Compare commits
188 Commits
release_1_
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -23,9 +23,13 @@ config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
gnu
|
||||
gnu/*.h
|
||||
gnu/*/
|
||||
gnu/.gitignore
|
||||
gnu/charset.alias
|
||||
gnulib
|
||||
libtool
|
||||
m4
|
||||
paxutils
|
||||
rmt
|
||||
stamp-h1
|
||||
|
||||
17
ChangeLog.1
17
ChangeLog.1
@@ -2,25 +2,22 @@ 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 -----
|
||||
|
||||
@@ -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.
|
||||
@@ -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/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
29
Makefile.am
29
Makefile.am
@@ -1,22 +1,22 @@
|
||||
# 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 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
|
||||
@@ -36,3 +36,4 @@ include Make.rules
|
||||
gen_start_date = 2009-03-06
|
||||
prev_change_log = ChangeLog.CVS
|
||||
changelog_dir = .
|
||||
changelog_amend_file=ChangeLog.amend
|
||||
|
||||
372
NEWS
372
NEWS
@@ -1,12 +1,227 @@
|
||||
GNU tar NEWS - User visible changes. 2010-10-24
|
||||
GNU tar NEWS - User visible changes. 2014-07-27
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
|
||||
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
|
||||
New command line option '--full-time' instructs tar to output file
|
||||
time stamps to the full resolution.
|
||||
|
||||
* Bugfixes.
|
||||
@@ -59,15 +274,15 @@ invoked as in the example below:
|
||||
|
||||
** --remove-files
|
||||
|
||||
`Tar --remove-files' failed to remove a directory which contained
|
||||
'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,
|
||||
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
|
||||
The '--verbose' option used with '--test-label' provides additional
|
||||
diagnostics.
|
||||
|
||||
Several volume labels may be specified in a command line, e.g.:
|
||||
@@ -79,7 +294,7 @@ matches the actual volume label.
|
||||
|
||||
** --label used with --update
|
||||
|
||||
The `--label' option can be used with `--update' to prevent accidental
|
||||
The '--label' option can be used with '--update' to prevent accidental
|
||||
update of an archive:
|
||||
|
||||
tar -rf archive --label 'My volume' .
|
||||
@@ -107,28 +322,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
|
||||
@@ -157,7 +372,7 @@ can be overridden by the
|
||||
--pax-opion='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.
|
||||
@@ -167,7 +382,7 @@ This can be overridden by the
|
||||
--pax-opion='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.
|
||||
|
||||
@@ -175,7 +390,7 @@ Any value from the --pax-option argument that is enclosed in a pair
|
||||
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.
|
||||
@@ -210,7 +425,7 @@ 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:
|
||||
@@ -270,17 +485,17 @@ control type of archive members affected by them. The flags are:
|
||||
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'
|
||||
|
||||
@@ -316,29 +531,29 @@ 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
|
||||
@@ -424,7 +639,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
|
||||
@@ -494,7 +709,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).
|
||||
@@ -534,7 +749,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.
|
||||
@@ -559,7 +774,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
|
||||
@@ -570,7 +785,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.
|
||||
@@ -584,7 +799,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.
|
||||
@@ -657,7 +872,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
|
||||
@@ -677,7 +892,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
|
||||
@@ -687,11 +902,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).
|
||||
@@ -745,12 +960,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
|
||||
@@ -856,7 +1071,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.
|
||||
|
||||
@@ -882,12 +1097,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.
|
||||
|
||||
|
||||
@@ -904,12 +1119,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.
|
||||
|
||||
@@ -951,20 +1166,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
|
||||
@@ -973,12 +1188,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.
|
||||
|
||||
@@ -995,40 +1210,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.
|
||||
|
||||
@@ -1037,7 +1252,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.
|
||||
@@ -1128,7 +1343,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
|
||||
@@ -1207,7 +1422,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
|
||||
@@ -1236,8 +1451,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.
|
||||
@@ -1290,15 +1505,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-2014 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
|
||||
@@ -1306,9 +1520,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
|
||||
|
||||
130
README
130
README
@@ -4,31 +4,31 @@ 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 '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.
|
||||
|
||||
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 +40,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 +76,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 +103,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 +118,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 +137,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 +159,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-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.
|
||||
|
||||
Please read the file NEWS for more information about POSIX compliance
|
||||
and new `tar' features.
|
||||
and new 'tar' features.
|
||||
|
||||
* What's next?
|
||||
|
||||
@@ -216,32 +216,36 @@ 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 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
|
||||
|
||||
11
README-alpha
11
README-alpha
@@ -62,14 +62,15 @@ some other value.
|
||||
|
||||
|
||||
|
||||
Copyright (C) 2001, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2001, 2003-2005, 2007, 2013-2014 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 +78,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/>.
|
||||
|
||||
@@ -36,30 +36,35 @@ 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
|
||||
root directory the file named '.bootstrap' with the following
|
||||
contents:
|
||||
|
||||
--gnulib-srcdir=$HOME/gnulib
|
||||
|
||||
Replace `$HOME/gnulib' with the actual directory where the Gnulib
|
||||
Replace '$HOME/gnulib' with the actual directory where the Gnulib
|
||||
sources reside.
|
||||
|
||||
For more information about `bootstrap', run `bootstrap --help'.
|
||||
For more information about 'bootstrap', run 'bootstrap --help'.
|
||||
|
||||
|
||||
* Copyright information
|
||||
|
||||
Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
Copyright 2007-2009, 2013-2014 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:
|
||||
|
||||
12
THANKS
12
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
|
||||
@@ -91,6 +92,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,6 +102,7 @@ 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
|
||||
@@ -118,6 +121,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
|
||||
@@ -241,6 +245,7 @@ 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 +301,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 +355,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 +364,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 +384,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 +406,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
|
||||
|
||||
26
TODO
26
TODO
@@ -45,24 +45,22 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2003-2004, 2007, 2013-2014 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:
|
||||
|
||||
62
acinclude.m4
62
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 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,50 @@ 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])
|
||||
AM_CONDITIONAL([TAR_LIB_ATTR],[false])
|
||||
if test "$ac_cv_header_sys_xattr_h" = yes; then
|
||||
AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \
|
||||
setxattr fsetxattr lsetxattr \
|
||||
listxattr flistxattr llistxattr,
|
||||
# only when functions are present
|
||||
AC_DEFINE([HAVE_SYS_XATTR_H], [1],
|
||||
[define to 1 if we have <sys/xattr.h> header])
|
||||
if test "$with_xattrs" != no; then
|
||||
AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.])
|
||||
fi
|
||||
)
|
||||
fi
|
||||
|
||||
# If <sys/xattr.h> is not found, then check for <attr/xattr.h>
|
||||
if test "$ac_cv_header_sys_xattr_h" != yes; then
|
||||
AC_CHECK_HEADERS([attr/xattr.h])
|
||||
AM_CONDITIONAL([TAR_COND_XATTR_H],[test "$ac_cv_header_attr_xattr_h" = yes])
|
||||
AC_CHECK_LIB([attr],[fgetxattr])
|
||||
AM_CONDITIONAL([TAR_LIB_ATTR],[test "$ac_cv_lib_attr_fgetxattr" = yes])
|
||||
if test "$ac_cv_header_attr_xattr_h" = yes; then
|
||||
AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \
|
||||
setxattr fsetxattr lsetxattr \
|
||||
listxattr flistxattr llistxattr,
|
||||
# only when functions are present
|
||||
AC_DEFINE([HAVE_ATTR_XATTR_H], [1],
|
||||
[define to 1 if we have <attr/xattr.h> header])
|
||||
if test "$with_xattrs" != no; then
|
||||
AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.])
|
||||
fi
|
||||
)
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#! /bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2010-10-24.18; # UTC
|
||||
scriptversion=2012-12-31.16; # UTC
|
||||
|
||||
# Bootstrap this package from checked-out sources.
|
||||
|
||||
# Copyright (C) 2003-2010 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003-2010, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -131,7 +131,6 @@ tests_base=tests
|
||||
# Extra files from gnulib, which override files from other sources.
|
||||
gnulib_extra_files="
|
||||
$build_aux/install-sh
|
||||
$build_aux/missing
|
||||
$build_aux/mdate-sh
|
||||
$build_aux/texinfo.tex
|
||||
$build_aux/depcomp
|
||||
@@ -464,8 +463,7 @@ git_modules_config () {
|
||||
}
|
||||
|
||||
gnulib_path=`git_modules_config submodule.gnulib.path`
|
||||
: ${gnulib_path=gnulib}
|
||||
|
||||
: ${gnulib_path:=gnulib}
|
||||
# Get gnulib files.
|
||||
|
||||
case ${GNULIB_SRCDIR--} in
|
||||
@@ -623,6 +621,7 @@ symlink_to_dir()
|
||||
/*) ;;
|
||||
*)
|
||||
case /$dst/ in
|
||||
/./*) ;;
|
||||
*//* | */../* | */./* | /*/*/*/*/*/)
|
||||
echo >&2 "$0: invalid symlink calculation: $src -> $dst"
|
||||
exit 1;;
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
# Bootstrap configuration for GNU tar.
|
||||
|
||||
# Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2009, 2013-2014 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.
|
||||
@@ -68,7 +67,7 @@ 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
|
||||
|
||||
163
configure.ac
163
configure.ac
@@ -1,42 +1,40 @@
|
||||
# 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-2014 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.24], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.28], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREREQ([2.63])
|
||||
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-xz 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 \
|
||||
@@ -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,115 @@ gl_INIT
|
||||
# paxutils modules
|
||||
tar_PAXUTILS
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
|
||||
# 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.
|
||||
|
||||
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 grantpt])
|
||||
AM_CONDITIONAL([TAR_COND_GRANTPT], [test $ac_cv_func_grantpt = yes])
|
||||
|
||||
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 +274,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
|
||||
|
||||
|
||||
@@ -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 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 = \
|
||||
@@ -31,10 +32,16 @@ tar_TEXINFOS = \
|
||||
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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006-2007, 2014 Free Software Foundation, Inc.
|
||||
@c Written by Sergey Poznyakoff
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
|
||||
Copyright @copyright{} 2000-2002, 2007-2008, 2014 Free Software
|
||||
Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
|
||||
@@ -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 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 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
;; Copyright 2006-2007, 2013-2014 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:
|
||||
|
||||
|
||||
@@ -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 Free Software
|
||||
@c Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@c This file contains support for 'renditions' by Fran@,{c}ois Pinard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2005, 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2005, 2007, 2014 Free Software Foundation, Inc.
|
||||
@c Written by Sergey Poznyakoff
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
@@ -11,11 +11,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 +33,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 +42,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 +94,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 +107,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 +115,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 preceeded 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,6 +137,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 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
|
||||
@@ -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 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,9 +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
|
||||
$ @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
|
||||
|
||||
905
doc/tar.texi
905
doc/tar.texi
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,19 @@
|
||||
# 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 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 Free Software
|
||||
@c Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
|
||||
3
gnu/Makefile.am
Normal file
3
gnu/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
# Make the subset of Gnulib that GNU tar needs.
|
||||
include gnulib.mk
|
||||
AM_CFLAGS += $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
@@ -1,6 +1,24 @@
|
||||
# List of gnulib modules needed for GNU tar.
|
||||
# A module name per line. Empty lines and comments are ignored.
|
||||
|
||||
# Copyright 2005-2010, 2012-2014 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
acl
|
||||
alloca
|
||||
argmatch
|
||||
argp
|
||||
@@ -11,12 +29,19 @@ configmake
|
||||
dirname
|
||||
error
|
||||
exclude
|
||||
extern-inline
|
||||
exitfail
|
||||
faccessat
|
||||
fchmodat
|
||||
fchownat
|
||||
fcntl-h
|
||||
fdopendir
|
||||
fdutimensat
|
||||
fileblocks
|
||||
fnmatch-gnu
|
||||
fprintftime
|
||||
fseeko
|
||||
fstatat
|
||||
full-write
|
||||
futimens
|
||||
getline
|
||||
@@ -32,21 +57,27 @@ inttypes
|
||||
lchown
|
||||
linkat
|
||||
localcharset
|
||||
manywarnings
|
||||
mkdirat
|
||||
mkdtemp
|
||||
mkfifoat
|
||||
modechange
|
||||
obstack
|
||||
openat
|
||||
parse-datetime
|
||||
posix_openpt
|
||||
ptsname
|
||||
priv-set
|
||||
progname
|
||||
quote
|
||||
quotearg
|
||||
readlinkat
|
||||
renameat
|
||||
root-uid
|
||||
rpmatch
|
||||
safe-read
|
||||
savedir
|
||||
selinux-at
|
||||
setenv
|
||||
snprintf
|
||||
stat-time
|
||||
@@ -55,12 +86,16 @@ stdint
|
||||
stpcpy
|
||||
strdup-posix
|
||||
strerror
|
||||
strtoimax
|
||||
strtol
|
||||
strtoul
|
||||
strtoumax
|
||||
symlinkat
|
||||
timespec
|
||||
unlinkat
|
||||
unlinkdir
|
||||
unlocked-io
|
||||
unlockpt
|
||||
utimensat
|
||||
version-etc-fsf
|
||||
xalloc
|
||||
|
||||
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 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,13 +27,36 @@ 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 \
|
||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||
prepargs.c prepargs.h \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h
|
||||
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 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,5 +1,5 @@
|
||||
/* Parse arguments from a string and prepend them to an argv.
|
||||
Copyright 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1999-2001, 2007, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -12,9 +12,7 @@
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, 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 <eggert@twinsun.com>. */
|
||||
|
||||
@@ -31,16 +29,6 @@
|
||||
|
||||
#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.
|
||||
@@ -55,7 +43,7 @@ prepend_args (char const *options, char *buf, char **argv)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (ISSPACE ((unsigned char) *o))
|
||||
while (isspace ((unsigned char) *o))
|
||||
o++;
|
||||
if (!*o)
|
||||
return n;
|
||||
@@ -66,7 +54,7 @@ prepend_args (char const *options, char *buf, char **argv)
|
||||
do
|
||||
if ((*b++ = *o++) == '\\' && *o)
|
||||
b[-1] = *o++;
|
||||
while (*o && ! ISSPACE ((unsigned char) *o));
|
||||
while (*o && ! isspace ((unsigned char) *o));
|
||||
|
||||
*b++ = '\0';
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* 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 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 +13,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. */
|
||||
|
||||
|
||||
1628
lib/wordsplit.c
Normal file
1628
lib/wordsplit.c
Normal file
File diff suppressed because it is too large
Load Diff
162
lib/wordsplit.h
Normal file
162
lib/wordsplit.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/* wordsplit - a word splitter
|
||||
Copyright (C) 2009-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3 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>
|
||||
|
||||
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 *, ...)
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
void (*ws_debug) (const char *, ...)
|
||||
__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
|
||||
110
lib/xattr-at.c
Normal file
110
lib/xattr-at.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/* openat-style fd-relative functions for operating with extended file
|
||||
attributes.
|
||||
|
||||
Copyright 2012-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 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"
|
||||
|
||||
/* 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
|
||||
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 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,22 +1,22 @@
|
||||
# List of files which contain translatable strings.
|
||||
|
||||
# Copyright (C) 1996, 1999, 2000, 2003, 2004, 2005, 2007 Free Software
|
||||
# Copyright 1996, 1999-2000, 2003-2005, 2007, 2013-2014 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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, 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,21 @@
|
||||
# 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 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
|
||||
|
||||
@@ -82,19 +82,19 @@ SLEEP_MESSAGE="`awk '
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright (C) 2004, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2004, 2007, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 3, or (at your option)
|
||||
## any later version.
|
||||
# This 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,7 +150,7 @@ 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.
|
||||
(
|
||||
@@ -187,7 +188,7 @@ 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
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#! /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 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 +49,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 +212,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,7 +306,7 @@ 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"
|
||||
@@ -339,9 +340,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
|
||||
}
|
||||
|
||||
@@ -7,9 +7,25 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Include location of `sendmail' and GNU finger.
|
||||
# Copyright 2004-2005, 2010, 2012-2014 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,8 +41,8 @@ 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
|
||||
# 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 \
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#! /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 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 +61,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 +71,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,66 @@
|
||||
#! /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 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 +76,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 +98,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 +204,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
|
||||
@@ -215,10 +486,13 @@ sub write_incr_db_0 ($$) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,18 +501,21 @@ 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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,21 +524,21 @@ 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 +548,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 +561,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,23 @@
|
||||
# concatenates a GNU tar multi-volume archive into a single tar archive.
|
||||
# Author: Bruno Haible <bruno@clisp.org>, Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
# Copyright 2004-2005, 2010, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
# 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() {
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/* xsparse - expands compressed sparse file images extracted from GNU tar
|
||||
archives.
|
||||
|
||||
Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
|
||||
Copyright 2006-2007, 2010, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff
|
||||
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 Sergey Poznyakoff */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -164,7 +165,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;
|
||||
@@ -194,7 +195,7 @@ read_xheader (char *name)
|
||||
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)
|
||||
@@ -235,13 +236,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_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
|
||||
@@ -252,7 +253,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)
|
||||
@@ -449,7 +450,7 @@ main (int argc, char **argv)
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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 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,6 +28,7 @@ tar_SOURCES = \
|
||||
create.c\
|
||||
delete.c\
|
||||
exit.c\
|
||||
exclist.c\
|
||||
extract.c\
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
@@ -42,10 +43,16 @@ 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) $(LIB_EACCESS)
|
||||
tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
|
||||
if TAR_LIB_ATTR
|
||||
tar_LDADD += -lattr
|
||||
endif
|
||||
|
||||
15
src/arith.h
15
src/arith.h
@@ -1,19 +1,20 @@
|
||||
/* Long integers, for GNU tar.
|
||||
Copyright 1999, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1999, 2007, 2013-2014 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
|
||||
|
||||
279
src/buffer.c
279
src/buffer.c
@@ -1,24 +1,24 @@
|
||||
/* Buffer management for tar.
|
||||
|
||||
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, 2013-2014 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-08-25.
|
||||
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-25. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
@@ -41,7 +41,7 @@
|
||||
static tarlong prev_written; /* bytes written on previous volumes */
|
||||
static tarlong bytes_written; /* bytes written on this volume */
|
||||
static void *record_buffer[2]; /* allocated memory */
|
||||
union block *record_buffer_aligned[2];
|
||||
static union block *record_buffer_aligned[2];
|
||||
static int record_index;
|
||||
|
||||
/* FIXME: The following variables should ideally be static to this
|
||||
@@ -83,8 +83,8 @@ extern bool time_to_start_writing;
|
||||
|
||||
bool write_archive_to_stdout;
|
||||
|
||||
void (*flush_write_ptr) (size_t);
|
||||
void (*flush_read_ptr) (void);
|
||||
static void (*flush_write_ptr) (size_t);
|
||||
static void (*flush_read_ptr) (void);
|
||||
|
||||
|
||||
char *volume_label;
|
||||
@@ -103,7 +103,7 @@ bool write_archive_to_stdout;
|
||||
|
||||
/* Multi-volume tracking support */
|
||||
|
||||
/* When creating a multi-volume archive, each `bufmap' represents
|
||||
/* When creating a multi-volume archive, each 'bufmap' represents
|
||||
a member stored (perhaps partly) in the current record buffer.
|
||||
After flushing the record to the output media, all bufmaps that
|
||||
represent fully written members are removed from the list, then
|
||||
@@ -193,7 +193,7 @@ bufmap_reset (struct bufmap *map, ssize_t fixup)
|
||||
static struct tar_stat_info dummy;
|
||||
|
||||
void
|
||||
buffer_write_global_xheader ()
|
||||
buffer_write_global_xheader (void)
|
||||
{
|
||||
xheader_write_global (&dummy.xhdr);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ mv_begin_read (struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
void
|
||||
mv_end ()
|
||||
mv_end (void)
|
||||
{
|
||||
if (multi_volume_option)
|
||||
bufmap_free (NULL);
|
||||
@@ -230,10 +230,10 @@ clear_read_error_count (void)
|
||||
|
||||
/* Time-related functions */
|
||||
|
||||
double duration;
|
||||
static double duration;
|
||||
|
||||
void
|
||||
set_start_time ()
|
||||
set_start_time (void)
|
||||
{
|
||||
gettime (&start_time);
|
||||
volume_start_time = start_time;
|
||||
@@ -247,22 +247,23 @@ set_volume_start_time (void)
|
||||
last_stat_time = volume_start_time;
|
||||
}
|
||||
|
||||
void
|
||||
compute_duration ()
|
||||
double
|
||||
compute_duration (void)
|
||||
{
|
||||
struct timespec now;
|
||||
gettime (&now);
|
||||
duration += ((now.tv_sec - last_stat_time.tv_sec)
|
||||
+ (now.tv_nsec - last_stat_time.tv_nsec) / 1e9);
|
||||
gettime (&last_stat_time);
|
||||
return duration;
|
||||
}
|
||||
|
||||
|
||||
/* Compression detection */
|
||||
|
||||
enum compress_type {
|
||||
ct_tar, /* Plain tar file */
|
||||
ct_none, /* Unknown compression type */
|
||||
ct_tar, /* Plain tar file */
|
||||
ct_compress,
|
||||
ct_gzip,
|
||||
ct_bzip2,
|
||||
@@ -272,31 +273,102 @@ enum compress_type {
|
||||
ct_xz
|
||||
};
|
||||
|
||||
static enum compress_type archive_compression_type = ct_none;
|
||||
|
||||
struct zip_magic
|
||||
{
|
||||
enum compress_type type;
|
||||
size_t length;
|
||||
char const *magic;
|
||||
};
|
||||
|
||||
struct zip_program
|
||||
{
|
||||
enum compress_type type;
|
||||
char const *program;
|
||||
char const *option;
|
||||
};
|
||||
|
||||
static struct zip_magic const magic[] = {
|
||||
{ ct_tar },
|
||||
{ ct_none, },
|
||||
{ ct_compress, 2, "\037\235", COMPRESS_PROGRAM, "-Z" },
|
||||
{ ct_gzip, 2, "\037\213", GZIP_PROGRAM, "-z" },
|
||||
{ ct_bzip2, 3, "BZh", BZIP2_PROGRAM, "-j" },
|
||||
{ ct_lzip, 4, "LZIP", LZIP_PROGRAM, "--lzip" },
|
||||
{ ct_lzma, 6, "\xFFLZMA", LZMA_PROGRAM, "--lzma" },
|
||||
{ ct_lzop, 4, "\211LZO", LZOP_PROGRAM, "--lzop" },
|
||||
{ ct_xz, 6, "\xFD" "7zXZ", XZ_PROGRAM, "-J" },
|
||||
{ ct_none, 0, 0 },
|
||||
{ ct_tar, 0, 0 },
|
||||
{ ct_compress, 2, "\037\235" },
|
||||
{ ct_gzip, 2, "\037\213" },
|
||||
{ ct_bzip2, 3, "BZh" },
|
||||
{ ct_lzip, 4, "LZIP" },
|
||||
{ ct_lzma, 6, "\xFFLZMA" },
|
||||
{ ct_lzop, 4, "\211LZO" },
|
||||
{ ct_xz, 6, "\xFD" "7zXZ" },
|
||||
};
|
||||
|
||||
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
|
||||
|
||||
#define compress_option(t) magic[t].option
|
||||
#define compress_program(t) magic[t].program
|
||||
static struct zip_program zip_program[] = {
|
||||
{ ct_compress, COMPRESS_PROGRAM, "-Z" },
|
||||
{ ct_compress, GZIP_PROGRAM, "-z" },
|
||||
{ ct_gzip, GZIP_PROGRAM, "-z" },
|
||||
{ ct_bzip2, BZIP2_PROGRAM, "-j" },
|
||||
{ ct_bzip2, "lbzip2", "-j" },
|
||||
{ ct_lzip, LZIP_PROGRAM, "--lzip" },
|
||||
{ ct_lzma, LZMA_PROGRAM, "--lzma" },
|
||||
{ ct_lzma, XZ_PROGRAM, "-J" },
|
||||
{ ct_lzop, LZOP_PROGRAM, "--lzop" },
|
||||
{ ct_xz, XZ_PROGRAM, "-J" },
|
||||
{ ct_none }
|
||||
};
|
||||
|
||||
static struct zip_program const *
|
||||
find_zip_program (enum compress_type type, int *pstate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = *pstate; zip_program[i].type != ct_none; i++)
|
||||
{
|
||||
if (zip_program[i].type == type)
|
||||
{
|
||||
*pstate = i + 1;
|
||||
return zip_program + i;
|
||||
}
|
||||
}
|
||||
*pstate = i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
first_decompress_program (int *pstate)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
|
||||
if (use_compress_program_option)
|
||||
return use_compress_program_option;
|
||||
|
||||
if (archive_compression_type == ct_none)
|
||||
return NULL;
|
||||
|
||||
*pstate = 0;
|
||||
zp = find_zip_program (archive_compression_type, pstate);
|
||||
return zp ? zp->program : NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
next_decompress_program (int *pstate)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
|
||||
if (use_compress_program_option)
|
||||
return NULL;
|
||||
zp = find_zip_program (archive_compression_type, pstate);
|
||||
return zp ? zp->program : NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
compress_option (enum compress_type type)
|
||||
{
|
||||
struct zip_program const *zp;
|
||||
int i = 0;
|
||||
zp = find_zip_program (type, &i);
|
||||
return zp ? zp->option : NULL;
|
||||
}
|
||||
|
||||
/* Check if the file ARCHIVE is a compressed archive. */
|
||||
static enum compress_type
|
||||
@@ -395,7 +467,7 @@ open_compressed_archive (void)
|
||||
break;
|
||||
|
||||
default:
|
||||
use_compress_program_option = compress_program (type);
|
||||
archive_compression_type = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -417,64 +489,98 @@ open_compressed_archive (void)
|
||||
return archive;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static int
|
||||
print_stats (FILE *fp, const char *text, tarlong numbytes)
|
||||
{
|
||||
char bytes[sizeof (tarlong) * CHAR_BIT];
|
||||
char abbr[LONGEST_HUMAN_READABLE + 1];
|
||||
char rate[LONGEST_HUMAN_READABLE + 1];
|
||||
|
||||
int n = 0;
|
||||
|
||||
int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
|
||||
|
||||
sprintf (bytes, TARLONG_FORMAT, numbytes);
|
||||
|
||||
fprintf (fp, "%s: %s (%s, %s/s)\n",
|
||||
text, bytes,
|
||||
human_readable (numbytes, abbr, human_opts, 1, 1),
|
||||
(0 < duration && numbytes / duration < (uintmax_t) -1
|
||||
? human_readable (numbytes / duration, rate, human_opts, 1, 1)
|
||||
: "?"));
|
||||
if (text && text[0])
|
||||
n += fprintf (fp, "%s: ", gettext (text));
|
||||
return n + fprintf (fp, TARLONG_FORMAT " (%s, %s/s)",
|
||||
numbytes,
|
||||
human_readable (numbytes, abbr, human_opts, 1, 1),
|
||||
(0 < duration && numbytes / duration < (uintmax_t) -1
|
||||
? human_readable (numbytes / duration, rate, human_opts, 1, 1)
|
||||
: "?"));
|
||||
}
|
||||
|
||||
void
|
||||
print_total_stats ()
|
||||
/* Format totals to file FP. FORMATS is an array of strings to output
|
||||
before each data item (bytes read, written, deleted, in that order).
|
||||
EOR is a delimiter to output after each item (used only if deleting
|
||||
from the archive), EOL is a delimiter to add at the end of the output
|
||||
line. */
|
||||
int
|
||||
format_total_stats (FILE *fp, const char **formats, int eor, int eol)
|
||||
{
|
||||
int n;
|
||||
|
||||
switch (subcommand_option)
|
||||
{
|
||||
case CREATE_SUBCOMMAND:
|
||||
case CAT_SUBCOMMAND:
|
||||
case UPDATE_SUBCOMMAND:
|
||||
case APPEND_SUBCOMMAND:
|
||||
/* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
|
||||
print_stats (stderr, _("Total bytes written"),
|
||||
prev_written + bytes_written);
|
||||
n = print_stats (fp, formats[TF_WRITE],
|
||||
prev_written + bytes_written);
|
||||
break;
|
||||
|
||||
case DELETE_SUBCOMMAND:
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
print_stats (stderr, _("Total bytes read"),
|
||||
records_read * record_size);
|
||||
print_stats (stderr, _("Total bytes written"),
|
||||
prev_written + bytes_written);
|
||||
fprintf (stderr, _("Total bytes deleted: %s\n"),
|
||||
STRINGIFY_BIGINT ((records_read - records_skipped)
|
||||
* record_size
|
||||
- (prev_written + bytes_written), buf));
|
||||
n = print_stats (fp, formats[TF_READ],
|
||||
records_read * record_size);
|
||||
|
||||
fputc (eor, fp);
|
||||
n++;
|
||||
|
||||
n += print_stats (fp, formats[TF_WRITE],
|
||||
prev_written + bytes_written);
|
||||
|
||||
fputc (eor, fp);
|
||||
n++;
|
||||
|
||||
if (formats[TF_DELETED] && formats[TF_DELETED][0])
|
||||
n += fprintf (fp, "%s: ", gettext (formats[TF_DELETED]));
|
||||
n += fprintf (fp, "%s",
|
||||
STRINGIFY_BIGINT ((records_read - records_skipped)
|
||||
* record_size
|
||||
- (prev_written + bytes_written), buf));
|
||||
}
|
||||
break;
|
||||
|
||||
case EXTRACT_SUBCOMMAND:
|
||||
case LIST_SUBCOMMAND:
|
||||
case DIFF_SUBCOMMAND:
|
||||
print_stats (stderr, _("Total bytes read"),
|
||||
records_read * record_size);
|
||||
n = print_stats (fp, _(formats[TF_READ]),
|
||||
records_read * record_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
if (eol)
|
||||
{
|
||||
fputc (eol, fp);
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
const char *default_total_format[] = {
|
||||
N_("Total bytes read"),
|
||||
/* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
|
||||
N_("Total bytes written"),
|
||||
N_("Total bytes deleted")
|
||||
};
|
||||
|
||||
void
|
||||
print_total_stats (void)
|
||||
{
|
||||
format_total_stats (stderr, default_total_format, '\n', '\n');
|
||||
}
|
||||
|
||||
/* Compute and return the block ordinal at current_block. */
|
||||
@@ -562,6 +668,22 @@ init_buffer (void)
|
||||
record_end = record_start + blocking_factor;
|
||||
}
|
||||
|
||||
static void
|
||||
check_tty (enum access_mode mode)
|
||||
{
|
||||
/* Refuse to read archive from and write it to a tty. */
|
||||
if (strcmp (archive_name_array[0], "-") == 0
|
||||
&& isatty (mode == ACCESS_READ ? STDIN_FILENO : STDOUT_FILENO))
|
||||
{
|
||||
FATAL_ERROR ((0, 0,
|
||||
mode == ACCESS_READ
|
||||
? _("Refusing to read archive contents from terminal "
|
||||
"(missing -f option?)")
|
||||
: _("Refusing to write archive contents to terminal "
|
||||
"(missing -f option?)")));
|
||||
}
|
||||
}
|
||||
|
||||
/* Open an archive file. The argument specifies whether we are
|
||||
reading or writing, or both. */
|
||||
static void
|
||||
@@ -582,6 +704,7 @@ _open_archive (enum access_mode wanted_access)
|
||||
|
||||
/* When updating the archive, we start with reading. */
|
||||
access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
|
||||
check_tty (access_mode);
|
||||
|
||||
read_full_records = read_full_records_option;
|
||||
|
||||
@@ -625,7 +748,6 @@ _open_archive (enum access_mode wanted_access)
|
||||
enum compress_type type;
|
||||
|
||||
archive = STDIN_FILENO;
|
||||
|
||||
type = check_compressed_archive (&shortfile);
|
||||
if (type != ct_tar && type != ct_none)
|
||||
FATAL_ERROR ((0, 0,
|
||||
@@ -651,9 +773,6 @@ _open_archive (enum access_mode wanted_access)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (verify_option)
|
||||
archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
else
|
||||
switch (wanted_access)
|
||||
{
|
||||
@@ -669,8 +788,12 @@ _open_archive (enum access_mode wanted_access)
|
||||
maybe_backup_file (archive_name_array[0], 1);
|
||||
backed_up_flag = 1;
|
||||
}
|
||||
archive = rmtcreat (archive_name_array[0], MODE_RW,
|
||||
rsh_command_option);
|
||||
if (verify_option)
|
||||
archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
else
|
||||
archive = rmtcreat (archive_name_array[0], MODE_RW,
|
||||
rsh_command_option);
|
||||
break;
|
||||
|
||||
case ACCESS_UPDATE:
|
||||
@@ -812,16 +935,16 @@ short_read (size_t status)
|
||||
left = record_size - status;
|
||||
|
||||
if (left && left % BLOCKSIZE == 0
|
||||
&& verbose_option
|
||||
&& (warning_option & WARN_RECORD_SIZE)
|
||||
&& record_start_block == 0 && status != 0
|
||||
&& archive_is_dev ())
|
||||
{
|
||||
unsigned long rsize = status / BLOCKSIZE;
|
||||
WARN ((0, 0,
|
||||
ngettext ("Record size = %lu block",
|
||||
"Record size = %lu blocks",
|
||||
rsize),
|
||||
rsize));
|
||||
ngettext ("Record size = %lu block",
|
||||
"Record size = %lu blocks",
|
||||
rsize),
|
||||
rsize));
|
||||
}
|
||||
|
||||
while (left % BLOCKSIZE != 0
|
||||
@@ -1857,13 +1980,13 @@ gnu_flush_write (size_t buffer_level)
|
||||
}
|
||||
|
||||
void
|
||||
flush_read ()
|
||||
flush_read (void)
|
||||
{
|
||||
flush_read_ptr ();
|
||||
}
|
||||
|
||||
void
|
||||
flush_write ()
|
||||
flush_write (void)
|
||||
{
|
||||
flush_write_ptr (record_size);
|
||||
}
|
||||
|
||||
323
src/checkpoint.c
323
src/checkpoint.c
@@ -1,22 +1,28 @@
|
||||
/* Checkpoint management for tar.
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
Copyright 2007, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This 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
|
||||
@@ -108,12 +115,14 @@ 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)
|
||||
{
|
||||
@@ -126,68 +135,211 @@ checkpoint_finish_compile ()
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
}
|
||||
|
||||
static char *
|
||||
expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
|
||||
static const char *checkpoint_total_format[] = {
|
||||
"R",
|
||||
"W",
|
||||
"D"
|
||||
};
|
||||
|
||||
static long
|
||||
getwidth (FILE *fp)
|
||||
{
|
||||
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 */
|
||||
char const *columns;
|
||||
|
||||
/* Fix the initial length guess */
|
||||
for (ip = input; (ip = strchr (ip, '%')) != NULL; )
|
||||
#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)
|
||||
{
|
||||
@@ -210,26 +362,10 @@ run_checkpoint_actions (bool do_write)
|
||||
|
||||
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;
|
||||
|
||||
@@ -237,13 +373,8 @@ run_checkpoint_actions (bool do_write)
|
||||
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:
|
||||
@@ -255,10 +386,37 @@ run_checkpoint_actions (bool do_write)
|
||||
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
|
||||
@@ -267,3 +425,14 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
176
src/common.h
176
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-2014 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This 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"
|
||||
@@ -70,6 +70,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. */
|
||||
|
||||
@@ -138,9 +143,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;
|
||||
|
||||
@@ -158,7 +160,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;
|
||||
@@ -182,10 +185,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 */
|
||||
@@ -229,8 +235,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;
|
||||
@@ -239,9 +250,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;
|
||||
|
||||
@@ -253,6 +261,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;
|
||||
@@ -313,11 +330,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. */
|
||||
@@ -370,6 +386,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 */
|
||||
@@ -415,7 +433,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);
|
||||
@@ -432,6 +450,12 @@ void archive_read_error (void);
|
||||
off_t seek_archive (off_t size);
|
||||
void set_start_time (void);
|
||||
|
||||
#define TF_READ 0
|
||||
#define TF_WRITE 1
|
||||
#define TF_DELETED 2
|
||||
int format_total_stats (FILE *fp, const char **formats, int eor, int eol);
|
||||
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);
|
||||
@@ -440,6 +464,9 @@ 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
|
||||
@@ -511,6 +538,7 @@ 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);
|
||||
@@ -519,6 +547,7 @@ 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. */
|
||||
|
||||
@@ -550,6 +579,7 @@ 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 OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
|
||||
@@ -573,23 +603,62 @@ void skip_member (void);
|
||||
|
||||
/* Module misc.c. */
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
void assign_string (char **dest, const char *src);
|
||||
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);
|
||||
void namebuf_add_dir (namebuf_t buf, const char *name);
|
||||
char *namebuf_finish (namebuf_t buf);
|
||||
|
||||
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 *);
|
||||
|
||||
@@ -613,6 +682,9 @@ void undo_last_backup (void);
|
||||
|
||||
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);
|
||||
@@ -628,8 +700,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)
|
||||
@@ -655,6 +725,7 @@ int uname_to_uid (char const *uname, uid_t *puid);
|
||||
void name_init (void);
|
||||
void name_add_name (const char *name, int matching_flags);
|
||||
void name_add_dir (const char *name);
|
||||
void name_add_file (const char *name, int term);
|
||||
void name_term (void);
|
||||
const char *name_next (int change_dirs);
|
||||
void name_gather (void);
|
||||
@@ -672,11 +743,8 @@ char *new_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);
|
||||
|
||||
@@ -700,19 +768,25 @@ const char *archive_format_string (enum archive_format fmt);
|
||||
const char *subcommand_string (enum subcommand c);
|
||||
void set_exit_status (int val);
|
||||
|
||||
void request_stdin (const char *option);
|
||||
void more_options (int argc, char **argv);
|
||||
|
||||
/* Module update.c. */
|
||||
|
||||
extern char *output_start;
|
||||
|
||||
void update_archive (void);
|
||||
|
||||
/* Module attrs.c. */
|
||||
#include "xattrs.h"
|
||||
|
||||
/* Module xheader.c. */
|
||||
|
||||
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);
|
||||
@@ -726,6 +800,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 */
|
||||
|
||||
@@ -750,7 +830,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);
|
||||
@@ -775,14 +856,18 @@ void set_transform_expr (const char *expr);
|
||||
bool transform_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_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
|
||||
@@ -804,10 +889,15 @@ 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
|
||||
|
||||
/* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default
|
||||
in verbose mode */
|
||||
#define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY)
|
||||
/* 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);
|
||||
@@ -828,3 +918,17 @@ 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_cleanup_exclist (struct tar_stat_info *dir);
|
||||
void info_free_exclist (struct tar_stat_info *dir);
|
||||
bool excluded_name (char const *name, struct tar_stat_info *st);
|
||||
void exclude_vcs_ignores (void);
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
@@ -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 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>
|
||||
@@ -80,7 +81,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)
|
||||
{
|
||||
@@ -234,7 +235,8 @@ 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 atime = get_stat_atime (&stat_data);
|
||||
if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
|
||||
@@ -358,31 +360,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 (current_stat_info.file_name, &stat_data) != 0)
|
||||
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 (¤t_stat_info));
|
||||
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
|
||||
@@ -409,7 +418,9 @@ 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 ();
|
||||
@@ -431,10 +442,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)
|
||||
@@ -460,7 +470,7 @@ 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. */
|
||||
@@ -497,7 +507,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;
|
||||
|
||||
@@ -512,13 +522,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 ();
|
||||
@@ -611,8 +632,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)
|
||||
149
src/create.c
149
src/create.c
@@ -1,23 +1,24 @@
|
||||
/* Create a tar archive.
|
||||
|
||||
Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1985, 1992-1994, 1996-1997, 1999-2001, 2003-2007,
|
||||
2009-2010, 2012-2014 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-08-25.
|
||||
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-25. */
|
||||
|
||||
#include <system.h>
|
||||
|
||||
@@ -511,12 +512,11 @@ start_private_header (const char *name, size_t size, time_t t)
|
||||
tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE);
|
||||
OFF_TO_CHARS (size, header->header.size);
|
||||
|
||||
TIME_TO_CHARS (t, header->header.mtime);
|
||||
TIME_TO_CHARS (t < 0 ? 0 : min (t, MAX_OCTAL_VAL (header->header.mtime)),
|
||||
header->header.mtime);
|
||||
MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
|
||||
UID_TO_CHARS (getuid (), header->header.uid);
|
||||
GID_TO_CHARS (getgid (), header->header.gid);
|
||||
MAJOR_TO_CHARS (0, header->header.devmajor);
|
||||
MINOR_TO_CHARS (0, header->header.devminor);
|
||||
UID_TO_CHARS (0, header->header.uid);
|
||||
GID_TO_CHARS (0, header->header.gid);
|
||||
strncpy (header->header.magic, TMAGIC, TMAGLEN);
|
||||
strncpy (header->header.version, TVERSION, TVERSLEN);
|
||||
return header;
|
||||
@@ -534,11 +534,6 @@ write_short_name (struct tar_stat_info *st)
|
||||
return header;
|
||||
}
|
||||
|
||||
#define FILL(field,byte) do { \
|
||||
memset(field, byte, sizeof(field)-1); \
|
||||
(field)[sizeof(field)-1] = 0; \
|
||||
} while (0)
|
||||
|
||||
/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
|
||||
static void
|
||||
write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
@@ -548,13 +543,7 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
union block *header;
|
||||
char *tmpname;
|
||||
|
||||
header = start_private_header ("././@LongLink", size, time (NULL));
|
||||
FILL (header->header.mtime, '0');
|
||||
FILL (header->header.mode, '0');
|
||||
FILL (header->header.uid, '0');
|
||||
FILL (header->header.gid, '0');
|
||||
FILL (header->header.devmajor, 0);
|
||||
FILL (header->header.devminor, 0);
|
||||
header = start_private_header ("././@LongLink", size, 0);
|
||||
uid_to_uname (0, &tmpname);
|
||||
UNAME_TO_CHARS (tmpname, header->header.uname);
|
||||
free (tmpname);
|
||||
@@ -562,7 +551,8 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
GNAME_TO_CHARS (tmpname, header->header.gname);
|
||||
free (tmpname);
|
||||
|
||||
strcpy (header->header.magic, OLDGNU_MAGIC);
|
||||
strcpy (header->buffer + offsetof (struct posix_header, magic),
|
||||
OLDGNU_MAGIC);
|
||||
header->header.typeflag = type;
|
||||
finish_header (st, header, -1);
|
||||
|
||||
@@ -710,7 +700,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header)
|
||||
{
|
||||
type = XGLTYPE;
|
||||
p = xheader_ghdr_name ();
|
||||
time (&t);
|
||||
t = start_time.tv_sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -784,9 +774,9 @@ start_header (struct tar_stat_info *st)
|
||||
. . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
|
||||
|
||||
. = works
|
||||
# = ``impossible file type''
|
||||
# = "impossible file type"
|
||||
|
||||
The following mask for old archive removes the `#'s in column 4
|
||||
The following mask for old archive removes the '#'s in column 4
|
||||
above, thus making GNU tar both a universal donor and a universal
|
||||
acceptor for Paul's test. */
|
||||
|
||||
@@ -899,7 +889,8 @@ start_header (struct tar_stat_info *st)
|
||||
case OLDGNU_FORMAT:
|
||||
case GNU_FORMAT: /*FIXME?*/
|
||||
/* Overwrite header->header.magic and header.version in one blow. */
|
||||
strcpy (header->header.magic, OLDGNU_MAGIC);
|
||||
strcpy (header->buffer + offsetof (struct posix_header, magic),
|
||||
OLDGNU_MAGIC);
|
||||
break;
|
||||
|
||||
case POSIX_FORMAT:
|
||||
@@ -918,8 +909,15 @@ start_header (struct tar_stat_info *st)
|
||||
}
|
||||
else
|
||||
{
|
||||
uid_to_uname (st->stat.st_uid, &st->uname);
|
||||
gid_to_gname (st->stat.st_gid, &st->gname);
|
||||
if (owner_name_option)
|
||||
st->uname = xstrdup (owner_name_option);
|
||||
else
|
||||
uid_to_uname (st->stat.st_uid, &st->uname);
|
||||
|
||||
if (group_name_option)
|
||||
st->gname = xstrdup (group_name_option);
|
||||
else
|
||||
gid_to_gname (st->stat.st_gid, &st->gname);
|
||||
|
||||
if (archive_format == POSIX_FORMAT
|
||||
&& (strlen (st->uname) > UNAME_FIELD_SIZE
|
||||
@@ -934,6 +932,30 @@ start_header (struct tar_stat_info *st)
|
||||
GNAME_TO_CHARS (st->gname, header->header.gname);
|
||||
}
|
||||
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
if (acls_option > 0)
|
||||
{
|
||||
if (st->acls_a_ptr)
|
||||
xheader_store ("SCHILY.acl.access", st, NULL);
|
||||
if (st->acls_d_ptr)
|
||||
xheader_store ("SCHILY.acl.default", st, NULL);
|
||||
}
|
||||
if ((selinux_context_option > 0) && st->cntx_name)
|
||||
xheader_store ("RHT.security.selinux", st, NULL);
|
||||
if (xattrs_option > 0)
|
||||
{
|
||||
size_t scan_xattr = 0;
|
||||
struct xattr_array *xattr_map = st->xattr_map;
|
||||
|
||||
while (scan_xattr < st->xattr_map_size)
|
||||
{
|
||||
xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
|
||||
++scan_xattr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -1042,7 +1064,7 @@ dump_regular_file (int fd, struct tar_stat_info *st)
|
||||
memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
|
||||
}
|
||||
|
||||
count = (fd <= 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
|
||||
count = (fd <= 0) ? bufsize : blocking_read (fd, blk->buffer, bufsize);
|
||||
if (count == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (st->orig_file_name,
|
||||
@@ -1091,6 +1113,8 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
|
||||
if (!blk)
|
||||
return;
|
||||
|
||||
info_attach_exclist (st);
|
||||
|
||||
if (incremental_option && archive_format != POSIX_FORMAT)
|
||||
blk->header.typeflag = GNUTYPE_DUMPDIR;
|
||||
else /* if (standard_option) */
|
||||
@@ -1174,7 +1198,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
|
||||
char const *entry;
|
||||
size_t entry_len;
|
||||
size_t name_len;
|
||||
|
||||
|
||||
name_buf = xstrdup (st->orig_file_name);
|
||||
name_size = name_len = strlen (name_buf);
|
||||
|
||||
@@ -1188,7 +1212,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
|
||||
name_buf = xrealloc (name_buf, name_size + 1);
|
||||
}
|
||||
strcpy (name_buf + name_len, entry);
|
||||
if (!excluded_name (name_buf))
|
||||
if (!excluded_name (name_buf, st))
|
||||
dump_file (st, entry, name_buf);
|
||||
}
|
||||
|
||||
@@ -1266,7 +1290,7 @@ get_directory_entries (struct tar_stat_info *st)
|
||||
while (! (st->dirstream = fdopendir (st->fd)))
|
||||
if (! open_failure_recover (st))
|
||||
return 0;
|
||||
return streamsavedir (st->dirstream);
|
||||
return streamsavedir (st->dirstream, savedir_sort_order);
|
||||
}
|
||||
|
||||
/* Dump the directory ST. Return true if successful, false (emitting
|
||||
@@ -1317,12 +1341,12 @@ create_archive (void)
|
||||
collect_and_sort_names ();
|
||||
|
||||
while ((p = name_from_list ()) != NULL)
|
||||
if (!excluded_name (p->name))
|
||||
if (!excluded_name (p->name, NULL))
|
||||
dump_file (0, p->name, p->name);
|
||||
|
||||
blank_name_list ();
|
||||
while ((p = name_from_list ()) != NULL)
|
||||
if (!excluded_name (p->name))
|
||||
if (!excluded_name (p->name, NULL))
|
||||
{
|
||||
struct tar_stat_info st;
|
||||
size_t plen = strlen (p->name);
|
||||
@@ -1336,7 +1360,7 @@ create_archive (void)
|
||||
if (! ISSLASH (buffer[plen - 1]))
|
||||
buffer[plen++] = DIRECTORY_SEPARATOR;
|
||||
tar_stat_init (&st);
|
||||
q = directory_contents (gnu_list_name->directory);
|
||||
q = directory_contents (p->directory);
|
||||
if (q)
|
||||
while (*q)
|
||||
{
|
||||
@@ -1379,7 +1403,7 @@ create_archive (void)
|
||||
{
|
||||
const char *name;
|
||||
while ((name = name_next (1)) != NULL)
|
||||
if (!excluded_name (name))
|
||||
if (!excluded_name (name, NULL))
|
||||
dump_file (0, name, name);
|
||||
}
|
||||
|
||||
@@ -1676,9 +1700,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
put in the archive.
|
||||
|
||||
This check is omitted if incremental_option is set *and* the
|
||||
requested file is not explicitely listed in the command line. */
|
||||
requested file is not explicitly listed in the command line. */
|
||||
|
||||
if (!(incremental_option && !is_individual_file (p))
|
||||
if (! (incremental_option && ! top_level)
|
||||
&& !S_ISDIR (st->stat.st_mode)
|
||||
&& OLDER_TAR_STAT_TIME (*st, m)
|
||||
&& (!after_date_option || OLDER_TAR_STAT_TIME (*st, c)))
|
||||
@@ -1709,6 +1733,10 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
bool ok;
|
||||
struct stat final_stat;
|
||||
|
||||
xattrs_acls_get (parentfd, name, st, 0, !is_dir);
|
||||
xattrs_selinux_get (parentfd, name, st, fd);
|
||||
xattrs_xattrs_get (parentfd, name, st, fd);
|
||||
|
||||
if (is_dir)
|
||||
{
|
||||
const char *tag_file_name;
|
||||
@@ -1795,6 +1823,7 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
set_exit_status (TAREXIT_DIFFERS);
|
||||
}
|
||||
else if (atime_preserve_option == replace_atime_preserve
|
||||
&& fd && (is_dir || original_size != 0)
|
||||
&& set_file_atime (fd, parentfd, name, st->atime) != 0)
|
||||
utime_error (p);
|
||||
}
|
||||
@@ -1826,6 +1855,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
|
||||
write_long_link (st);
|
||||
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
st->stat.st_size = 0; /* force 0 size on symlink */
|
||||
header = start_header (st);
|
||||
@@ -1844,11 +1876,26 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
|
||||
}
|
||||
#endif
|
||||
else if (S_ISCHR (st->stat.st_mode))
|
||||
type = CHRTYPE;
|
||||
{
|
||||
type = CHRTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, 0, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
}
|
||||
else if (S_ISBLK (st->stat.st_mode))
|
||||
type = BLKTYPE;
|
||||
{
|
||||
type = BLKTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, 0, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
}
|
||||
else if (S_ISFIFO (st->stat.st_mode))
|
||||
type = FIFOTYPE;
|
||||
{
|
||||
type = FIFOTYPE;
|
||||
xattrs_acls_get (parentfd, name, st, 0, true);
|
||||
xattrs_selinux_get (parentfd, name, st, 0);
|
||||
xattrs_xattrs_get (parentfd, name, st, 0);
|
||||
}
|
||||
else if (S_ISSOCK (st->stat.st_mode))
|
||||
{
|
||||
WARNOPT (WARN_FILE_IGNORED,
|
||||
|
||||
27
src/delete.c
27
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 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>
|
||||
|
||||
361
src/exclist.c
Normal file
361
src/exclist.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/* Per-directory exclusion files for tar.
|
||||
|
||||
Copyright 2014 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];
|
||||
};
|
||||
|
||||
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_cleanup_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
struct exclist *ep = dir->exclude_list;
|
||||
|
||||
while (ep)
|
||||
{
|
||||
struct exclist *next = ep->next;
|
||||
|
||||
if (ep->flags & EXCL_NON_RECURSIVE)
|
||||
{
|
||||
|
||||
/* Remove the entry */
|
||||
if (ep->prev)
|
||||
ep->prev->next = ep->next;
|
||||
else
|
||||
dir->exclude_list = ep->next;
|
||||
|
||||
if (ep->next)
|
||||
ep->next->prev = ep->prev;
|
||||
|
||||
free_exclude (ep->excluded);
|
||||
free (ep);
|
||||
}
|
||||
ep = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
info_free_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int *hgopt;
|
||||
static int hg_options;
|
||||
|
||||
if (!data)
|
||||
hgopt = &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);
|
||||
}
|
||||
|
||||
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 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"
|
||||
|
||||
265
src/extract.c
265
src/extract.c
@@ -1,28 +1,30 @@
|
||||
/* Extract files from 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-2014 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-11-19.
|
||||
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-11-19. */
|
||||
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
#include <errno.h>
|
||||
#include <priv-set.h>
|
||||
#include <root-uid.h>
|
||||
#include <utimens.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -97,6 +99,14 @@ struct delayed_set_stat
|
||||
/* Directory that the name is relative to. */
|
||||
int change_dir;
|
||||
|
||||
/* extended attributes*/
|
||||
char *cntx_name;
|
||||
char *acls_a_ptr;
|
||||
size_t acls_a_len;
|
||||
char *acls_d_ptr;
|
||||
size_t acls_d_len;
|
||||
size_t xattr_map_size;
|
||||
struct xattr_array *xattr_map;
|
||||
/* Length and contents of name. */
|
||||
size_t file_name_len;
|
||||
char file_name[1];
|
||||
@@ -110,12 +120,15 @@ struct delayed_link
|
||||
/* The next delayed link in the list. */
|
||||
struct delayed_link *next;
|
||||
|
||||
/* The device, inode number and ctime of the placeholder. Use
|
||||
ctime, not mtime, to make false matches less likely if some
|
||||
other process removes the placeholder. */
|
||||
/* The device, inode number and birthtime of the placeholder.
|
||||
birthtime.tv_nsec is negative if the birthtime is not available.
|
||||
Don't use mtime as this would allow for false matches if some
|
||||
other process removes the placeholder. Don't use ctime as
|
||||
this would cause race conditions and other screwups, e.g.,
|
||||
when restoring hard-linked symlinks. */
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
struct timespec ctime;
|
||||
struct timespec birthtime;
|
||||
|
||||
/* True if the link is symbolic. */
|
||||
bool is_symlink;
|
||||
@@ -134,6 +147,18 @@ struct delayed_link
|
||||
hard-linked together. */
|
||||
struct string_list *sources;
|
||||
|
||||
/* SELinux context */
|
||||
char *cntx_name;
|
||||
|
||||
/* ACLs */
|
||||
char *acls_a_ptr;
|
||||
size_t acls_a_len;
|
||||
char *acls_d_ptr;
|
||||
size_t acls_d_len;
|
||||
|
||||
size_t xattr_map_size;
|
||||
struct xattr_array *xattr_map;
|
||||
|
||||
/* The desired target of the desired link. */
|
||||
char target[1];
|
||||
};
|
||||
@@ -150,7 +175,7 @@ struct string_list
|
||||
void
|
||||
extr_init (void)
|
||||
{
|
||||
we_are_root = geteuid () == 0;
|
||||
we_are_root = geteuid () == ROOT_UID;
|
||||
same_permissions_option += we_are_root;
|
||||
same_owner_option += we_are_root;
|
||||
|
||||
@@ -272,7 +297,7 @@ set_mode (char const *file_name,
|
||||
static void
|
||||
check_time (char const *file_name, struct timespec t)
|
||||
{
|
||||
if (t.tv_sec <= 0)
|
||||
if (t.tv_sec < 0)
|
||||
WARNOPT (WARN_TIMESTAMP,
|
||||
(0, 0, _("%s: implausibly old time stamp %s"),
|
||||
file_name, tartime (t, true)));
|
||||
@@ -360,6 +385,12 @@ set_stat (char const *file_name,
|
||||
st->stat.st_mode & ~ current_umask,
|
||||
0 < same_permissions_option && ! interdir ? MODE_ALL : MODE_RWX,
|
||||
fd, current_mode, current_mode_mask, typeflag, atflag);
|
||||
|
||||
/* these three calls must be done *after* fd_chown() call because fd_chown
|
||||
causes that linux capabilities becomes cleared. */
|
||||
xattrs_xattrs_set (st, file_name, typeflag, 1);
|
||||
xattrs_acls_set (st, file_name, typeflag);
|
||||
xattrs_selinux_set (st, file_name, typeflag);
|
||||
}
|
||||
|
||||
/* For each entry H in the leading prefix of entries in HEAD that do
|
||||
@@ -431,6 +462,36 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
|
||||
data->atflag = atflag;
|
||||
data->after_links = 0;
|
||||
data->change_dir = chdir_current;
|
||||
data->cntx_name = NULL;
|
||||
if (st)
|
||||
assign_string (&data->cntx_name, st->cntx_name);
|
||||
if (st && st->acls_a_ptr)
|
||||
{
|
||||
data->acls_a_ptr = xmemdup (st->acls_a_ptr, st->acls_a_len + 1);
|
||||
data->acls_a_len = st->acls_a_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->acls_a_ptr = NULL;
|
||||
data->acls_a_len = 0;
|
||||
}
|
||||
if (st && st->acls_d_ptr)
|
||||
{
|
||||
data->acls_d_ptr = xmemdup (st->acls_d_ptr, st->acls_d_len + 1);
|
||||
data->acls_d_len = st->acls_d_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->acls_d_ptr = NULL;
|
||||
data->acls_d_len = 0;
|
||||
}
|
||||
if (st)
|
||||
xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
|
||||
else
|
||||
{
|
||||
data->xattr_map = NULL;
|
||||
data->xattr_map_size = 0;
|
||||
}
|
||||
strcpy (data->file_name, file_name);
|
||||
delayed_set_stat_head = data;
|
||||
if (must_be_dot_or_slash (file_name))
|
||||
@@ -609,6 +670,18 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
switch (e)
|
||||
{
|
||||
case ELOOP:
|
||||
|
||||
/* With open ("symlink", O_NOFOLLOW|...), POSIX says errno == ELOOP,
|
||||
but some operating systems do not conform to the standard. */
|
||||
#ifdef EFTYPE
|
||||
/* NetBSD uses errno == EFTYPE; see <http://gnats.netbsd.org/43154>. */
|
||||
case EFTYPE:
|
||||
#endif
|
||||
/* FreeBSD 8.1 uses errno == EMLINK. */
|
||||
case EMLINK:
|
||||
/* Tru64 5.1B uses errno == ENOTSUP. */
|
||||
case ENOTSUP:
|
||||
|
||||
if (! regular
|
||||
|| old_files_option != OVERWRITE_OLD_FILES || dereference_option)
|
||||
break;
|
||||
@@ -627,9 +700,14 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
|
||||
switch (old_files_option)
|
||||
{
|
||||
case KEEP_OLD_FILES:
|
||||
case SKIP_OLD_FILES:
|
||||
WARNOPT (WARN_EXISTING_FILE,
|
||||
(0, 0, _("%s: skipping existing file"), file_name));
|
||||
return RECOVER_SKIP;
|
||||
|
||||
case KEEP_OLD_FILES:
|
||||
return RECOVER_NO;
|
||||
|
||||
case KEEP_NEWER_FILES:
|
||||
if (file_newer_p (file_name, stp, ¤t_stat_info))
|
||||
break;
|
||||
@@ -661,6 +739,40 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
return RECOVER_NO;
|
||||
}
|
||||
|
||||
/* Restore stat extended attributes (xattr) for FILE_NAME, using information
|
||||
given in *ST. Restore before extraction because they may affect file layout
|
||||
(e.g. on Lustre distributed parallel filesystem - setting info about how many
|
||||
servers is this file striped over, stripe size, mirror copies, etc.
|
||||
in advance dramatically improves the following performance of reading and
|
||||
writing a file). If not restoring permissions, invert the INVERT_PERMISSIONS
|
||||
bits from the file's current permissions. TYPEFLAG specifies the type of the
|
||||
file. FILE_CREATED indicates set_xattr has created the file */
|
||||
static int
|
||||
set_xattr (char const *file_name, struct tar_stat_info const *st,
|
||||
mode_t invert_permissions, char typeflag, int *file_created)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
bool interdir_made = false;
|
||||
|
||||
if ((xattrs_option > 0) && st->xattr_map_size)
|
||||
{
|
||||
mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
|
||||
|
||||
do
|
||||
status = mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0);
|
||||
while (status && maybe_recoverable ((char *)file_name, false,
|
||||
&interdir_made));
|
||||
|
||||
xattrs_xattrs_set (st, file_name, typeflag, 0);
|
||||
*file_created = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
/* Fix the statuses of all directories whose statuses need fixing, and
|
||||
which are not ancestors of FILE_NAME. If AFTER_LINKS is
|
||||
nonzero, do this for all such directories; otherwise, stop at the
|
||||
@@ -721,18 +833,43 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
|
||||
sb.stat.st_gid = data->gid;
|
||||
sb.atime = data->atime;
|
||||
sb.mtime = data->mtime;
|
||||
sb.cntx_name = data->cntx_name;
|
||||
sb.acls_a_ptr = data->acls_a_ptr;
|
||||
sb.acls_a_len = data->acls_a_len;
|
||||
sb.acls_d_ptr = data->acls_d_ptr;
|
||||
sb.acls_d_len = data->acls_d_len;
|
||||
sb.xattr_map = data->xattr_map;
|
||||
sb.xattr_map_size = data->xattr_map_size;
|
||||
set_stat (data->file_name, &sb,
|
||||
-1, current_mode, current_mode_mask,
|
||||
DIRTYPE, data->interdir, data->atflag);
|
||||
}
|
||||
|
||||
delayed_set_stat_head = data->next;
|
||||
xheader_xattr_free (data->xattr_map, data->xattr_map_size);
|
||||
free (data->cntx_name);
|
||||
free (data->acls_a_ptr);
|
||||
free (data->acls_d_ptr);
|
||||
free (data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
is_directory_link (const char *file_name)
|
||||
{
|
||||
struct stat st;
|
||||
int e = errno;
|
||||
int res;
|
||||
|
||||
res = (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 &&
|
||||
S_ISLNK (st.st_mode) &&
|
||||
fstatat (chdir_fd, file_name, &st, 0) == 0 &&
|
||||
S_ISDIR (st.st_mode));
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Extractor functions for various member types */
|
||||
|
||||
static int
|
||||
@@ -777,7 +914,7 @@ extract_dir (char *file_name, int typeflag)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
status = mkdir (file_name, mode);
|
||||
status = mkdirat (chdir_fd, file_name, mode);
|
||||
if (status == 0)
|
||||
{
|
||||
current_mode = mode & ~ current_umask;
|
||||
@@ -788,10 +925,15 @@ extract_dir (char *file_name, int typeflag)
|
||||
|
||||
if (errno == EEXIST
|
||||
&& (interdir_made
|
||||
|| keep_directory_symlink_option
|
||||
|| old_files_option == DEFAULT_OLD_FILES
|
||||
|| old_files_option == OVERWRITE_OLD_FILES))
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (keep_directory_symlink_option && is_directory_link (file_name))
|
||||
return 0;
|
||||
|
||||
if (deref_stat (file_name, &st) == 0)
|
||||
{
|
||||
current_mode = st.st_mode;
|
||||
@@ -842,7 +984,8 @@ extract_dir (char *file_name, int typeflag)
|
||||
|
||||
static int
|
||||
open_output_file (char const *file_name, int typeflag, mode_t mode,
|
||||
mode_t *current_mode, mode_t *current_mode_mask)
|
||||
int file_created, mode_t *current_mode,
|
||||
mode_t *current_mode_mask)
|
||||
{
|
||||
int fd;
|
||||
bool overwriting_old_files = old_files_option == OVERWRITE_OLD_FILES;
|
||||
@@ -852,6 +995,10 @@ open_output_file (char const *file_name, int typeflag, mode_t mode,
|
||||
? O_TRUNC | (dereference_option ? 0 : O_NOFOLLOW)
|
||||
: O_EXCL));
|
||||
|
||||
/* File might be created in set_xattr. So clear O_EXCL to avoid open() fail */
|
||||
if (file_created)
|
||||
openflag = openflag & ~O_EXCL;
|
||||
|
||||
if (typeflag == CONTTYPE)
|
||||
{
|
||||
static int conttype_diagnosed;
|
||||
@@ -864,6 +1011,21 @@ open_output_file (char const *file_name, int typeflag, mode_t mode,
|
||||
}
|
||||
}
|
||||
|
||||
/* If O_NOFOLLOW is needed but does not work, check for a symlink
|
||||
separately. There's a race condition, but that cannot be avoided
|
||||
on hosts lacking O_NOFOLLOW. */
|
||||
if (! HAVE_WORKING_O_NOFOLLOW
|
||||
&& overwriting_old_files && ! dereference_option)
|
||||
{
|
||||
struct stat st;
|
||||
if (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0
|
||||
&& S_ISLNK (st.st_mode))
|
||||
{
|
||||
errno = ELOOP;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd = openat (chdir_fd, file_name, openflag, mode);
|
||||
if (0 <= fd)
|
||||
{
|
||||
@@ -908,6 +1070,8 @@ extract_file (char *file_name, int typeflag)
|
||||
bool interdir_made = false;
|
||||
mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
|
||||
& ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
|
||||
mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO)
|
||||
: 0;
|
||||
mode_t current_mode = 0;
|
||||
mode_t current_mode_mask = 0;
|
||||
|
||||
@@ -924,8 +1088,18 @@ extract_file (char *file_name, int typeflag)
|
||||
}
|
||||
else
|
||||
{
|
||||
int file_created = 0;
|
||||
if (set_xattr (file_name, ¤t_stat_info, invert_permissions,
|
||||
typeflag, &file_created))
|
||||
{
|
||||
skip_member ();
|
||||
open_error (file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((fd = open_output_file (file_name, typeflag, mode,
|
||||
¤t_mode, ¤t_mode_mask))
|
||||
file_created, ¤t_mode,
|
||||
¤t_mode_mask))
|
||||
< 0)
|
||||
{
|
||||
int recover = maybe_recoverable (file_name, true, &interdir_made);
|
||||
@@ -964,7 +1138,7 @@ extract_file (char *file_name, int typeflag)
|
||||
if (written > size)
|
||||
written = size;
|
||||
errno = 0;
|
||||
count = full_write (fd, data_block->buffer, written);
|
||||
count = blocking_write (fd, data_block->buffer, written);
|
||||
size -= written;
|
||||
|
||||
set_next_block_after ((union block *)
|
||||
@@ -1050,7 +1224,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
delayed_link_head = p;
|
||||
p->dev = st.st_dev;
|
||||
p->ino = st.st_ino;
|
||||
p->ctime = get_stat_ctime (&st);
|
||||
p->birthtime = get_stat_birthtime (&st);
|
||||
p->is_symlink = is_symlink;
|
||||
if (is_symlink)
|
||||
{
|
||||
@@ -1065,6 +1239,13 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
|
||||
+ strlen (file_name) + 1);
|
||||
p->sources->next = 0;
|
||||
strcpy (p->sources->string, file_name);
|
||||
p->cntx_name = NULL;
|
||||
assign_string (&p->cntx_name, current_stat_info.cntx_name);
|
||||
p->acls_a_ptr = NULL;
|
||||
p->acls_a_len = 0;
|
||||
p->acls_d_ptr = NULL;
|
||||
p->acls_d_len = 0;
|
||||
xheader_xattr_copy (¤t_stat_info, &p->xattr_map, &p->xattr_map_size);
|
||||
strcpy (p->target, current_stat_info.link_name);
|
||||
|
||||
h = delayed_set_stat_head;
|
||||
@@ -1108,7 +1289,8 @@ extract_link (char *file_name, int typeflag)
|
||||
if (ds->change_dir == chdir_current
|
||||
&& ds->dev == st1.st_dev
|
||||
&& ds->ino == st1.st_ino
|
||||
&& timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0)
|
||||
&& (timespec_cmp (ds->birthtime, get_stat_birthtime (&st1))
|
||||
== 0))
|
||||
{
|
||||
struct string_list *p = xmalloc (offsetof (struct string_list, string)
|
||||
+ strlen (file_name) + 1);
|
||||
@@ -1178,7 +1360,7 @@ extract_symlink (char *file_name, int typeflag)
|
||||
if (!warned_once)
|
||||
{
|
||||
warned_once = 1;
|
||||
WARNOPT (WARN_SYMBOLIC_CAST,
|
||||
WARNOPT (WARN_SYMLINK_CAST,
|
||||
(0, 0,
|
||||
_("Attempting extraction of symbolic links as hard links")));
|
||||
}
|
||||
@@ -1191,7 +1373,7 @@ static int
|
||||
extract_node (char *file_name, int typeflag)
|
||||
{
|
||||
bool interdir_made = false;
|
||||
mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
|
||||
mode_t mode = (current_stat_info.stat.st_mode & (MODE_RWX | S_IFBLK | S_IFCHR)
|
||||
& ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
|
||||
|
||||
while (mknodat (chdir_fd, file_name, mode, current_stat_info.stat.st_rdev)
|
||||
@@ -1258,6 +1440,13 @@ extract_failure (char *file_name, int typeflag)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
extract_skip (char *file_name, int typeflag)
|
||||
{
|
||||
skip_member ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*tar_extractor_t) (char *file_name, int typeflag);
|
||||
|
||||
|
||||
@@ -1338,7 +1527,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
ERROR ((0, 0,
|
||||
_("%s: Cannot extract -- file is continued from another volume"),
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
*fun = extract_failure;
|
||||
*fun = extract_skip;
|
||||
break;
|
||||
|
||||
case GNUTYPE_LONGNAME:
|
||||
@@ -1350,7 +1539,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
default:
|
||||
WARNOPT (WARN_UNKNOWN_CAST,
|
||||
(0, 0,
|
||||
_("%s: Unknown file type `%c', extracted as normal file"),
|
||||
_("%s: Unknown file type '%c', extracted as normal file"),
|
||||
quotearg_colon (file_name), typeflag));
|
||||
*fun = extract_file;
|
||||
}
|
||||
@@ -1474,7 +1663,7 @@ apply_delayed_links (void)
|
||||
if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0
|
||||
&& st.st_dev == ds->dev
|
||||
&& st.st_ino == ds->ino
|
||||
&& timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0)
|
||||
&& timespec_cmp (get_stat_birthtime (&st), ds->birthtime) == 0)
|
||||
{
|
||||
/* Unlink the placeholder, then create a hard link if possible,
|
||||
a symbolic link otherwise. */
|
||||
@@ -1499,6 +1688,13 @@ apply_delayed_links (void)
|
||||
st1.stat.st_gid = ds->gid;
|
||||
st1.atime = ds->atime;
|
||||
st1.mtime = ds->mtime;
|
||||
st1.cntx_name = ds->cntx_name;
|
||||
st1.acls_a_ptr = ds->acls_a_ptr;
|
||||
st1.acls_a_len = ds->acls_a_len;
|
||||
st1.acls_d_ptr = ds->acls_d_ptr;
|
||||
st1.acls_d_len = ds->acls_d_len;
|
||||
st1.xattr_map = ds->xattr_map;
|
||||
st1.xattr_map_size = ds->xattr_map_size;
|
||||
set_stat (source, &st1, -1, 0, 0, SYMTYPE,
|
||||
false, AT_SYMLINK_NOFOLLOW);
|
||||
valid_source = source;
|
||||
@@ -1513,6 +1709,9 @@ apply_delayed_links (void)
|
||||
sources = next;
|
||||
}
|
||||
|
||||
xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
|
||||
free (ds->cntx_name);
|
||||
|
||||
{
|
||||
struct delayed_link *next = ds->next;
|
||||
free (ds);
|
||||
|
||||
598
src/incremen.c
598
src/incremen.c
@@ -1,21 +1,22 @@
|
||||
/* GNU dump extensions to tar.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2009, 2013-2014
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This 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 <hash.h>
|
||||
@@ -279,7 +280,7 @@ free_directory (struct directory *dir)
|
||||
static struct directory *
|
||||
attach_directory (const char *name)
|
||||
{
|
||||
char *cname = normalize_filename (name);
|
||||
char *cname = normalize_filename (chdir_current, name);
|
||||
struct directory *dir = make_directory (name, cname);
|
||||
if (dirtail)
|
||||
dirtail->next = dir;
|
||||
@@ -300,6 +301,24 @@ dirlist_replace_prefix (const char *pref, const char *repl)
|
||||
replace_prefix (&dp->name, pref, pref_len, repl, repl_len);
|
||||
}
|
||||
|
||||
void
|
||||
clear_directory_table (void)
|
||||
{
|
||||
struct directory *dp;
|
||||
|
||||
if (directory_table)
|
||||
hash_clear (directory_table);
|
||||
if (directory_meta_table)
|
||||
hash_clear (directory_meta_table);
|
||||
for (dp = dirhead; dp; )
|
||||
{
|
||||
struct directory *next = dp->next;
|
||||
free_directory (dp);
|
||||
dp = next;
|
||||
}
|
||||
dirhead = dirtail = NULL;
|
||||
}
|
||||
|
||||
/* Create and link a new directory entry for directory NAME, having a
|
||||
device number DEV and an inode number INO, with NFS indicating
|
||||
whether it is an NFS device and FOUND indicating whether we have
|
||||
@@ -327,7 +346,8 @@ note_directory (char const *name, struct timespec mtime,
|
||||
if (! ((directory_table
|
||||
|| (directory_table = hash_initialize (0, 0,
|
||||
hash_directory_canonical_name,
|
||||
compare_directory_canonical_names, 0)))
|
||||
compare_directory_canonical_names,
|
||||
0)))
|
||||
&& hash_insert (directory_table, directory)))
|
||||
xalloc_die ();
|
||||
|
||||
@@ -350,7 +370,7 @@ find_directory (const char *name)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
char *caname = normalize_filename (name);
|
||||
char *caname = normalize_filename (chdir_current, name);
|
||||
struct directory *dir = make_directory (name, caname);
|
||||
struct directory *ret = hash_lookup (directory_table, dir);
|
||||
free_directory (dir);
|
||||
@@ -426,8 +446,8 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
{
|
||||
struct directory *directory;
|
||||
struct stat *stat_data = &st->stat;
|
||||
dev_t device = st->parent ? st->parent->stat.st_dev : 0;
|
||||
bool nfs = NFS_FILE_STAT (*stat_data);
|
||||
bool perhaps_renamed = false;
|
||||
|
||||
if ((directory = find_directory (name_buffer)) != NULL)
|
||||
{
|
||||
@@ -482,9 +502,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
}
|
||||
else
|
||||
{
|
||||
WARNOPT (WARN_RENAME_DIRECTORY,
|
||||
(0, 0, _("%s: Directory has been renamed"),
|
||||
quotearg_colon (name_buffer)));
|
||||
perhaps_renamed = true;
|
||||
directory->children = ALL_CHILDREN;
|
||||
directory->device_number = stat_data->st_dev;
|
||||
directory->inode_number = stat_data->st_ino;
|
||||
@@ -503,7 +521,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
stat_data->st_ino);
|
||||
|
||||
directory = note_directory (name_buffer,
|
||||
get_stat_mtime(stat_data),
|
||||
get_stat_mtime (stat_data),
|
||||
stat_data->st_dev,
|
||||
stat_data->st_ino,
|
||||
nfs,
|
||||
@@ -540,18 +558,23 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
}
|
||||
}
|
||||
|
||||
/* If the directory is on another device and --one-file-system was given,
|
||||
omit it... */
|
||||
if (one_file_system_option && device != stat_data->st_dev
|
||||
/* ... except if it was explicitely given in the command line */
|
||||
&& !is_individual_file (name_buffer))
|
||||
/* FIXME:
|
||||
WARNOPT (WARN_XDEV,
|
||||
(0, 0,
|
||||
_("%s: directory is on a different filesystem; not dumped"),
|
||||
quotearg_colon (directory->name)));
|
||||
*/
|
||||
directory->children = NO_CHILDREN;
|
||||
if (one_file_system_option && st->parent
|
||||
&& stat_data->st_dev != st->parent->stat.st_dev)
|
||||
{
|
||||
WARNOPT (WARN_XDEV,
|
||||
(0, 0,
|
||||
_("%s: directory is on a different filesystem; not dumped"),
|
||||
quotearg_colon (directory->name)));
|
||||
directory->children = NO_CHILDREN;
|
||||
/* If there is any dumpdir info in that directory, remove it */
|
||||
if (directory->dump)
|
||||
{
|
||||
dumpdir_free (directory->dump);
|
||||
directory->dump = NULL;
|
||||
}
|
||||
perhaps_renamed = false;
|
||||
}
|
||||
|
||||
else if (flag & PD_FORCE_CHILDREN)
|
||||
{
|
||||
directory->children = PD_CHILDREN(flag);
|
||||
@@ -559,6 +582,11 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
*entry = 'N';
|
||||
}
|
||||
|
||||
if (perhaps_renamed)
|
||||
WARNOPT (WARN_RENAME_DIRECTORY,
|
||||
(0, 0, _("%s: Directory has been renamed"),
|
||||
quotearg_colon (name_buffer)));
|
||||
|
||||
DIR_SET_FLAG (directory, DIRF_INIT);
|
||||
|
||||
if (directory->children != NO_CHILDREN)
|
||||
@@ -581,6 +609,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st,
|
||||
exclusion_tag_warning (name_buffer, tag_file_name,
|
||||
_("contents not dumped"));
|
||||
directory->children = NO_CHILDREN;
|
||||
directory->tagfile = tag_file_name;
|
||||
break;
|
||||
|
||||
case exclusion_tag_under:
|
||||
@@ -652,15 +681,13 @@ makedumpdir (struct directory *directory, const char *dir)
|
||||
if (loc)
|
||||
{
|
||||
if (directory->tagfile)
|
||||
*new_dump_ptr = strcmp (directory->tagfile, array[i]) == 0 ?
|
||||
' ' : 'I';
|
||||
*new_dump_ptr = 'I';
|
||||
else
|
||||
*new_dump_ptr = ' ';
|
||||
new_dump_ptr++;
|
||||
}
|
||||
else if (directory->tagfile)
|
||||
*new_dump_ptr++ = strcmp (directory->tagfile, array[i]) == 0 ?
|
||||
' ' : 'I';
|
||||
*new_dump_ptr++ = 'I';
|
||||
else
|
||||
*new_dump_ptr++ = 'Y'; /* New entry */
|
||||
|
||||
@@ -671,9 +698,26 @@ makedumpdir (struct directory *directory, const char *dir)
|
||||
*new_dump_ptr = 0;
|
||||
directory->idump = directory->dump;
|
||||
directory->dump = dumpdir_create0 (new_dump, NULL);
|
||||
free (new_dump);
|
||||
free (array);
|
||||
}
|
||||
|
||||
/* Create a dumpdir containing only one entry: that for the
|
||||
tagfile. */
|
||||
static void
|
||||
maketagdumpdir (struct directory *directory)
|
||||
{
|
||||
size_t len = strlen (directory->tagfile) + 1;
|
||||
char *new_dump = xmalloc (len + 2);
|
||||
new_dump[0] = 'Y';
|
||||
memcpy (new_dump + 1, directory->tagfile, len);
|
||||
new_dump[len + 1] = 0;
|
||||
|
||||
directory->idump = directory->dump;
|
||||
directory->dump = dumpdir_create0 (new_dump, NULL);
|
||||
free (new_dump);
|
||||
}
|
||||
|
||||
/* Recursively scan the directory identified by ST. */
|
||||
struct directory *
|
||||
scan_directory (struct tar_stat_info *st)
|
||||
@@ -690,6 +734,8 @@ scan_directory (struct tar_stat_info *st)
|
||||
if (! dirp)
|
||||
savedir_error (dir);
|
||||
|
||||
info_attach_exclist (st);
|
||||
|
||||
tmp = xstrdup (dir);
|
||||
zap_slashes (tmp);
|
||||
|
||||
@@ -701,90 +747,97 @@ scan_directory (struct tar_stat_info *st)
|
||||
|
||||
nbuf = namebuf_create (dir);
|
||||
|
||||
if (dirp && directory->children != NO_CHILDREN)
|
||||
if (dirp)
|
||||
{
|
||||
char *entry; /* directory entry being scanned */
|
||||
struct dumpdir_iter *itr;
|
||||
|
||||
makedumpdir (directory, dirp);
|
||||
|
||||
for (entry = dumpdir_first (directory->dump, 1, &itr);
|
||||
entry;
|
||||
entry = dumpdir_next (itr))
|
||||
if (directory->children != NO_CHILDREN)
|
||||
{
|
||||
char *full_name = namebuf_name (nbuf, entry + 1);
|
||||
char *entry; /* directory entry being scanned */
|
||||
struct dumpdir_iter *itr;
|
||||
|
||||
if (*entry == 'I') /* Ignored entry */
|
||||
*entry = 'N';
|
||||
else if (excluded_name (full_name))
|
||||
*entry = 'N';
|
||||
else
|
||||
makedumpdir (directory, dirp);
|
||||
|
||||
for (entry = dumpdir_first (directory->dump, 1, &itr);
|
||||
entry;
|
||||
entry = dumpdir_next (itr))
|
||||
{
|
||||
int fd = st->fd;
|
||||
void (*diag) (char const *) = 0;
|
||||
struct tar_stat_info stsub;
|
||||
tar_stat_init (&stsub);
|
||||
char *full_name = namebuf_name (nbuf, entry + 1);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
errno = - fd;
|
||||
diag = open_diag;
|
||||
}
|
||||
else if (fstatat (fd, entry + 1, &stsub.stat, fstatat_flags) != 0)
|
||||
diag = stat_diag;
|
||||
else if (S_ISDIR (stsub.stat.st_mode))
|
||||
{
|
||||
int subfd = subfile_open (st, entry + 1, open_read_flags);
|
||||
if (subfd < 0)
|
||||
diag = open_diag;
|
||||
else
|
||||
{
|
||||
stsub.fd = subfd;
|
||||
if (fstat (subfd, &stsub.stat) != 0)
|
||||
diag = stat_diag;
|
||||
}
|
||||
}
|
||||
|
||||
if (diag)
|
||||
{
|
||||
file_removed_diag (full_name, false, diag);
|
||||
*entry = 'N';
|
||||
}
|
||||
else if (S_ISDIR (stsub.stat.st_mode))
|
||||
{
|
||||
int pd_flag = 0;
|
||||
if (!recursion_option)
|
||||
pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
|
||||
else if (directory->children == ALL_CHILDREN)
|
||||
pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
|
||||
*entry = 'D';
|
||||
|
||||
stsub.parent = st;
|
||||
procdir (full_name, &stsub, pd_flag, entry);
|
||||
restore_parent_fd (&stsub);
|
||||
}
|
||||
else if (one_file_system_option && device != stsub.stat.st_dev)
|
||||
if (*entry == 'I') /* Ignored entry */
|
||||
*entry = 'N';
|
||||
else if (*entry == 'Y')
|
||||
/* New entry, skip further checks */;
|
||||
/* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
|
||||
else if (OLDER_STAT_TIME (stsub.stat, m)
|
||||
&& (!after_date_option
|
||||
|| OLDER_STAT_TIME (stsub.stat, c)))
|
||||
else if (excluded_name (full_name, st))
|
||||
*entry = 'N';
|
||||
else
|
||||
*entry = 'Y';
|
||||
{
|
||||
int fd = st->fd;
|
||||
void (*diag) (char const *) = 0;
|
||||
struct tar_stat_info stsub;
|
||||
tar_stat_init (&stsub);
|
||||
|
||||
tar_stat_destroy (&stsub);
|
||||
if (fd < 0)
|
||||
{
|
||||
errno = - fd;
|
||||
diag = open_diag;
|
||||
}
|
||||
else if (fstatat (fd, entry + 1, &stsub.stat,
|
||||
fstatat_flags) != 0)
|
||||
diag = stat_diag;
|
||||
else if (S_ISDIR (stsub.stat.st_mode))
|
||||
{
|
||||
int subfd = subfile_open (st, entry + 1,
|
||||
open_read_flags);
|
||||
if (subfd < 0)
|
||||
diag = open_diag;
|
||||
else
|
||||
{
|
||||
stsub.fd = subfd;
|
||||
if (fstat (subfd, &stsub.stat) != 0)
|
||||
diag = stat_diag;
|
||||
}
|
||||
}
|
||||
|
||||
if (diag)
|
||||
{
|
||||
file_removed_diag (full_name, false, diag);
|
||||
*entry = 'N';
|
||||
}
|
||||
else if (S_ISDIR (stsub.stat.st_mode))
|
||||
{
|
||||
int pd_flag = 0;
|
||||
if (!recursion_option)
|
||||
pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
|
||||
else if (directory->children == ALL_CHILDREN)
|
||||
pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
|
||||
*entry = 'D';
|
||||
|
||||
stsub.parent = st;
|
||||
procdir (full_name, &stsub, pd_flag, entry);
|
||||
restore_parent_fd (&stsub);
|
||||
}
|
||||
else if (one_file_system_option &&
|
||||
device != stsub.stat.st_dev)
|
||||
*entry = 'N';
|
||||
else if (*entry == 'Y')
|
||||
/* New entry, skip further checks */;
|
||||
/* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
|
||||
else if (OLDER_STAT_TIME (stsub.stat, m)
|
||||
&& (!after_date_option
|
||||
|| OLDER_STAT_TIME (stsub.stat, c)))
|
||||
*entry = 'N';
|
||||
else
|
||||
*entry = 'Y';
|
||||
|
||||
tar_stat_destroy (&stsub);
|
||||
}
|
||||
}
|
||||
free (itr);
|
||||
}
|
||||
free (itr);
|
||||
else if (directory->tagfile)
|
||||
maketagdumpdir (directory);
|
||||
}
|
||||
|
||||
namebuf_free (nbuf);
|
||||
|
||||
if (dirp)
|
||||
free (dirp);
|
||||
free (dirp);
|
||||
|
||||
return directory;
|
||||
}
|
||||
@@ -834,7 +887,7 @@ store_rename (struct directory *dir, struct obstack *stk)
|
||||
are ignored when hit by this function next time.
|
||||
If the chain forms a cycle, prev points to the entry DIR is renamed
|
||||
from. In this case it still retains DIRF_RENAMED flag, which will be
|
||||
cleared in the `else' branch below */
|
||||
cleared in the 'else' branch below */
|
||||
for (prev = dir; prev && prev->orig != dir; prev = prev->orig)
|
||||
DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
|
||||
|
||||
@@ -920,8 +973,6 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
{
|
||||
int n;
|
||||
uintmax_t u;
|
||||
time_t sec;
|
||||
long int nsec;
|
||||
char *buf = NULL;
|
||||
size_t bufsize = 0;
|
||||
char *ebuf;
|
||||
@@ -943,21 +994,15 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
bufsize = strlen (buf) + 1;
|
||||
}
|
||||
|
||||
sec = TYPE_MINIMUM (time_t);
|
||||
nsec = -1;
|
||||
errno = 0;
|
||||
u = strtoumax (buf, &ebuf, 10);
|
||||
if (!errno && TYPE_MAXIMUM (time_t) < u)
|
||||
errno = ERANGE;
|
||||
if (errno || buf == ebuf)
|
||||
newer_mtime_option = decode_timespec (buf, &ebuf, false);
|
||||
|
||||
if (! valid_timespec (newer_mtime_option))
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option),
|
||||
lineno,
|
||||
_("Invalid time stamp")));
|
||||
else
|
||||
{
|
||||
sec = u;
|
||||
|
||||
if (version == 1 && *ebuf)
|
||||
{
|
||||
char const *buf_ns = ebuf + 1;
|
||||
@@ -971,20 +1016,13 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
quotearg_colon (listed_incremental_option),
|
||||
lineno,
|
||||
_("Invalid time stamp")));
|
||||
sec = TYPE_MINIMUM (time_t);
|
||||
newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t);
|
||||
newer_mtime_option.tv_nsec = -1;
|
||||
}
|
||||
else
|
||||
nsec = u;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pre-1 incremental format does not contain nanoseconds */
|
||||
nsec = 0;
|
||||
newer_mtime_option.tv_nsec = u;
|
||||
}
|
||||
}
|
||||
newer_mtime_option.tv_sec = sec;
|
||||
newer_mtime_option.tv_nsec = nsec;
|
||||
|
||||
|
||||
while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
|
||||
{
|
||||
@@ -1001,20 +1039,12 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
|
||||
if (version == 1)
|
||||
{
|
||||
errno = 0;
|
||||
u = strtoumax (strp, &ebuf, 10);
|
||||
if (!errno && TYPE_MAXIMUM (time_t) < u)
|
||||
errno = ERANGE;
|
||||
if (errno || strp == ebuf || *ebuf != ' ')
|
||||
{
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time (seconds)")));
|
||||
sec = (time_t) -1;
|
||||
}
|
||||
else
|
||||
sec = u;
|
||||
mtime = decode_timespec (strp, &ebuf, false);
|
||||
strp = ebuf;
|
||||
if (!valid_timespec (mtime) || *strp != ' ')
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time")));
|
||||
|
||||
errno = 0;
|
||||
u = strtoumax (strp, &ebuf, 10);
|
||||
@@ -1025,46 +1055,30 @@ read_incr_db_01 (int version, const char *initbuf)
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid modification time (nanoseconds)")));
|
||||
nsec = -1;
|
||||
mtime.tv_nsec = -1;
|
||||
}
|
||||
else
|
||||
nsec = u;
|
||||
mtime.tv_sec = sec;
|
||||
mtime.tv_nsec = nsec;
|
||||
mtime.tv_nsec = u;
|
||||
strp = ebuf;
|
||||
}
|
||||
else
|
||||
memset (&mtime, 0, sizeof mtime);
|
||||
mtime.tv_sec = mtime.tv_nsec = 0;
|
||||
|
||||
errno = 0;
|
||||
u = strtoumax (strp, &ebuf, 10);
|
||||
if (!errno && TYPE_MAXIMUM (dev_t) < u)
|
||||
errno = ERANGE;
|
||||
if (errno || strp == ebuf || *ebuf != ' ')
|
||||
{
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid device number")));
|
||||
dev = (dev_t) -1;
|
||||
}
|
||||
else
|
||||
dev = u;
|
||||
dev = strtosysint (strp, &ebuf,
|
||||
TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t));
|
||||
strp = ebuf;
|
||||
if (errno || *strp != ' ')
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid device number")));
|
||||
|
||||
errno = 0;
|
||||
u = strtoumax (strp, &ebuf, 10);
|
||||
if (!errno && TYPE_MAXIMUM (ino_t) < u)
|
||||
errno = ERANGE;
|
||||
if (errno || strp == ebuf || *ebuf != ' ')
|
||||
{
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid inode number")));
|
||||
ino = (ino_t) -1;
|
||||
}
|
||||
else
|
||||
ino = u;
|
||||
ino = strtosysint (strp, &ebuf,
|
||||
TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t));
|
||||
strp = ebuf;
|
||||
if (errno || *strp != ' ')
|
||||
ERROR ((0, errno, "%s:%ld: %s",
|
||||
quotearg_colon (listed_incremental_option), lineno,
|
||||
_("Invalid inode number")));
|
||||
|
||||
strp++;
|
||||
unquote_string (strp);
|
||||
@@ -1091,97 +1105,84 @@ read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Read from file FP a nul-terminated string and convert it to
|
||||
intmax_t. Return the resulting value in PVAL. Assume '-' has
|
||||
already been read.
|
||||
/* Read from file FP a null-terminated string and convert it to an
|
||||
integer. FIELDNAME is the intended use of the integer, useful for
|
||||
diagnostics. MIN_VAL and MAX_VAL are its minimum and maximum
|
||||
permissible values; MIN_VAL must be nonpositive and MAX_VAL positive.
|
||||
Store into *PVAL the resulting value, converted to intmax_t.
|
||||
|
||||
Throw a fatal error if the string cannot be converted or if the
|
||||
converted value is less than MIN_VAL. */
|
||||
converted value is out of range.
|
||||
|
||||
static void
|
||||
read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval)
|
||||
Return true if successful, false if end of file. */
|
||||
|
||||
static bool
|
||||
read_num (FILE *fp, char const *fieldname,
|
||||
intmax_t min_val, uintmax_t max_val, intmax_t *pval)
|
||||
{
|
||||
int c;
|
||||
size_t i;
|
||||
int i;
|
||||
char buf[INT_BUFSIZE_BOUND (intmax_t)];
|
||||
char *ep;
|
||||
buf[0] = '-';
|
||||
char offbuf[INT_BUFSIZE_BOUND (off_t)];
|
||||
char minbuf[INT_BUFSIZE_BOUND (intmax_t)];
|
||||
char maxbuf[INT_BUFSIZE_BOUND (intmax_t)];
|
||||
int conversion_errno;
|
||||
int c = getc (fp);
|
||||
bool negative = c == '-';
|
||||
|
||||
for (i = 1; ISDIGIT (c = getc (fp)); i++)
|
||||
for (i = 0; (i == 0 && negative) || ISDIGIT (c); i++)
|
||||
{
|
||||
if (i == sizeof buf - 1)
|
||||
FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
if (ferror (fp))
|
||||
FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
|
||||
else
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
errno = 0;
|
||||
*pval = strtoimax (buf, &ep, 10);
|
||||
if (c || errno || *pval < min_val)
|
||||
FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
|
||||
}
|
||||
|
||||
/* Read from file FP a nul-terminated string and convert it to
|
||||
uintmax_t. Return the resulting value in PVAL. Assume C has
|
||||
already been read.
|
||||
|
||||
Throw a fatal error if the string cannot be converted or if the
|
||||
converted value exceeds MAX_VAL.
|
||||
|
||||
Return the last character read or EOF on end of file. */
|
||||
|
||||
static int
|
||||
read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval)
|
||||
{
|
||||
size_t i;
|
||||
char buf[UINTMAX_STRSIZE_BOUND], *ep;
|
||||
|
||||
for (i = 0; ISDIGIT (c); i++)
|
||||
{
|
||||
if (i == sizeof buf - 1)
|
||||
FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
|
||||
buf[i] = c;
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("%s: byte %s: %s %.*s... too long"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (fp), offbuf),
|
||||
fieldname, i + 1, buf));
|
||||
c = getc (fp);
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
if (ferror (fp))
|
||||
FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
|
||||
else if (i == 0)
|
||||
return c;
|
||||
else
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
|
||||
read_fatal (listed_incremental_option);
|
||||
if (i != 0)
|
||||
FATAL_ERROR ((0, 0, "%s: %s",
|
||||
quotearg_colon (listed_incremental_option),
|
||||
_("Unexpected EOF in snapshot file")));
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
errno = 0;
|
||||
*pval = strtoumax (buf, &ep, 10);
|
||||
if (c || errno || max_val < *pval)
|
||||
FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
|
||||
return c;
|
||||
}
|
||||
if (c)
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("%s: byte %s: %s %s followed by invalid byte 0x%02x"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (fp), offbuf),
|
||||
fieldname, buf, c));
|
||||
|
||||
/* Read from file FP a nul-terminated string and convert it to
|
||||
uintmax_t. Return the resulting value in PVAL.
|
||||
*pval = strtosysint (buf, NULL, min_val, max_val);
|
||||
conversion_errno = errno;
|
||||
|
||||
Throw a fatal error if the string cannot be converted or if the
|
||||
converted value exceeds MAX_VAL.
|
||||
switch (conversion_errno)
|
||||
{
|
||||
case ERANGE:
|
||||
FATAL_ERROR ((0, conversion_errno,
|
||||
_("%s: byte %s: (valid range %s..%s)\n\t%s %s"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (fp), offbuf),
|
||||
imaxtostr (min_val, minbuf),
|
||||
umaxtostr (max_val, maxbuf), fieldname, buf));
|
||||
default:
|
||||
FATAL_ERROR ((0, conversion_errno,
|
||||
_("%s: byte %s: %s %s"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (fp), offbuf), fieldname, buf));
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
|
||||
Return the last character read or EOF on end of file. */
|
||||
|
||||
static int
|
||||
read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval)
|
||||
{
|
||||
return read_unsigned_num (getc (fp), fp, max_val, pval);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Read from FP two NUL-terminated strings representing a struct
|
||||
@@ -1192,35 +1193,28 @@ read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval)
|
||||
static void
|
||||
read_timespec (FILE *fp, struct timespec *pval)
|
||||
{
|
||||
int c = getc (fp);
|
||||
intmax_t i;
|
||||
uintmax_t u;
|
||||
intmax_t s, ns;
|
||||
|
||||
if (c == '-')
|
||||
if (read_num (fp, "sec", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &s)
|
||||
&& read_num (fp, "nsec", 0, BILLION - 1, &ns))
|
||||
{
|
||||
read_negative_num (fp, TYPE_MINIMUM (time_t), &i);
|
||||
c = 0;
|
||||
pval->tv_sec = i;
|
||||
pval->tv_sec = s;
|
||||
pval->tv_nsec = ns;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u);
|
||||
pval->tv_sec = u;
|
||||
FATAL_ERROR ((0, 0, "%s: %s",
|
||||
quotearg_colon (listed_incremental_option),
|
||||
_("Unexpected EOF in snapshot file")));
|
||||
}
|
||||
|
||||
if (c || read_num (fp, BILLION - 1, &u))
|
||||
FATAL_ERROR ((0, 0, "%s: %s",
|
||||
quotearg_colon (listed_incremental_option),
|
||||
_("Unexpected EOF in snapshot file")));
|
||||
pval->tv_nsec = u;
|
||||
}
|
||||
|
||||
/* Read incremental snapshot format 2 */
|
||||
static void
|
||||
read_incr_db_2 (void)
|
||||
{
|
||||
uintmax_t u;
|
||||
struct obstack stk;
|
||||
char offbuf[INT_BUFSIZE_BOUND (off_t)];
|
||||
|
||||
obstack_init (&stk);
|
||||
|
||||
@@ -1228,6 +1222,7 @@ read_incr_db_2 (void)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
intmax_t i;
|
||||
struct timespec mtime;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
@@ -1236,20 +1231,22 @@ read_incr_db_2 (void)
|
||||
char *content;
|
||||
size_t s;
|
||||
|
||||
if (read_num (listed_incremental_stream, 1, &u))
|
||||
if (! read_num (listed_incremental_stream, "nfs", 0, 1, &i))
|
||||
return; /* Normal return */
|
||||
|
||||
nfs = u;
|
||||
nfs = i;
|
||||
|
||||
read_timespec (listed_incremental_stream, &mtime);
|
||||
|
||||
if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))
|
||||
if (! read_num (listed_incremental_stream, "dev",
|
||||
TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i))
|
||||
break;
|
||||
dev = u;
|
||||
dev = i;
|
||||
|
||||
if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))
|
||||
if (! read_num (listed_incremental_stream, "ino",
|
||||
TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i))
|
||||
break;
|
||||
ino = u;
|
||||
ino = i;
|
||||
|
||||
if (read_obstack (listed_incremental_stream, &stk, &s))
|
||||
break;
|
||||
@@ -1259,8 +1256,9 @@ read_incr_db_2 (void)
|
||||
while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
|
||||
;
|
||||
if (getc (listed_incremental_stream) != 0)
|
||||
FATAL_ERROR ((0, 0, "%s: %s",
|
||||
FATAL_ERROR ((0, 0, _("%s: byte %s: %s"),
|
||||
quotearg_colon (listed_incremental_option),
|
||||
offtostr (ftello (listed_incremental_stream), offbuf),
|
||||
_("Missing record terminator")));
|
||||
|
||||
content = obstack_finish (&stk);
|
||||
@@ -1272,6 +1270,51 @@ read_incr_db_2 (void)
|
||||
_("Unexpected EOF in snapshot file")));
|
||||
}
|
||||
|
||||
/* Display (to stdout) the range of allowed values for each field
|
||||
in the snapshot file. The array below should be kept in sync
|
||||
with any changes made to the read_num() calls in the parsing
|
||||
loop inside read_incr_db_2().
|
||||
|
||||
(This function is invoked via the --show-snapshot-field-ranges
|
||||
command line option.) */
|
||||
|
||||
struct field_range
|
||||
{
|
||||
char const *fieldname;
|
||||
intmax_t min_val;
|
||||
uintmax_t max_val;
|
||||
};
|
||||
|
||||
static struct field_range const field_ranges[] = {
|
||||
{ "nfs", 0, 1 },
|
||||
{ "timestamp_sec", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t) },
|
||||
{ "timestamp_nsec", 0, BILLION - 1 },
|
||||
{ "dev", TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t) },
|
||||
{ "ino", TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t) },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
void
|
||||
show_snapshot_field_ranges (void)
|
||||
{
|
||||
struct field_range const *p;
|
||||
char minbuf[SYSINT_BUFSIZE];
|
||||
char maxbuf[SYSINT_BUFSIZE];
|
||||
|
||||
printf("This tar's snapshot file field ranges are\n");
|
||||
printf (" (%-15s => [ %s, %s ]):\n\n", "field name", "min", "max");
|
||||
|
||||
for (p=field_ranges; p->fieldname != NULL; p++)
|
||||
{
|
||||
printf (" %-15s => [ %s, %s ],\n", p->fieldname,
|
||||
sysinttostr (p->min_val, p->min_val, p->max_val, minbuf),
|
||||
sysinttostr (p->max_val, p->min_val, p->max_val, maxbuf));
|
||||
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Read incremental snapshot file (directory file).
|
||||
If the file has older incremental version, make sure that it is processed
|
||||
correctly and that tar will use the most conservative backup method among
|
||||
@@ -1352,8 +1395,7 @@ read_directory_file (void)
|
||||
|
||||
if (ferror (listed_incremental_stream))
|
||||
read_error (listed_incremental_option);
|
||||
if (buf)
|
||||
free (buf);
|
||||
free (buf);
|
||||
}
|
||||
|
||||
/* Output incremental data for the directory ENTRY to the file DATA.
|
||||
@@ -1366,20 +1408,21 @@ write_directory_file_entry (void *entry, void *data)
|
||||
|
||||
if (DIR_IS_FOUND (directory))
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
char buf[SYSINT_BUFSIZE];
|
||||
char const *s;
|
||||
|
||||
s = DIR_IS_NFS (directory) ? "1" : "0";
|
||||
fwrite (s, 2, 1, fp);
|
||||
s = (TYPE_SIGNED (time_t)
|
||||
? imaxtostr (directory->mtime.tv_sec, buf)
|
||||
: umaxtostr (directory->mtime.tv_sec, buf));
|
||||
s = sysinttostr (directory->mtime.tv_sec, TYPE_MINIMUM (time_t),
|
||||
TYPE_MAXIMUM (time_t), buf);
|
||||
fwrite (s, strlen (s) + 1, 1, fp);
|
||||
s = umaxtostr (directory->mtime.tv_nsec, buf);
|
||||
s = imaxtostr (directory->mtime.tv_nsec, buf);
|
||||
fwrite (s, strlen (s) + 1, 1, fp);
|
||||
s = umaxtostr (directory->device_number, buf);
|
||||
s = sysinttostr (directory->device_number,
|
||||
TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), buf);
|
||||
fwrite (s, strlen (s) + 1, 1, fp);
|
||||
s = umaxtostr (directory->inode_number, buf);
|
||||
s = sysinttostr (directory->inode_number,
|
||||
TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), buf);
|
||||
fwrite (s, strlen (s) + 1, 1, fp);
|
||||
|
||||
fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
|
||||
@@ -1586,7 +1629,7 @@ try_purge_directory (char const *directory_name)
|
||||
if (!is_dumpdir (¤t_stat_info))
|
||||
return false;
|
||||
|
||||
current_dir = savedir (directory_name);
|
||||
current_dir = tar_savedir (directory_name, 0);
|
||||
|
||||
if (!current_dir)
|
||||
/* The directory doesn't exist now. It'll be created. In any
|
||||
@@ -1664,8 +1707,7 @@ try_purge_directory (char const *directory_name)
|
||||
{
|
||||
const char *entry;
|
||||
struct stat st;
|
||||
if (p)
|
||||
free (p);
|
||||
free (p);
|
||||
p = new_name (directory_name, cur);
|
||||
|
||||
if (deref_stat (p, &st) != 0)
|
||||
|
||||
354
src/list.c
354
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-2014 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,15 +26,13 @@
|
||||
|
||||
#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 */
|
||||
|
||||
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
|
||||
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
|
||||
@@ -46,11 +45,11 @@ union block *recent_global_header; /* Recent global header block */
|
||||
static gid_t gid_from_header (const char *buf, size_t size);
|
||||
static major_t major_from_header (const char *buf, size_t size);
|
||||
static minor_t minor_from_header (const char *buf, size_t size);
|
||||
static mode_t mode_from_header (const char *buf, size_t size, unsigned *hbits);
|
||||
static 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 uintmax_t from_header (const char *, size_t, const char *,
|
||||
uintmax_t, uintmax_t, bool, bool);
|
||||
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] =
|
||||
@@ -75,6 +74,93 @@ 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)
|
||||
return;
|
||||
|
||||
if (strncmp (p, one_top_level_dir, strlen (one_top_level_dir)) == 0)
|
||||
{
|
||||
int pos = strlen (one_top_level_dir);
|
||||
if (ISSLASH (p[pos]) || p[pos] == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
*pfile_name = new_name (one_top_level_dir, file_name);
|
||||
normalize_filename_x (*pfile_name);
|
||||
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))
|
||||
@@ -117,7 +203,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)
|
||||
{
|
||||
@@ -136,6 +223,8 @@ read_and (void (*do_something) (void))
|
||||
}
|
||||
}
|
||||
|
||||
transform_stat_info (current_header->header.typeflag,
|
||||
¤t_stat_info);
|
||||
(*do_something) ();
|
||||
continue;
|
||||
|
||||
@@ -256,7 +345,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;
|
||||
@@ -281,9 +370,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;
|
||||
@@ -346,7 +434,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
|
||||
@@ -372,15 +464,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;
|
||||
}
|
||||
@@ -439,8 +529,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)
|
||||
{
|
||||
@@ -471,8 +560,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)
|
||||
{
|
||||
@@ -495,47 +583,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;
|
||||
}
|
||||
|
||||
static 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
|
||||
@@ -556,7 +603,7 @@ 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)
|
||||
@@ -572,7 +619,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;
|
||||
@@ -586,6 +635,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);
|
||||
@@ -655,38 +706,34 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
|| stat_info->dumpdir)
|
||||
stat_info->is_dumpdir = true;
|
||||
}
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_VOLHDR)
|
||||
/* Name transformations don't apply to volume headers. */
|
||||
return;
|
||||
|
||||
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. */
|
||||
@@ -705,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++;
|
||||
}
|
||||
@@ -714,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;
|
||||
}
|
||||
|
||||
@@ -745,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++;
|
||||
@@ -758,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,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)
|
||||
{
|
||||
@@ -858,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.) */
|
||||
@@ -870,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)
|
||||
{
|
||||
@@ -896,8 +943,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -905,26 +951,26 @@ 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);
|
||||
}
|
||||
|
||||
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. */
|
||||
Set *HBITS if there are any unrecognized bits. */
|
||||
static mode_t
|
||||
mode_from_header (const char *p, size_t s, unsigned *hbits)
|
||||
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)
|
||||
@@ -937,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;
|
||||
}
|
||||
|
||||
@@ -946,31 +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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1060,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 */
|
||||
@@ -1093,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
|
||||
{
|
||||
@@ -1120,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';
|
||||
@@ -1152,6 +1200,9 @@ 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, full_time_option);
|
||||
@@ -1173,17 +1224,11 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
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),
|
||||
0, UINTMAX_MAX,
|
||||
false, false);
|
||||
if (u != -1)
|
||||
user = STRINGIFY_BIGINT (u, uform);
|
||||
else
|
||||
{
|
||||
sprintf (uform, "%ld",
|
||||
(long) UID_FROM_HEADER (blk->header.uid));
|
||||
user = uform;
|
||||
}
|
||||
user = (u != -1
|
||||
? STRINGIFY_BIGINT (u, uform)
|
||||
: imaxtostr (UID_FROM_HEADER (blk->header.uid), uform));
|
||||
}
|
||||
|
||||
if (st->gname
|
||||
@@ -1198,17 +1243,11 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
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),
|
||||
0, UINTMAX_MAX,
|
||||
false, false);
|
||||
if (g != -1)
|
||||
group = STRINGIFY_BIGINT (g, gform);
|
||||
else
|
||||
{
|
||||
sprintf (gform, "%ld",
|
||||
(long) GID_FROM_HEADER (blk->header.gid));
|
||||
group = gform;
|
||||
}
|
||||
group = (g != -1
|
||||
? STRINGIFY_BIGINT (g, gform)
|
||||
: imaxtostr (GID_FROM_HEADER (blk->header.gid), gform));
|
||||
}
|
||||
|
||||
/* Format the file size or major/minor device numbers. */
|
||||
@@ -1242,6 +1281,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)
|
||||
{
|
||||
@@ -1297,6 +1338,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
|
||||
}
|
||||
}
|
||||
fflush (stdlis);
|
||||
xattrs_print (st);
|
||||
}
|
||||
|
||||
|
||||
@@ -1353,8 +1395,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1411,7 +1453,7 @@ skip_member (void)
|
||||
}
|
||||
|
||||
void
|
||||
test_archive_label ()
|
||||
test_archive_label (void)
|
||||
{
|
||||
base64_init ();
|
||||
name_gather ();
|
||||
|
||||
407
src/misc.c
407
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, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992, 1994-1997, 1999-2001, 2003-2007, 2009-2010,
|
||||
2012-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -14,9 +14,9 @@
|
||||
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"
|
||||
@@ -29,6 +29,8 @@
|
||||
# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
|
||||
#endif
|
||||
|
||||
static const char *tar_getcdpath (int);
|
||||
|
||||
|
||||
/* Handling strings. */
|
||||
|
||||
@@ -37,8 +39,7 @@
|
||||
void
|
||||
assign_string (char **string, const char *value)
|
||||
{
|
||||
if (*string)
|
||||
free (*string);
|
||||
free (*string);
|
||||
*string = value ? xstrdup (value) : 0;
|
||||
}
|
||||
|
||||
@@ -106,7 +107,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,11 +231,12 @@ zap_slashes (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. */
|
||||
static void
|
||||
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)
|
||||
{
|
||||
char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
@@ -268,37 +270,42 @@ normalize_filename_x (char *file_name)
|
||||
}
|
||||
|
||||
/* Normalize NAME by removing redundant slashes and "." components,
|
||||
including redundant trailing slashes. Return a normalized
|
||||
newly-allocated copy. */
|
||||
including redundant trailing slashes.
|
||||
|
||||
Return a normalized newly-allocated copy. */
|
||||
|
||||
char *
|
||||
normalize_filename (const char *name)
|
||||
normalize_filename (int cdidx, const char *name)
|
||||
{
|
||||
char *copy = NULL;
|
||||
|
||||
if (IS_RELATIVE_FILE_NAME (name))
|
||||
{
|
||||
/* Set COPY to the absolute file name if possible.
|
||||
/* Set COPY to the absolute path for this name.
|
||||
|
||||
FIXME: There should be no need to get the absolute file name.
|
||||
getcwd is slow, it might fail, and it does not necessarily
|
||||
return a canonical name even when it succeeds. Perhaps we
|
||||
can use dev+ino pairs instead of names? */
|
||||
copy = xgetcwd ();
|
||||
if (copy)
|
||||
{
|
||||
size_t copylen = strlen (copy);
|
||||
bool need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT
|
||||
&& copylen == 2 && ISSLASH (copy[1]));
|
||||
copy = xrealloc (copy, copylen + need_separator + strlen (name) + 1);
|
||||
copy[copylen] = DIRECTORY_SEPARATOR;
|
||||
strcpy (copy + copylen + need_separator, name);
|
||||
}
|
||||
else
|
||||
WARN ((0, errno, _("Cannot get working directory")));
|
||||
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)
|
||||
if (!copy)
|
||||
copy = xstrdup (name);
|
||||
normalize_filename_x (copy);
|
||||
return copy;
|
||||
@@ -326,6 +333,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. */
|
||||
@@ -382,6 +459,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. */
|
||||
|
||||
@@ -484,7 +639,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;
|
||||
|
||||
@@ -617,6 +772,57 @@ deref_stat (char const *name, struct stat *buf)
|
||||
return fstatat (chdir_fd, name, buf, fstatat_flags);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
size_t bytes = safe_read (fd, buf, count);
|
||||
|
||||
#if defined F_SETFL && O_NONBLOCK
|
||||
if (bytes == SAFE_READ_ERROR && errno == EAGAIN)
|
||||
{
|
||||
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 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
|
||||
@@ -633,7 +839,11 @@ struct wd
|
||||
{
|
||||
/* The directory's name. */
|
||||
char const *name;
|
||||
|
||||
/* "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. */
|
||||
@@ -663,7 +873,7 @@ static int wdcache[CHDIR_CACHE_SIZE];
|
||||
static size_t wdcache_count;
|
||||
|
||||
int
|
||||
chdir_count ()
|
||||
chdir_count (void)
|
||||
{
|
||||
if (wd_count == 0)
|
||||
return wd_count;
|
||||
@@ -675,19 +885,18 @@ 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].abspath = xgetcwd ();
|
||||
wd[wd_count].fd = AT_FDCWD;
|
||||
wd_count++;
|
||||
}
|
||||
@@ -704,7 +913,22 @@ chdir_arg (char const *dir)
|
||||
return wd_count - 1;
|
||||
}
|
||||
|
||||
|
||||
/* If the given name is absolute, use it to represent this directory;
|
||||
otherwise, construct a name based on the previous -C option. */
|
||||
if (IS_ABSOLUTE_FILE_NAME (dir))
|
||||
absdir = xstrdup (dir);
|
||||
else if (wd[wd_count - 1].abspath)
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath);
|
||||
namebuf_add_dir (nbuf, dir);
|
||||
absdir = namebuf_finish (nbuf);
|
||||
}
|
||||
else
|
||||
absdir = 0;
|
||||
|
||||
wd[wd_count].name = dir;
|
||||
wd[wd_count].abspath = absdir;
|
||||
wd[wd_count].fd = 0;
|
||||
return wd_count++;
|
||||
}
|
||||
@@ -764,11 +988,11 @@ chdir_do (int i)
|
||||
int prev = wdcache[0];
|
||||
for (ci = 1; prev != i; ci++)
|
||||
{
|
||||
int curr = wdcache[ci];
|
||||
int cur = wdcache[ci];
|
||||
wdcache[ci] = prev;
|
||||
if (curr == i)
|
||||
if (cur == i)
|
||||
break;
|
||||
prev = curr;
|
||||
prev = cur;
|
||||
}
|
||||
wdcache[0] = i;
|
||||
}
|
||||
@@ -778,6 +1002,32 @@ chdir_do (int i)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -856,21 +1106,6 @@ file_removed_diag (const char *name, bool top_level,
|
||||
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)
|
||||
{
|
||||
@@ -927,7 +1162,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 */
|
||||
};
|
||||
@@ -961,3 +1196,55 @@ namebuf_name (namebuf_t buf, const char *name)
|
||||
strcpy (buf->buffer + buf->dir_length, name);
|
||||
return buf->buffer;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
410
src/names.c
410
src/names.c
@@ -1,7 +1,7 @@
|
||||
/* Various processing of names.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
|
||||
Copyright 1988, 1992, 1994, 1996-2001, 2003-2007, 2009, 2013-2014
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -14,14 +14,15 @@
|
||||
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 <fnmatch.h>
|
||||
#include <hash.h>
|
||||
#include <quotearg.h>
|
||||
#include <wordsplit.h>
|
||||
#include <argp.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -47,8 +48,6 @@ static char *cached_no_such_gname;
|
||||
static uid_t cached_no_such_uid;
|
||||
static gid_t cached_no_such_gid;
|
||||
|
||||
static void register_individual_file (char const *name);
|
||||
|
||||
/* Given UID, find the corresponding UNAME. */
|
||||
void
|
||||
uid_to_uname (uid_t uid, char **uname)
|
||||
@@ -199,7 +198,7 @@ static struct name *namelist; /* first name in list, if any */
|
||||
static struct name *nametail; /* end of name list */
|
||||
|
||||
/* File name arguments are processed in two stages: first a
|
||||
name_array (see below) is filled, then the names from it
|
||||
name element list (see below) is filled, then the names from it
|
||||
are moved into the namelist.
|
||||
|
||||
This awkward process is needed only to implement --same-order option,
|
||||
@@ -209,39 +208,72 @@ static struct name *nametail; /* end of name list */
|
||||
|
||||
However, I very much doubt if we still need this -- Sergey */
|
||||
|
||||
/* A name_array element contains entries of three types: */
|
||||
/* A name_list element contains entries of three types: */
|
||||
|
||||
#define NELT_NAME 0 /* File name */
|
||||
#define NELT_CHDIR 1 /* Change directory request */
|
||||
#define NELT_FMASK 2 /* Change fnmatch options request */
|
||||
#define NELT_FILE 3 /* Read file names from that file */
|
||||
#define NELT_NOOP 4 /* No operation */
|
||||
|
||||
struct name_elt /* A name_array element. */
|
||||
{
|
||||
struct name_elt *next, *prev;
|
||||
char type; /* Element type, see NELT_* constants above */
|
||||
union
|
||||
{
|
||||
const char *name; /* File or directory name */
|
||||
int matching_flags;/* fnmatch options if type == NELT_FMASK */
|
||||
struct /* File, if type == NELT_FILE */
|
||||
{
|
||||
const char *name;/* File name */
|
||||
int term; /* File name terminator in the list */
|
||||
FILE *fp;
|
||||
} file;
|
||||
} v;
|
||||
};
|
||||
|
||||
static struct name_elt *name_array; /* store an array of names */
|
||||
static size_t allocated_entries; /* how big is the array? */
|
||||
static size_t entries; /* how many entries does it have? */
|
||||
static size_t scanned; /* how many of the entries have we scanned? */
|
||||
size_t name_count; /* how many of the entries are names? */
|
||||
static struct name_elt *name_head; /* store a list of names */
|
||||
size_t name_count; /* how many of the entries are names? */
|
||||
|
||||
/* Check the size of name_array, reallocating it as necessary. */
|
||||
static void
|
||||
check_name_alloc (void)
|
||||
static struct name_elt *
|
||||
name_elt_alloc (void)
|
||||
{
|
||||
if (entries == allocated_entries)
|
||||
struct name_elt *elt;
|
||||
|
||||
elt = xmalloc (sizeof (*elt));
|
||||
if (!name_head)
|
||||
{
|
||||
if (allocated_entries == 0)
|
||||
allocated_entries = 10; /* Set initial allocation */
|
||||
name_array = x2nrealloc (name_array, &allocated_entries,
|
||||
sizeof (name_array[0]));
|
||||
name_head = elt;
|
||||
name_head->prev = name_head->next = NULL;
|
||||
name_head->type = NELT_NOOP;
|
||||
elt = xmalloc (sizeof (*elt));
|
||||
}
|
||||
|
||||
elt->prev = name_head->prev;
|
||||
if (name_head->prev)
|
||||
name_head->prev->next = elt;
|
||||
elt->next = name_head;
|
||||
name_head->prev = elt;
|
||||
return elt;
|
||||
}
|
||||
|
||||
static void
|
||||
name_list_adjust (void)
|
||||
{
|
||||
if (name_head)
|
||||
while (name_head->prev)
|
||||
name_head = name_head->prev;
|
||||
}
|
||||
|
||||
static void
|
||||
name_list_advance (void)
|
||||
{
|
||||
struct name_elt *elt = name_head;
|
||||
name_head = elt->next;
|
||||
if (name_head)
|
||||
name_head->prev = NULL;
|
||||
free (elt);
|
||||
}
|
||||
|
||||
/* Add to name_array the file NAME with fnmatch options MATCHING_FLAGS */
|
||||
@@ -249,17 +281,14 @@ void
|
||||
name_add_name (const char *name, int matching_flags)
|
||||
{
|
||||
static int prev_flags = 0; /* FIXME: Or EXCLUDE_ANCHORED? */
|
||||
struct name_elt *ep;
|
||||
struct name_elt *ep = name_elt_alloc ();
|
||||
|
||||
check_name_alloc ();
|
||||
ep = &name_array[entries++];
|
||||
if (prev_flags != matching_flags)
|
||||
{
|
||||
ep->type = NELT_FMASK;
|
||||
ep->v.matching_flags = matching_flags;
|
||||
prev_flags = matching_flags;
|
||||
check_name_alloc ();
|
||||
ep = &name_array[entries++];
|
||||
ep = name_elt_alloc ();
|
||||
}
|
||||
ep->type = NELT_NAME;
|
||||
ep->v.name = name;
|
||||
@@ -270,13 +299,20 @@ name_add_name (const char *name, int matching_flags)
|
||||
void
|
||||
name_add_dir (const char *name)
|
||||
{
|
||||
struct name_elt *ep;
|
||||
check_name_alloc ();
|
||||
ep = &name_array[entries++];
|
||||
struct name_elt *ep = name_elt_alloc ();
|
||||
ep->type = NELT_CHDIR;
|
||||
ep->v.name = name;
|
||||
}
|
||||
|
||||
void
|
||||
name_add_file (const char *name, int term)
|
||||
{
|
||||
struct name_elt *ep = name_elt_alloc ();
|
||||
ep->type = NELT_FILE;
|
||||
ep->v.file.name = name;
|
||||
ep->v.file.term = term;
|
||||
ep->v.file.fp = NULL;
|
||||
}
|
||||
|
||||
/* Names from external name file. */
|
||||
|
||||
@@ -290,15 +326,224 @@ name_init (void)
|
||||
{
|
||||
name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
|
||||
name_buffer_length = NAME_FIELD_SIZE;
|
||||
name_list_adjust ();
|
||||
}
|
||||
|
||||
void
|
||||
name_term (void)
|
||||
{
|
||||
free (name_buffer);
|
||||
free (name_array);
|
||||
}
|
||||
|
||||
/* Prevent recursive inclusion of the same file */
|
||||
struct file_id_list
|
||||
{
|
||||
struct file_id_list *next;
|
||||
ino_t ino;
|
||||
dev_t dev;
|
||||
const char *from_file;
|
||||
};
|
||||
|
||||
static struct file_id_list *file_id_list;
|
||||
|
||||
/* Return the name of the file from which the file names and options
|
||||
are being read.
|
||||
*/
|
||||
static const char *
|
||||
file_list_name (void)
|
||||
{
|
||||
struct name_elt *elt;
|
||||
|
||||
for (elt = name_head; elt; elt = elt->next)
|
||||
if (elt->type == NELT_FILE && elt->v.file.fp)
|
||||
return elt->v.file.name;
|
||||
return _("command line");
|
||||
}
|
||||
|
||||
static int
|
||||
add_file_id (const char *filename)
|
||||
{
|
||||
struct file_id_list *p;
|
||||
struct stat st;
|
||||
const char *reading_from;
|
||||
|
||||
if (stat (filename, &st))
|
||||
stat_fatal (filename);
|
||||
reading_from = file_list_name ();
|
||||
for (p = file_id_list; p; p = p->next)
|
||||
if (p->ino == st.st_ino && p->dev == st.st_dev)
|
||||
{
|
||||
int oldc = set_char_quoting (NULL, ':', 1);
|
||||
ERROR ((0, 0,
|
||||
_("%s: file list requested from %s already read from %s"),
|
||||
quotearg_n (0, filename),
|
||||
reading_from, p->from_file));
|
||||
set_char_quoting (NULL, ':', oldc);
|
||||
return 1;
|
||||
}
|
||||
p = xmalloc (sizeof *p);
|
||||
p->next = file_id_list;
|
||||
p->ino = st.st_ino;
|
||||
p->dev = st.st_dev;
|
||||
p->from_file = reading_from;
|
||||
file_id_list = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum read_file_list_state /* Result of reading file name from the list file */
|
||||
{
|
||||
file_list_success, /* OK, name read successfully */
|
||||
file_list_end, /* End of list file */
|
||||
file_list_zero, /* Zero separator encountered where it should not */
|
||||
file_list_skip /* Empty (zero-length) entry encountered, skip it */
|
||||
};
|
||||
|
||||
/* Read from FP a sequence of characters up to TERM and put them
|
||||
into STK.
|
||||
*/
|
||||
static enum read_file_list_state
|
||||
read_name_from_file (struct name_elt *ent)
|
||||
{
|
||||
int c;
|
||||
size_t counter = 0;
|
||||
FILE *fp = ent->v.file.fp;
|
||||
int term = ent->v.file.term;
|
||||
|
||||
for (c = getc (fp); c != EOF && c != term; c = getc (fp))
|
||||
{
|
||||
if (counter == name_buffer_length)
|
||||
name_buffer = x2realloc (name_buffer, &name_buffer_length);
|
||||
name_buffer[counter++] = c;
|
||||
if (c == 0)
|
||||
{
|
||||
/* We have read a zero separator. The file possibly is
|
||||
zero-separated */
|
||||
return file_list_zero;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == 0 && c != EOF)
|
||||
return file_list_skip;
|
||||
|
||||
if (counter == name_buffer_length)
|
||||
name_buffer = x2realloc (name_buffer, &name_buffer_length);
|
||||
name_buffer[counter] = 0;
|
||||
|
||||
return (counter == 0 && c == EOF) ? file_list_end : file_list_success;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_option (const char *str)
|
||||
{
|
||||
struct wordsplit ws;
|
||||
int i;
|
||||
|
||||
while (*str && isspace (*str))
|
||||
++str;
|
||||
if (*str != '-')
|
||||
return 1;
|
||||
|
||||
ws.ws_offs = 1;
|
||||
if (wordsplit (str, &ws, WRDSF_DEFFLAGS|WRDSF_DOOFFS))
|
||||
FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"),
|
||||
str, wordsplit_strerror (&ws)));
|
||||
ws.ws_wordv[0] = program_invocation_short_name;
|
||||
more_options (ws.ws_wordc+ws.ws_offs, ws.ws_wordv);
|
||||
for (i = 0; i < ws.ws_wordc+ws.ws_offs; i++)
|
||||
ws.ws_wordv[i] = NULL;
|
||||
|
||||
wordsplit_free (&ws);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_next_name (struct name_elt *ent, struct name_elt *ret)
|
||||
{
|
||||
if (!ent->v.file.fp)
|
||||
{
|
||||
if (!strcmp (ent->v.file.name, "-"))
|
||||
{
|
||||
request_stdin ("-T");
|
||||
ent->v.file.fp = stdin;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (add_file_id (ent->v.file.name))
|
||||
{
|
||||
name_list_advance ();
|
||||
return 1;
|
||||
}
|
||||
if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) == NULL)
|
||||
open_fatal (ent->v.file.name);
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (read_name_from_file (ent))
|
||||
{
|
||||
case file_list_skip:
|
||||
continue;
|
||||
|
||||
case file_list_zero:
|
||||
WARNOPT (WARN_FILENAME_WITH_NULS,
|
||||
(0, 0, N_("%s: file name read contains nul character"),
|
||||
quotearg_colon (ent->v.file.name)));
|
||||
ent->v.file.term = 0;
|
||||
/* fall through */
|
||||
case file_list_success:
|
||||
if (unquote_option)
|
||||
unquote_string (name_buffer);
|
||||
if (handle_option (name_buffer) == 0)
|
||||
{
|
||||
name_list_adjust ();
|
||||
return 1;
|
||||
}
|
||||
ret->type = NELT_NAME;
|
||||
ret->v.name = name_buffer;
|
||||
return 0;
|
||||
|
||||
case file_list_end:
|
||||
if (strcmp (ent->v.file.name, "-"))
|
||||
fclose (ent->v.file.fp);
|
||||
ent->v.file.fp = NULL;
|
||||
name_list_advance ();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
copy_name (struct name_elt *ep)
|
||||
{
|
||||
const char *source;
|
||||
size_t source_len;
|
||||
char *cursor;
|
||||
|
||||
source = ep->v.name;
|
||||
source_len = strlen (source);
|
||||
if (name_buffer_length < source_len)
|
||||
{
|
||||
do
|
||||
{
|
||||
name_buffer_length *= 2;
|
||||
if (! name_buffer_length)
|
||||
xalloc_die ();
|
||||
}
|
||||
while (name_buffer_length < source_len);
|
||||
|
||||
free (name_buffer);
|
||||
name_buffer = xmalloc(name_buffer_length + 2);
|
||||
}
|
||||
strcpy (name_buffer, source);
|
||||
|
||||
/* Zap trailing slashes. */
|
||||
cursor = name_buffer + strlen (name_buffer) - 1;
|
||||
while (cursor > name_buffer && ISSLASH (*cursor))
|
||||
*cursor-- = '\0';
|
||||
}
|
||||
|
||||
|
||||
static int matching_flags; /* exclude_fnmatch options */
|
||||
|
||||
/* Get the next NELT_NAME element from name_array. Result is in
|
||||
@@ -313,57 +558,42 @@ static struct name_elt *
|
||||
name_next_elt (int change_dirs)
|
||||
{
|
||||
static struct name_elt entry;
|
||||
const char *source;
|
||||
char *cursor;
|
||||
struct name_elt *ep;
|
||||
|
||||
while (scanned != entries)
|
||||
while ((ep = name_head) != NULL)
|
||||
{
|
||||
struct name_elt *ep;
|
||||
size_t source_len;
|
||||
|
||||
ep = &name_array[scanned++];
|
||||
if (ep->type == NELT_FMASK)
|
||||
switch (ep->type)
|
||||
{
|
||||
case NELT_NOOP:
|
||||
name_list_advance ();
|
||||
break;
|
||||
|
||||
case NELT_FMASK:
|
||||
matching_flags = ep->v.matching_flags;
|
||||
recursion_option = matching_flags & FNM_LEADING_DIR;
|
||||
name_list_advance ();
|
||||
continue;
|
||||
}
|
||||
|
||||
source = ep->v.name;
|
||||
source_len = strlen (source);
|
||||
if (name_buffer_length < source_len)
|
||||
{
|
||||
do
|
||||
case NELT_FILE:
|
||||
if (read_next_name (ep, &entry) == 0)
|
||||
return &entry;
|
||||
continue;
|
||||
|
||||
case NELT_CHDIR:
|
||||
if (change_dirs)
|
||||
{
|
||||
name_buffer_length *= 2;
|
||||
if (! name_buffer_length)
|
||||
xalloc_die ();
|
||||
chdir_do (chdir_arg (xstrdup (ep->v.name)));
|
||||
name_list_advance ();
|
||||
break;
|
||||
}
|
||||
while (name_buffer_length < source_len);
|
||||
|
||||
free (name_buffer);
|
||||
name_buffer = xmalloc (name_buffer_length + 2);
|
||||
}
|
||||
strcpy (name_buffer, source);
|
||||
|
||||
/* Zap trailing slashes. */
|
||||
|
||||
cursor = name_buffer + strlen (name_buffer) - 1;
|
||||
while (cursor > name_buffer && ISSLASH (*cursor))
|
||||
*cursor-- = '\0';
|
||||
|
||||
if (change_dirs && ep->type == NELT_CHDIR)
|
||||
{
|
||||
if (chdir (name_buffer) < 0)
|
||||
chdir_fatal (name_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fall through */
|
||||
case NELT_NAME:
|
||||
copy_name (ep);
|
||||
if (unquote_option)
|
||||
unquote_string (name_buffer);
|
||||
if (incremental_option)
|
||||
register_individual_file (name_buffer);
|
||||
entry.type = ep->type;
|
||||
entry.v.name = name_buffer;
|
||||
name_list_advance ();
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
@@ -673,9 +903,9 @@ label_notfound (void)
|
||||
|
||||
/* Sort *singly* linked LIST of names, of given LENGTH, using COMPARE
|
||||
to order names. Return the sorted list. Note that after calling
|
||||
this function, the `prev' links in list elements are messed up.
|
||||
this function, the 'prev' links in list elements are messed up.
|
||||
|
||||
Apart from the type `struct name' and the definition of SUCCESSOR,
|
||||
Apart from the type 'struct name' and the definition of SUCCESSOR,
|
||||
this is a generic list-sorting function, but it's too painful to
|
||||
make it both generic and portable
|
||||
in C. */
|
||||
@@ -898,7 +1128,7 @@ name_compare (void const *entry1, void const *entry2)
|
||||
}
|
||||
|
||||
|
||||
/* Rebase `name' member of CHILD and all its siblings to
|
||||
/* Rebase 'name' member of CHILD and all its siblings to
|
||||
the new PARENT. */
|
||||
static void
|
||||
rebase_child_list (struct name *child, struct name *parent)
|
||||
@@ -1012,13 +1242,11 @@ collect_and_sort_names (void)
|
||||
namelist = merge_sort (namelist, num_names, compare_names);
|
||||
|
||||
num_names = 0;
|
||||
nametab = hash_initialize (0, 0,
|
||||
name_hash,
|
||||
name_compare, NULL);
|
||||
nametab = hash_initialize (0, 0, name_hash, name_compare, NULL);
|
||||
for (name = namelist; name; name = next_name)
|
||||
{
|
||||
next_name = name->next;
|
||||
name->caname = normalize_filename (name->name);
|
||||
name->caname = normalize_filename (name->change_dir, name->name);
|
||||
if (prev_name)
|
||||
{
|
||||
struct name *p = hash_lookup (nametab, name);
|
||||
@@ -1104,7 +1332,7 @@ name_scan (const char *file_name)
|
||||
struct name *gnu_list_name;
|
||||
|
||||
struct name const *
|
||||
name_from_list ()
|
||||
name_from_list (void)
|
||||
{
|
||||
if (!gnu_list_name)
|
||||
gnu_list_name = namelist;
|
||||
@@ -1145,34 +1373,6 @@ new_name (const char *file_name, const char *name)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Return nonzero if file NAME is excluded. */
|
||||
bool
|
||||
excluded_name (char const *name)
|
||||
{
|
||||
return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
|
||||
}
|
||||
|
||||
static Hash_table *individual_file_table;
|
||||
|
||||
static void
|
||||
register_individual_file (char const *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (deref_stat (name, &st) != 0)
|
||||
return; /* Will be complained about later */
|
||||
if (S_ISDIR (st.st_mode))
|
||||
return;
|
||||
|
||||
hash_string_insert (&individual_file_table, name);
|
||||
}
|
||||
|
||||
bool
|
||||
is_individual_file (char const *name)
|
||||
{
|
||||
return hash_string_lookup (individual_file_table, name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return the size of the prefix of FILE_NAME that is removed after
|
||||
|
||||
67
src/sparse.c
67
src/sparse.c
@@ -1,7 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright 2003-2007, 2010, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -14,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>
|
||||
@@ -230,7 +228,7 @@ sparse_scan_file (struct tar_sparse_file *file)
|
||||
if (!tar_sparse_scan (file, scan_begin, NULL))
|
||||
return false;
|
||||
|
||||
while ((count = safe_read (fd, buffer, sizeof buffer)) != 0
|
||||
while ((count = blocking_read (fd, buffer, sizeof buffer)) != 0
|
||||
&& count != SAFE_READ_ERROR)
|
||||
{
|
||||
/* Analyze the block. */
|
||||
@@ -360,7 +358,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);
|
||||
@@ -591,18 +589,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... */
|
||||
|
||||
@@ -629,8 +627,8 @@ oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
|
||||
return add_finish;
|
||||
sp.offset = OFF_FROM_HEADER (s->offset);
|
||||
sp.numbytes = OFF_FROM_HEADER (s->numbytes);
|
||||
if (sp.offset < 0
|
||||
|| sp.offset + sp.numbytes < 0
|
||||
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;
|
||||
@@ -644,10 +642,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 */
|
||||
@@ -768,10 +766,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 */
|
||||
@@ -811,6 +809,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)
|
||||
@@ -919,6 +918,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)
|
||||
{
|
||||
@@ -968,9 +979,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)
|
||||
{
|
||||
@@ -1029,12 +1038,13 @@ pax_dump_header_1 (struct tar_sparse_file *file)
|
||||
xheader_store ("GNU.sparse.name", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.realsize", file->stat_info, NULL);
|
||||
|
||||
file->stat_info->file_name = xheader_format_name (file->stat_info,
|
||||
"%d/GNUSparseFile.%p/%f", 0);
|
||||
file->stat_info->file_name =
|
||||
xheader_format_name (file->stat_info, "%d/GNUSparseFile.%p/%f", 0);
|
||||
/* Make sure the created header name is shorter than NAME_FIELD_SIZE: */
|
||||
if (strlen (file->stat_info->file_name) > NAME_FIELD_SIZE)
|
||||
file->stat_info->file_name[NAME_FIELD_SIZE] = 0;
|
||||
|
||||
blk = start_header (file->stat_info);
|
||||
/* Store the effective (shrunken) file size */
|
||||
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);
|
||||
free (file->stat_info->file_name);
|
||||
file->stat_info->file_name = save_file_name;
|
||||
@@ -1077,6 +1087,7 @@ 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)
|
||||
|
||||
56
src/suffix.c
56
src/suffix.c
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2007, 2009 Free Software Foundation, Inc.
|
||||
Copyright 2007, 2009, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff.
|
||||
|
||||
@@ -29,6 +29,7 @@ struct compression_suffix
|
||||
static struct compression_suffix compression_suffixes[] = {
|
||||
#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,33 +44,44 @@ 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 const char *
|
||||
find_compression_program (const char *name, const char *defprog)
|
||||
static struct compression_suffix const *
|
||||
find_compression_suffix (const char *name, size_t *ret_len)
|
||||
{
|
||||
char *suf = strrchr (name, '.');
|
||||
|
||||
if (suf)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
struct compression_suffix *p;
|
||||
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
for (i = 0; i < nsuffixes; i++)
|
||||
for (p = compression_suffixes; p->suffix; p++)
|
||||
{
|
||||
if (compression_suffixes[i].length == len
|
||||
&& memcmp (compression_suffixes[i].suffix, suf, len) == 0)
|
||||
return compression_suffixes[i].program;
|
||||
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)
|
||||
{
|
||||
struct compression_suffix const *p = find_compression_suffix (name, NULL);
|
||||
if (p)
|
||||
return p->program;
|
||||
return defprog;
|
||||
}
|
||||
|
||||
@@ -80,3 +92,23 @@ set_compression_program_by_suffix (const char *name, const char *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;
|
||||
}
|
||||
|
||||
|
||||
107
src/system.c
107
src/system.c
@@ -1,7 +1,6 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007,
|
||||
2008, 2010 Free Software Foundation, Inc.
|
||||
Copyright 2003-2008, 2010, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -14,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>
|
||||
|
||||
@@ -23,6 +21,20 @@
|
||||
#include <priv-set.h>
|
||||
#include <rmt.h>
|
||||
#include <signal.h>
|
||||
#include <wordsplit.h>
|
||||
|
||||
static _Noreturn void
|
||||
xexec (const char *cmd)
|
||||
{
|
||||
struct wordsplit ws;
|
||||
|
||||
ws.ws_env = (const char **) environ;
|
||||
if (wordsplit (cmd, &ws, (WRDSF_DEFFLAGS | WRDSF_ENV) & ~WRDSF_NOVAR))
|
||||
FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"),
|
||||
cmd, wordsplit_strerror (&ws)));
|
||||
execvp (ws.ws_wordv[0], ws.ws_wordv);
|
||||
exec_fatal (cmd);
|
||||
}
|
||||
|
||||
#if MSDOS
|
||||
|
||||
@@ -194,7 +206,7 @@ sys_spawn_shell (void)
|
||||
if (child == 0)
|
||||
{
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (shell, "-sh", "-i", (char *) 0);
|
||||
execlp (shell, "-sh", "-i", NULL);
|
||||
exec_fatal (shell);
|
||||
}
|
||||
else
|
||||
@@ -365,8 +377,7 @@ sys_child_open_for_compress (void)
|
||||
xdup2 (archive, STDOUT_FILENO);
|
||||
}
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option, NULL);
|
||||
exec_fatal (use_compress_program_option);
|
||||
xexec (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -383,9 +394,7 @@ sys_child_open_for_compress (void)
|
||||
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (child_pipe[PREAD]);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
(char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
xexec (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
@@ -455,6 +464,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)
|
||||
@@ -501,9 +546,7 @@ sys_child_open_for_uncompress (void)
|
||||
open_fatal (archive_name_array[0]);
|
||||
xdup2 (archive, STDIN_FILENO);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -520,9 +563,7 @@ sys_child_open_for_uncompress (void)
|
||||
xdup2 (child_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (child_pipe[PWRITE]);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
@@ -679,13 +720,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);
|
||||
@@ -703,15 +743,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;
|
||||
|
||||
priv_set_restore_linkdir ();
|
||||
execv ("/bin/sh", argv);
|
||||
|
||||
exec_fatal (file_name);
|
||||
xexec (to_command_option);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -753,10 +786,9 @@ 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);
|
||||
@@ -818,15 +850,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;
|
||||
|
||||
priv_set_restore_linkdir ();
|
||||
execv (argv[0], argv);
|
||||
|
||||
exec_fatal (info_script_option);
|
||||
xexec (info_script_option);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -835,7 +860,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 ();
|
||||
@@ -866,15 +890,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;
|
||||
|
||||
priv_set_restore_linkdir ();
|
||||
execv (argv[0], argv);
|
||||
|
||||
exec_fatal (script_name);
|
||||
xexec (script_name);
|
||||
}
|
||||
|
||||
#endif /* not MSDOS */
|
||||
|
||||
54
src/tar.h
54
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 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
|
||||
@@ -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,6 +327,9 @@ struct tar_stat_info
|
||||
size_t sparse_map_size; /* Size of the sparse map */
|
||||
struct sp_array *sparse_map;
|
||||
|
||||
size_t xattr_map_size; /* Size of the xattr map */
|
||||
struct xattr_array *xattr_map;
|
||||
|
||||
/* Extended headers */
|
||||
struct xheader xhdr;
|
||||
|
||||
@@ -337,6 +358,9 @@ struct tar_stat_info
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
Copyright 2006-2008, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -12,8 +12,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>
|
||||
@@ -71,7 +70,7 @@ struct transform
|
||||
|
||||
|
||||
|
||||
int transform_flags = XFORM_ALL;
|
||||
static int transform_flags = XFORM_ALL;
|
||||
static struct transform *transform_head, *transform_tail;
|
||||
|
||||
static struct transform *
|
||||
@@ -347,7 +346,7 @@ parse_transform_expr (const char *expr)
|
||||
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++;
|
||||
@@ -360,7 +359,7 @@ parse_transform_expr (const char *expr)
|
||||
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++;
|
||||
@@ -373,7 +372,7 @@ parse_transform_expr (const char *expr)
|
||||
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;
|
||||
@@ -628,3 +627,9 @@ transform_name (char **pinput, int type)
|
||||
{
|
||||
return transform_name_fp (pinput, type, NULL, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
transform_program_p (void)
|
||||
{
|
||||
return transform_head != NULL;
|
||||
}
|
||||
|
||||
60
src/unlink.c
60
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 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,7 +24,9 @@
|
||||
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 */
|
||||
@@ -39,7 +43,7 @@ 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 (void)
|
||||
@@ -68,16 +72,31 @@ 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 (unlinkat (chdir_fd, p->file_name, AT_REMOVEDIR) != 0)
|
||||
const char *fname;
|
||||
|
||||
if (p->dir_idx
|
||||
&& (p->file_name[0] == 0
|
||||
|| strcmp (p->file_name, ".") == 0))
|
||||
{
|
||||
fname = tar_dirname ();
|
||||
chdir_do (p->dir_idx - 1);
|
||||
}
|
||||
else
|
||||
fname = p->file_name;
|
||||
|
||||
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
@@ -95,7 +114,7 @@ flush_deferred_unlinks (bool force)
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
rmdir_error (p->file_name);
|
||||
rmdir_error (fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,10 +139,11 @@ flush_deferred_unlinks (bool force)
|
||||
}
|
||||
if (!dunlink_head)
|
||||
dunlink_tail = NULL;
|
||||
chdir_do (saved_chdir);
|
||||
}
|
||||
|
||||
void
|
||||
finish_deferred_unlinks ()
|
||||
finish_deferred_unlinks (void)
|
||||
{
|
||||
flush_deferred_unlinks (true);
|
||||
while (dunlink_avail)
|
||||
@@ -145,7 +165,9 @@ queue_deferred_unlink (const char *name, bool is_dir)
|
||||
|
||||
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;
|
||||
|
||||
|
||||
48
src/update.c
48
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 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
|
||||
@@ -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
|
||||
@@ -142,16 +145,8 @@ update_archive (void)
|
||||
{
|
||||
if (S_ISDIR (s.st_mode))
|
||||
{
|
||||
char *p, *dirp;
|
||||
DIR *stream;
|
||||
int fd = openat (chdir_fd, name->name,
|
||||
open_read_flags | O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
open_error (name->name);
|
||||
else if (! ((stream = fdopendir (fd))
|
||||
&& (dirp = streamsavedir (stream))))
|
||||
savedir_error (name->name);
|
||||
else
|
||||
char *p, *dirp = tar_savedir (name->name, 1);
|
||||
if (dirp)
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (name->name);
|
||||
|
||||
@@ -164,11 +159,6 @@ update_archive (void)
|
||||
|
||||
remname (name);
|
||||
}
|
||||
|
||||
if (stream
|
||||
? closedir (stream) != 0
|
||||
: 0 <= fd && close (fd) != 0)
|
||||
savedir_error (name->name);
|
||||
}
|
||||
else if (tar_timespec_cmp (get_stat_mtime (&s),
|
||||
current_stat_info.mtime)
|
||||
@@ -226,7 +216,7 @@ 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;
|
||||
|
||||
25
src/utf8.c
25
src/utf8.c
@@ -1,20 +1,21 @@
|
||||
/* Charset handling for GNU tar.
|
||||
|
||||
Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2004, 2006-2007, 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This 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 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,10 @@ static char const *const warning_args[] = {
|
||||
"unknown-cast",
|
||||
"unknown-keyword",
|
||||
"xdev",
|
||||
"decompress-program",
|
||||
"existing-file",
|
||||
"xattr-write",
|
||||
"record-size",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -64,7 +70,11 @@ 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
|
||||
};
|
||||
|
||||
ARGMATCH_VERIFY (warning_args, warning_types);
|
||||
|
||||
755
src/xattrs.c
Normal file
755
src/xattrs.c
Normal file
@@ -0,0 +1,755 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2014 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);
|
||||
}
|
||||
|
||||
/* get all xattrs from file given by FILE_NAME or FD (when non-zero). 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;
|
||||
|
||||
/* Archive all xattrs during creation, decide at extraction time
|
||||
* which ones are of interest/use for the target filesystem. */
|
||||
while (((fd == 0)
|
||||
? ((aret = lgetxattrat (parentfd, file_name, attr,
|
||||
val, asz)) == -1)
|
||||
: ((aret = fgetxattr (fd, attr, val, asz)) == -1))
|
||||
&& (errno == ERANGE))
|
||||
{
|
||||
val = x2nrealloc (val, &asz, 1);
|
||||
}
|
||||
|
||||
if (aret != -1)
|
||||
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 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 */
|
||||
614
src/xheader.c
614
src/xheader.c
@@ -1,21 +1,22 @@
|
||||
/* POSIX extended headers for tar.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software
|
||||
Copyright (C) 2003-2007, 2009-2010, 2012-2014 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
This 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>
|
||||
|
||||
@@ -86,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 */
|
||||
@@ -167,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);
|
||||
}
|
||||
}
|
||||
@@ -262,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;
|
||||
|
||||
@@ -335,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++;
|
||||
@@ -455,11 +452,129 @@ xheader_write_global (struct xheader *xhdr)
|
||||
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 */
|
||||
|
||||
@@ -473,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
|
||||
@@ -489,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;
|
||||
}
|
||||
|
||||
@@ -500,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;
|
||||
}
|
||||
@@ -511,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;
|
||||
}
|
||||
@@ -526,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;
|
||||
@@ -543,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)
|
||||
{
|
||||
@@ -618,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));
|
||||
}
|
||||
|
||||
@@ -691,10 +811,16 @@ xheader_store (char const *keyword, struct tar_stat_info *st,
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -721,15 +847,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
|
||||
{
|
||||
@@ -741,7 +923,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');
|
||||
@@ -849,14 +1031,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.). */
|
||||
@@ -899,140 +1079,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;
|
||||
}
|
||||
|
||||
@@ -1074,7 +1188,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
|
||||
@@ -1083,8 +1198,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;
|
||||
}
|
||||
|
||||
@@ -1197,7 +1313,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
|
||||
@@ -1206,8 +1323,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;
|
||||
}
|
||||
|
||||
@@ -1329,7 +1447,7 @@ sparse_map_decoder (struct tar_stat_info *st,
|
||||
st->sparse_map_avail = 0;
|
||||
while (1)
|
||||
{
|
||||
uintmax_t u;
|
||||
intmax_t u;
|
||||
char *delim;
|
||||
struct sp_array e;
|
||||
|
||||
@@ -1341,11 +1459,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;
|
||||
@@ -1354,7 +1477,7 @@ 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 (off_t));
|
||||
return;
|
||||
@@ -1469,6 +1592,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)
|
||||
@@ -1506,53 +1703,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 },
|
||||
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.
|
||||
@@ -1561,11 +1758,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 }
|
||||
};
|
||||
|
||||
@@ -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-2013 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,12 +42,20 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
## ------------ ##
|
||||
|
||||
TESTSUITE_AT = \
|
||||
T-cd.at\
|
||||
T-empty.at\
|
||||
T-null.at\
|
||||
T-rec.at\
|
||||
T-zfile.at\
|
||||
T-nonl.at\
|
||||
T-mult.at\
|
||||
T-nest.at\
|
||||
testsuite.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
append02.at\
|
||||
append03.at\
|
||||
append04.at\
|
||||
backup01.at\
|
||||
chtype.at\
|
||||
comprec.at\
|
||||
@@ -67,6 +71,16 @@ TESTSUITE_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\
|
||||
@@ -82,6 +96,10 @@ TESTSUITE_AT = \
|
||||
extrac13.at\
|
||||
extrac14.at\
|
||||
extrac15.at\
|
||||
extrac16.at\
|
||||
extrac17.at\
|
||||
extrac18.at\
|
||||
extrac19.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
gzip.at\
|
||||
@@ -93,8 +111,12 @@ TESTSUITE_AT = \
|
||||
incr04.at\
|
||||
incr05.at\
|
||||
incr06.at\
|
||||
incr07.at\
|
||||
incr08.at\
|
||||
incr09.at\
|
||||
indexfile.at\
|
||||
ignfail.at\
|
||||
iotty.at\
|
||||
label01.at\
|
||||
label02.at\
|
||||
label03.at\
|
||||
@@ -107,6 +129,8 @@ TESTSUITE_AT = \
|
||||
listed01.at\
|
||||
listed02.at\
|
||||
listed03.at\
|
||||
listed04.at\
|
||||
listed05.at\
|
||||
long01.at\
|
||||
longv7.at\
|
||||
lustar01.at\
|
||||
@@ -121,10 +145,22 @@ TESTSUITE_AT = \
|
||||
multiv07.at\
|
||||
multiv08.at\
|
||||
old.at\
|
||||
onetop01.at\
|
||||
onetop02.at\
|
||||
onetop03.at\
|
||||
onetop04.at\
|
||||
opcomp01.at\
|
||||
opcomp02.at\
|
||||
opcomp03.at\
|
||||
opcomp04.at\
|
||||
opcomp05.at\
|
||||
opcomp06.at\
|
||||
options.at\
|
||||
options02.at\
|
||||
owner.at\
|
||||
pipe.at\
|
||||
recurse.at\
|
||||
recurs02.at\
|
||||
rename01.at\
|
||||
rename02.at\
|
||||
rename03.at\
|
||||
@@ -133,6 +169,25 @@ TESTSUITE_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\
|
||||
@@ -142,11 +197,13 @@ TESTSUITE_AT = \
|
||||
sparse01.at\
|
||||
sparse02.at\
|
||||
sparse03.at\
|
||||
sparse04.at\
|
||||
sparsemv.at\
|
||||
sparsemvp.at\
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
time01.at\
|
||||
truncate.at\
|
||||
update.at\
|
||||
update01.at\
|
||||
@@ -154,6 +211,7 @@ TESTSUITE_AT = \
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
verify.at\
|
||||
version.at\
|
||||
xform-h.at\
|
||||
xform01.at\
|
||||
@@ -162,7 +220,18 @@ TESTSUITE_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\
|
||||
acls01.at\
|
||||
acls02.at\
|
||||
acls03.at\
|
||||
selnx01.at\
|
||||
selacl01.at\
|
||||
capabs_raw01.at
|
||||
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
|
||||
@@ -196,9 +265,20 @@ installcheck-local:
|
||||
|
||||
check_PROGRAMS = genfile
|
||||
|
||||
if TAR_COND_GRANTPT
|
||||
check_PROGRAMS += ttyemu
|
||||
endif
|
||||
|
||||
genfile_SOURCES = genfile.c argcv.c argcv.h
|
||||
|
||||
ttyemu_SOURCES = ttyemu.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../gnu -I$(top_srcdir)/gnu -I$(top_srcdir)/lib
|
||||
AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\"
|
||||
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 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])
|
||||
|
||||
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
|
||||
@@ -1,30 +1,30 @@
|
||||
# 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 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 +34,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 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 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 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,45 @@
|
||||
# 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 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-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 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
|
||||
52
tests/T-zfile.at
Normal file
52
tests/T-zfile.at
Normal file
@@ -0,0 +1,52 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014 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 empty file as an argument to -T.
|
||||
#
|
||||
# Reported by: Michal Žejdl <zejdl@suas.cz>
|
||||
# References: <http://lists.gnu.org/archive/html/bug-tar/2013-07/msg00009.html>
|
||||
|
||||
AT_SETUP([empty file])
|
||||
AT_KEYWORDS([files-from empty-file])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --length=0 --file empty
|
||||
genfile --file a
|
||||
genfile --file b
|
||||
AT_DATA([valid],[a
|
||||
b
|
||||
])
|
||||
|
||||
tar cf archive -T empty -T valid
|
||||
tar tf archive
|
||||
echo "=="
|
||||
tar cf archive -T valid -T empty
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[a
|
||||
b
|
||||
==
|
||||
a
|
||||
b
|
||||
],
|
||||
[],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
AT_CLEANUP
|
||||
55
tests/acls01.at
Normal file
55
tests/acls01.at
Normal file
@@ -0,0 +1,55 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2011, 2013-2014 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/>.
|
||||
#
|
||||
# Test description:
|
||||
#
|
||||
# This is basic test for acl support.
|
||||
|
||||
AT_SETUP([acls: basic functionality])
|
||||
AT_KEYWORDS([xattrs acls acls01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_XATTRS_UTILS_PREREQ
|
||||
AT_ACLS_PREREQ
|
||||
|
||||
mkdir dir
|
||||
genfile --file dir/file
|
||||
|
||||
MYNAME=$( id -un )
|
||||
|
||||
setfacl -m u:$MYNAME:--x dir/file
|
||||
setfacl -m u:$MYNAME:--x dir
|
||||
|
||||
getfattr -h -m. -d dir dir/file > before
|
||||
|
||||
tar --acls -cf archive.tar dir
|
||||
rm -rf dir
|
||||
|
||||
tar --acls -xf archive.tar
|
||||
|
||||
getfattr -h -m. -d dir dir/file > after
|
||||
|
||||
diff before after
|
||||
test "$?" = 0
|
||||
],
|
||||
[0],
|
||||
[])
|
||||
|
||||
AT_CLEANUP
|
||||
61
tests/acls02.at
Normal file
61
tests/acls02.at
Normal file
@@ -0,0 +1,61 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2011, 2013-2014 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/>.
|
||||
#
|
||||
# Test description:
|
||||
#
|
||||
# This is basic test for acl support.
|
||||
|
||||
AT_SETUP([acls: work with -C])
|
||||
AT_KEYWORDS([xattrs acls acls02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_XATTRS_UTILS_PREREQ
|
||||
AT_ACLS_PREREQ
|
||||
|
||||
mkdir dir
|
||||
mkdir dir/subdir
|
||||
genfile --file dir/subdir/file
|
||||
|
||||
MYNAME=$( id -un )
|
||||
|
||||
setfacl -m u:$MYNAME:--x dir/subdir
|
||||
setfacl -m u:$MYNAME:--x dir/subdir/file
|
||||
|
||||
cd dir
|
||||
getfattr -h -m. -d subdir subdir/file > ../before
|
||||
cd ..
|
||||
|
||||
tar --acls -cf archive.tar -C dir subdir
|
||||
rm -rf dir
|
||||
|
||||
mkdir dir
|
||||
tar --acls -xf archive.tar -C dir
|
||||
|
||||
cd dir
|
||||
getfattr -h -m. -d subdir subdir/file > ../after
|
||||
cd ..
|
||||
|
||||
diff before after
|
||||
test "$?" = 0
|
||||
],
|
||||
[0],
|
||||
[])
|
||||
|
||||
AT_CLEANUP
|
||||
131
tests/acls03.at
Normal file
131
tests/acls03.at
Normal file
@@ -0,0 +1,131 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013, 2014 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/>.
|
||||
#
|
||||
# Test description:
|
||||
#
|
||||
# Check the storing/restoring with/without default ACLs. When --acls is passed,
|
||||
# restored directory tree should always match archive contents (even when the
|
||||
# archive does not contain any ACLs).
|
||||
#
|
||||
# References:
|
||||
# http://www.mail-archive.com/bug-tar@gnu.org/msg04355.html
|
||||
|
||||
AT_SETUP([acls: default ACLs])
|
||||
AT_KEYWORDS([xattrs acls acls03])
|
||||
|
||||
m4_define([ACL_LISTDIR], [
|
||||
cd $1
|
||||
$1="$(find d1 | sort | xargs -n 1 getfacl)"
|
||||
cd ..
|
||||
])
|
||||
|
||||
m4_define([ACL_ASSERT], [
|
||||
echo "$$1" > $1.log
|
||||
echo "$$2" > $2.log
|
||||
if test ! "$$1" "$3" "$$2"; then
|
||||
echo "bad '$1' against '$2' output"
|
||||
fi
|
||||
])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_XATTRS_UTILS_PREREQ
|
||||
AT_ACLS_PREREQ
|
||||
AT_SORT_PREREQ
|
||||
|
||||
MYNAME=$( id -un )
|
||||
MYGROUP=$( id -gn )
|
||||
|
||||
# Prepare directory structure with default ACLs
|
||||
mkdir -p pure/d1/d2
|
||||
genfile --file pure/d1/f2a
|
||||
genfile --file pure/d1/f2b
|
||||
genfile --file pure/d1/d2/f3a
|
||||
genfile --file pure/d1/d2/f3b
|
||||
setfacl -m g:$MYGROUP:r-x pure/d1
|
||||
setfacl -d -m g:$MYGROUP:rwx pure/d1
|
||||
setfacl -d -m u:$MYNAME:rwx pure/d1
|
||||
# "*a" files have "some" additional ACLs
|
||||
setfacl -m u:$MYNAME:--- pure/d1/d2/f3a
|
||||
setfacl -m u:$MYNAME:--- pure/d1/f2a
|
||||
|
||||
# use default format (no acls stored)
|
||||
tar -cf noacl.tar -C pure d1
|
||||
|
||||
# use posix format, acls stored
|
||||
tar --acls -cf acl.tar -C pure d1
|
||||
|
||||
# Directory names are chosen based on "how the files were extracted from
|
||||
# archive". Equivalent no* tags are used also:
|
||||
# ^sacl_ — extracted archive has stored ACLs
|
||||
# _def_ — target directory (-C) has default ACLs
|
||||
# _optacl$ — extraction was done with --acls option
|
||||
|
||||
mkdir sacl_def_optacl
|
||||
mkdir sacl_def_optnoacl
|
||||
mkdir sacl_nodef_optacl
|
||||
mkdir sacl_nodef_optnoacl
|
||||
mkdir nosacl_def_optacl
|
||||
mkdir nosacl_def_optnoacl
|
||||
mkdir nosacl_nodef_optacl
|
||||
mkdir nosacl_nodef_optnoacl
|
||||
|
||||
setfacl -d -m u:$MYNAME:--- nosacl_def_optnoacl sacl_def_optnoacl sacl_def_optacl nosacl_def_optacl
|
||||
setfacl -d -m g:$MYGROUP:--- nosacl_def_optnoacl sacl_def_optnoacl sacl_def_optacl nosacl_def_optacl
|
||||
|
||||
tar -xf acl.tar -C sacl_nodef_optnoacl
|
||||
tar --acls -xf acl.tar -C sacl_nodef_optacl
|
||||
tar -xf acl.tar -C sacl_def_optnoacl
|
||||
tar --acls -xf acl.tar -C sacl_def_optacl
|
||||
tar -xf noacl.tar -C nosacl_def_optnoacl
|
||||
# _NO_ ACLs in output
|
||||
tar -xf noacl.tar -C nosacl_nodef_optnoacl
|
||||
tar -xf noacl.tar -C nosacl_nodef_optacl
|
||||
tar -cf noacl_repackaged.tar -C nosacl_nodef_optnoacl d1
|
||||
# _NO_ ACLs in output (even when default ACLs exist)
|
||||
tar --acls -xf noacl_repackaged.tar -C nosacl_def_optacl
|
||||
|
||||
ACL_LISTDIR(pure)
|
||||
|
||||
ACL_LISTDIR(sacl_def_optacl)
|
||||
ACL_LISTDIR(sacl_def_optnoacl)
|
||||
ACL_LISTDIR(sacl_nodef_optacl)
|
||||
ACL_LISTDIR(sacl_nodef_optnoacl)
|
||||
ACL_LISTDIR(nosacl_def_optacl)
|
||||
ACL_LISTDIR(nosacl_def_optnoacl)
|
||||
ACL_LISTDIR(nosacl_nodef_optacl)
|
||||
ACL_LISTDIR(nosacl_nodef_optnoacl)
|
||||
|
||||
ACL_ASSERT(pure, sacl_def_optacl, =)
|
||||
|
||||
ACL_ASSERT(sacl_def_optacl, sacl_nodef_optacl, =)
|
||||
ACL_ASSERT(sacl_def_optnoacl, nosacl_def_optnoacl, =)
|
||||
ACL_ASSERT(sacl_nodef_optnoacl, nosacl_nodef_optnoacl, =)
|
||||
ACL_ASSERT(nosacl_def_optacl, nosacl_nodef_optacl, =)
|
||||
ACL_ASSERT(nosacl_def_optacl, nosacl_nodef_optnoacl, =)
|
||||
|
||||
ACL_ASSERT(sacl_def_optacl, sacl_def_optnoacl, !=)
|
||||
ACL_ASSERT(sacl_def_optacl, nosacl_def_optnoacl, !=)
|
||||
ACL_ASSERT(nosacl_def_optnoacl, nosacl_nodef_optnoacl, !=)
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
[])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,22 +1,22 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2004, 2006-2007, 2013-2014 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([append])
|
||||
AT_KEYWORDS([append append00])
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2005-2007, 2013-2014 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/>.
|
||||
|
||||
# When decoding a header tar was assigning 0 to oldgnu_header.isextended,
|
||||
# which destroyed name prefix. When updating archive, modified prefix
|
||||
@@ -29,7 +29,7 @@
|
||||
AT_SETUP([appending files with long names])
|
||||
AT_KEYWORDS([append append01])
|
||||
|
||||
m4_define([PREFIX],[This_is_a_very_long_file_name_prefix_that_is_designed_to_cause_problems_with_appending_long_file_names_that_run_into_a_limit_of_the_ustar_tarX])
|
||||
m4_pushdef([PREFIX],[This_is_a_very_long_file_name_prefix_that_is_designed_to_cause_problems_with_appending_long_file_names_that_run_into_a_limit_of_the_ustar_tarX])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir PREFIX
|
||||
@@ -44,4 +44,5 @@ PREFIX/file2
|
||||
],
|
||||
[],[],[],[oldgnu, ustar, posix, gnu])
|
||||
|
||||
m4_popdef([PREFIX])
|
||||
AT_CLEANUP
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2007, 2009, 2013-2014 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/>.
|
||||
|
||||
# Using tar 1.15.x the following equivalent command sets:
|
||||
#
|
||||
|
||||
45
tests/append03.at
Normal file
45
tests/append03.at
Normal file
@@ -0,0 +1,45 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2010, 2013-2014 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([append with name transformation])
|
||||
AT_KEYWORDS([append append03])
|
||||
|
||||
# Description: Make sure filenames are transformed during append.
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --file file.1
|
||||
genfile --file file.2
|
||||
|
||||
tar -c -f archive --transform 's/file/plik/' file.*
|
||||
echo Appending
|
||||
tar -r -f archive --transform 's/file/plik/' -v --show-transformed-names file.1
|
||||
echo Testing
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[Appending
|
||||
plik.1
|
||||
Testing
|
||||
plik.1
|
||||
plik.2
|
||||
plik.1
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
60
tests/append04.at
Normal file
60
tests/append04.at
Normal file
@@ -0,0 +1,60 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2014 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/>.
|
||||
|
||||
# When called with --append and --verify options, tar would rewrite the
|
||||
# archive instead of appending to it.
|
||||
#
|
||||
# Last-Affected-Version: 1.26
|
||||
# Reported-by: Jivko Angelov <jivko@siteground.com>
|
||||
# References: <51D6983C.3060404@siteground.com>,
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2013-07/msg00003.html
|
||||
|
||||
AT_SETUP([append with verify])
|
||||
AT_KEYWORDS([append append04 verify append-verify])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
# Create two empty files:
|
||||
touch file1 file2
|
||||
|
||||
# Create an archive:
|
||||
tar cpfW archive.tar file1 file2
|
||||
|
||||
# Verify created archive by listing its content:
|
||||
tar -tf archive.tar
|
||||
echo ==
|
||||
# Create another empty file:
|
||||
touch file3
|
||||
|
||||
# Append it to the already created archive:
|
||||
tar rpfW archive.tar file3
|
||||
|
||||
# Verify content of the new archive:
|
||||
tar -tf archive.tar
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
file2
|
||||
==
|
||||
file1
|
||||
file2
|
||||
file3
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,6 +1,21 @@
|
||||
# @configure_input@ -*- shell-script -*-
|
||||
# Configurable variable values for tar test suite.
|
||||
# Copyright (C) 2004, 2006 Free Software Foundation, Inc.
|
||||
# Copyright 2004, 2006, 2013-2014 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/>.
|
||||
|
||||
PATH=@abs_builddir@:@abs_top_builddir@/src:@abs_top_srcdir@/build-aux:$top_srcdir:$srcdir:$PATH
|
||||
|
||||
@@ -34,3 +49,11 @@ decho() {
|
||||
echo $*
|
||||
echo >&2 $*
|
||||
}
|
||||
|
||||
mkexcltest() {
|
||||
mkdir $1 $1/subdir
|
||||
genfile --file=$1/top-level-file
|
||||
genfile --file=$1/subdir/excludeme
|
||||
genfile --file=$1/subdir/subdir-file
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
# Copyright 2009-2010, 2013-2014 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/>.
|
||||
|
||||
# Description:
|
||||
# When extracting, tar (<1.22) sometimes renamed a backup back to the
|
||||
@@ -34,6 +34,7 @@ AT_SETUP([extracting existing dir with --backup])
|
||||
AT_KEYWORDS([extract backup backup01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
unset VERSION_CONTROL
|
||||
mkdir dir1 dir2
|
||||
echo bla > dir1/file1
|
||||
tar cf test.tar dir1 dir2
|
||||
@@ -42,7 +43,7 @@ tar xfv test.tar --backup --warning=no-timestamp
|
||||
[0],
|
||||
[dir1/
|
||||
dir1/file1
|
||||
Renaming `dir1/file1' to `dir1/file1~'
|
||||
Renaming 'dir1/file1' to 'dir1/file1~'
|
||||
dir2/
|
||||
])
|
||||
|
||||
|
||||
53
tests/capabs_raw01.at
Normal file
53
tests/capabs_raw01.at
Normal file
@@ -0,0 +1,53 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2012-2014 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/>.
|
||||
#
|
||||
# Test description: Test if file capabilities are archived/restored correctly
|
||||
# using just the default xattr support (capabilities are stored/restored in
|
||||
# binary format -> system dependant).
|
||||
|
||||
AT_SETUP([capabilities: binary store/restore])
|
||||
AT_KEYWORDS([xattrs capabilities capabs_raw01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_PRIVILEGED_PREREQ
|
||||
AT_XATTRS_PREREQ
|
||||
AT_CAPABILITIES_UTILS_PREREQ
|
||||
|
||||
mkdir dir
|
||||
genfile --file dir/file
|
||||
|
||||
setcap "= cap_chown=ei" dir/file
|
||||
|
||||
# archive whole directory including binary xattrs
|
||||
tar --xattrs -cf archive.tar dir
|
||||
|
||||
# clear the directory
|
||||
rm -rf dir
|
||||
|
||||
# restore _all_ xattrs (not just the user.* domain)
|
||||
tar --xattrs --xattrs-include='*' -xf archive.tar
|
||||
|
||||
getcap dir/file
|
||||
],
|
||||
[0],
|
||||
[dir/file = cap_chown+ei
|
||||
])
|
||||
|
||||
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