Compare commits
263 Commits
alpha_1_15
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f572ca0cfb | ||
|
|
29236a68fa | ||
|
|
a4b1564d4a | ||
|
|
94d0385a57 | ||
|
|
603c1d60a6 | ||
|
|
29e9004b69 | ||
|
|
8da152d2b3 | ||
|
|
00746182f3 | ||
|
|
6c8815909d | ||
|
|
fde336b21a | ||
|
|
394b12d950 | ||
|
|
372638ae7a | ||
|
|
c455373e5b | ||
|
|
f2541c66cd | ||
|
|
7e6d54d0c0 | ||
|
|
876e554157 | ||
|
|
1118d24fd3 | ||
|
|
dc6f7ebf20 | ||
|
|
1102eeef1f | ||
|
|
e8a4c35a73 | ||
|
|
e359fad641 | ||
|
|
f5504a3bae | ||
|
|
341be8f405 | ||
|
|
4f2a22f306 | ||
|
|
a76ab340dd | ||
|
|
3ad3ca8734 | ||
|
|
82b2829e10 | ||
|
|
f852428d5f | ||
|
|
86e91a5bfc | ||
|
|
ec5743a628 | ||
|
|
bf7f4fdc1e | ||
|
|
98b9522499 | ||
|
|
6398dbe1a5 | ||
|
|
37724f5e20 | ||
|
|
c8c351684c | ||
|
|
01b6fb98bf | ||
|
|
f1309bffbf | ||
|
|
c732eb584e | ||
|
|
0680ad4d42 | ||
|
|
1942370acd | ||
|
|
94de7c4c77 | ||
|
|
05805868f2 | ||
|
|
57aa98047e | ||
|
|
7573967406 | ||
|
|
ab8711413c | ||
|
|
9fd9a0913d | ||
|
|
f4e4adea80 | ||
|
|
7110641821 | ||
|
|
fce454b5ca | ||
|
|
8ad985ea6c | ||
|
|
37edfd9e8f | ||
|
|
016f7c87a7 | ||
|
|
52b8bea074 | ||
|
|
5addfdcb03 | ||
|
|
e707b47aba | ||
|
|
76dc519f9f | ||
|
|
2a00376816 | ||
|
|
9766528b07 | ||
|
|
f26a90783b | ||
|
|
36fe16aaf5 | ||
|
|
89f1667fdb | ||
|
|
f2d65dda39 | ||
|
|
8370746251 | ||
|
|
2614af6d3c | ||
|
|
614def3113 | ||
|
|
b6365e9b03 | ||
|
|
bf789e3642 | ||
|
|
1421ee630d | ||
|
|
9869d0ae17 | ||
|
|
edc0b12c5e | ||
|
|
808cafa454 | ||
|
|
d1dedae402 | ||
|
|
de754902da | ||
|
|
bc7f4ad027 | ||
|
|
55abc110f5 | ||
|
|
4d753fced1 | ||
|
|
85a4e0fdeb | ||
|
|
583415c2c1 | ||
|
|
6488588c5f | ||
|
|
ac40b1e6f6 | ||
|
|
4bf5f6dca4 | ||
|
|
ecaff7cbba | ||
|
|
ea9e2d8d8e | ||
|
|
39e5d9182c | ||
|
|
c7aa519f09 | ||
|
|
bf5ba3dbef | ||
|
|
ea368b6d1b | ||
|
|
d0201294c0 | ||
|
|
c5b15c4ac1 | ||
|
|
4b3dd17c00 | ||
|
|
d339cc38af | ||
|
|
796a69787e | ||
|
|
4c54e234c1 | ||
|
|
c027e03924 | ||
|
|
6d615f12d4 | ||
|
|
8f970d2c1e | ||
|
|
d04af8f714 | ||
|
|
e2ecb82711 | ||
|
|
8e2e731733 | ||
|
|
19a63e523d | ||
|
|
5679d3020e | ||
|
|
1001c1b326 | ||
|
|
090d1d36ae | ||
|
|
2e1f904f2c | ||
|
|
6a0b5421b9 | ||
|
|
9c764b14a9 | ||
|
|
ae67839879 | ||
|
|
9588a106a7 | ||
|
|
b3627f3f07 | ||
|
|
ca7df3fe6b | ||
|
|
ab19642053 | ||
|
|
a71b154289 | ||
|
|
ceaef10443 | ||
|
|
5da6733724 | ||
|
|
8d6c177ecb | ||
|
|
1ecd6672e1 | ||
|
|
ca2f855c90 | ||
|
|
693134a4e7 | ||
|
|
90cec95580 | ||
|
|
b6fcb4ba8f | ||
|
|
6d1e9ab67e | ||
|
|
300210aa15 | ||
|
|
532b2dd31f | ||
|
|
3358f5fcc3 | ||
|
|
51e3f3f1ca | ||
|
|
caf6b29f1e | ||
|
|
12ae9f6912 | ||
|
|
64041696c9 | ||
|
|
8ee09b9939 | ||
|
|
72f60f9e5f | ||
|
|
378818cb3e | ||
|
|
c980a06329 | ||
|
|
4c7a2b10b8 | ||
|
|
8f3ed604b9 | ||
|
|
b886724818 | ||
|
|
f143fa5d64 | ||
|
|
1e3568d947 | ||
|
|
b229a86dd7 | ||
|
|
05b250d4a4 | ||
|
|
42d180b24e | ||
|
|
8c10111c66 | ||
|
|
15a55db341 | ||
|
|
e721e74259 | ||
|
|
1bea3b4b25 | ||
|
|
4ef056729e | ||
|
|
37986cdff9 | ||
|
|
5fe07ac97d | ||
|
|
a35935e973 | ||
|
|
e832cab432 | ||
|
|
578f46309f | ||
|
|
4396675861 | ||
|
|
a3dd97d9be | ||
|
|
13adf3f762 | ||
|
|
f1b1e9a476 | ||
|
|
fc4502c17e | ||
|
|
0abf3a5ac9 | ||
|
|
19b36aaf60 | ||
|
|
9b44f8efed | ||
|
|
97bfe578ed | ||
|
|
fb88325f56 | ||
|
|
a1b2406646 | ||
|
|
5e14ef32c0 | ||
|
|
f9bd340c1b | ||
|
|
46defea70e | ||
|
|
5daab19c27 | ||
|
|
7214086d3d | ||
|
|
93560dd669 | ||
|
|
c1f55f1c37 | ||
|
|
2d2e1d411e | ||
|
|
5591fa407a | ||
|
|
e2dbba2f07 | ||
|
|
018de58373 | ||
|
|
17111bef8f | ||
|
|
3a9f2ea587 | ||
|
|
02c7b862a3 | ||
|
|
9154c0c43b | ||
|
|
5108a3dc41 | ||
|
|
c52e5fc4e8 | ||
|
|
0fc3177ed2 | ||
|
|
6be1349236 | ||
|
|
a2625311c8 | ||
|
|
6e2760f7d7 | ||
|
|
8b2f4ad670 | ||
|
|
d4c0836ec2 | ||
|
|
40afe4d362 | ||
|
|
435edb824e | ||
|
|
9d2e8df195 | ||
|
|
aa7476a68e | ||
|
|
16c48ef8d0 | ||
|
|
0da8aac59f | ||
|
|
bb6f707781 | ||
|
|
7cb01d37bb | ||
|
|
d79bbe0fd1 | ||
|
|
f984c43b82 | ||
|
|
d75890c1b8 | ||
|
|
b3b4347821 | ||
|
|
39080c7628 | ||
|
|
c58063c17a | ||
|
|
ae7bd36423 | ||
|
|
973b611290 | ||
|
|
29fb7356df | ||
|
|
bbee515590 | ||
|
|
c8aa01c80c | ||
|
|
43ba23114f | ||
|
|
7bfcbd6a27 | ||
|
|
c5fd5f9e8d | ||
|
|
a23a95b4a0 | ||
|
|
19498c9172 | ||
|
|
edff149522 | ||
|
|
f20e08dd45 | ||
|
|
e6d15fc7af | ||
|
|
c96ba08e06 | ||
|
|
6f89b1fce5 | ||
|
|
93f8f6780a | ||
|
|
75f37f4cef | ||
|
|
3947e63c25 | ||
|
|
8b471d55ff | ||
|
|
c2c2df6c93 | ||
|
|
cf857388c1 | ||
|
|
9dfad74683 | ||
|
|
57267f7ed9 | ||
|
|
476abe556b | ||
|
|
fe72c79ad8 | ||
|
|
8fea578b22 | ||
|
|
a46704b1bf | ||
|
|
6f8cbc5ca8 | ||
|
|
c03131aba9 | ||
|
|
c9195c75be | ||
|
|
5632d195f5 | ||
|
|
ef90e05363 | ||
|
|
939d63b92d | ||
|
|
0ff13351f0 | ||
|
|
c57418b462 | ||
|
|
3c7dd57a17 | ||
|
|
0b3fe146dd | ||
|
|
90088ff00d | ||
|
|
a183d6f7f5 | ||
|
|
4883aab47d | ||
|
|
30873dbd97 | ||
|
|
74849d8119 | ||
|
|
3962eb6a3e | ||
|
|
c99076e925 | ||
|
|
6315d1700b | ||
|
|
520104f5f8 | ||
|
|
34e5f66589 | ||
|
|
d2b3114a3b | ||
|
|
2b27e8de1f | ||
|
|
a85cfd69e3 | ||
|
|
4b951034f3 | ||
|
|
1524831224 | ||
|
|
ee6f14194d | ||
|
|
ac7f4e853d | ||
|
|
47dd75e87b | ||
|
|
6054b5e9d5 | ||
|
|
edd6df370d | ||
|
|
fd89d5a3cd | ||
|
|
71f2e412ae | ||
|
|
67877f7de2 | ||
|
|
c9e7465642 | ||
|
|
a0b4431f26 | ||
|
|
192ac7136a | ||
|
|
c2775aedf1 | ||
|
|
f1fe157dfe |
643
ChangeLog
643
ChangeLog
@@ -1,3 +1,634 @@
|
||||
2006-10-21 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* NEWS, configure.ac: Version 1.16
|
||||
* Makefile.am (distclean-local): New rule
|
||||
|
||||
2006-10-17 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/tar.c: Fix help output formatting. Thanks Benno
|
||||
Schulenberg.
|
||||
|
||||
2006-10-16 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* Makefile.am (dist-hook): Create a cpio archive.
|
||||
* NEWS: Update
|
||||
|
||||
2006-10-14 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi (Synopsis): Document tar exit codes.
|
||||
* src/create.c (dump_regular_file,dump_file0): Set exit_status to
|
||||
TAREXIT_DIFFERS if the file being dumped was truncated or
|
||||
otherwise changed.
|
||||
* src/tar.c: Do not attempt to close stderr after call to
|
||||
close_stdout.
|
||||
* tests/grow.at: New test case
|
||||
* tests/Makefile.am: New test grow.at
|
||||
* tests/testsuite.at: Likewise
|
||||
* tests/truncate.at (AT_KEYWORDS): Keyword `filechange'
|
||||
Test tar exit status.
|
||||
|
||||
* src/buffer.c (_open_archive): Make sure stdlis is set to stderr
|
||||
when we are writing archive to stdout (unless --index-file is
|
||||
used). Bug introduced on 2006-07-06.
|
||||
* tests/Makefile.am: New test verbose.at
|
||||
* tests/testsuite.at: Likewise
|
||||
* tests/indexfile.at (AT_KEYWORDS): Add stdout keyword
|
||||
* tests/verbose.at: New test case
|
||||
|
||||
2006-10-02 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* THANKS: Add Joerg Weilbier
|
||||
* src/buffer.c (new_volume): Initialize current_block
|
||||
* src/xheader.c (xheader_string_end): Fix diagnostic message.
|
||||
* tests/multiv05.at: New testcase.
|
||||
* tests/Makefile.am, tests/testsuite.at: Add multiv05.at
|
||||
|
||||
2006-09-27 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* bootstrap: Use ${package} instead of hardcoding package name
|
||||
* doc/tar.texi: Minor fix
|
||||
* src/tar.c (doc0, doc1, initialize_argp_doc): Removed. Rely on
|
||||
the new argp method instead.
|
||||
|
||||
2006-09-12 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* README: Fix a typo
|
||||
|
||||
2006-09-08 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Adjust to latest gnulib.
|
||||
* lib/.cvsignore: Add at-func.c, configmake.h, fchmodat.c,
|
||||
fcntl.h, fcntl_.h, inttypes_.h, lstat.c, lstat.h.
|
||||
* tests/testsuite.at (AT_TAR_MKHIER): Use install-sh -d
|
||||
rather than the no-longer-included mkinstalldirs.
|
||||
|
||||
2006-09-08 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/incremen.c (try_purge_directory): Initialize struct st. Fix
|
||||
condition for selecting candidates for removal.
|
||||
* README-alpha: List texinfo among build prerequisites for the CVS
|
||||
version.
|
||||
|
||||
* bootstrap (intl_files_to_remove): Do not remove m4/inttypes-h.m4
|
||||
and m4/inttypes-pri.m4
|
||||
|
||||
2006-08-11 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* bootstrap: Set XGETTEXT_OPTIONS to flag our printf-format functions,
|
||||
so that translators are warned about strings that are formats but
|
||||
don't look like formats. This might help prevent core dumps.
|
||||
* configure.ac (AM_GNU_GETTEXT): Upgrade to need-formatstring-macros.
|
||||
Suggested by Eric Blake to avoid problems like
|
||||
<http://lists.gnu.org/archive/html/bug-coreutils/2006-07/msg00087.html>.
|
||||
(AM_GNU_GETTEXT_VERSION): Upgrade from 0.12.1 to 0.15. The gettext
|
||||
manual says we should use the version number normally expected of
|
||||
maintainers, neither more nor less.
|
||||
|
||||
* bootstrap (get_translations):
|
||||
Don't exclude ky.po; it is working again.
|
||||
|
||||
2006-08-09 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* bootstrap (get_translations):
|
||||
Don't exclude ja.po; it is working again.
|
||||
Don't remove all old .po files if we're merely updating one.
|
||||
* po/.cvsignore: Add Makevars.
|
||||
|
||||
2006-08-07 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* src/tar.c: Work around limitation imposed by gettext 0.15
|
||||
by concatenating strings with "\v" after translation.
|
||||
(doc): Remove, splitting into:
|
||||
(doc0, doc1): New constants.
|
||||
(argp): Don't use doc; just initialize to NULL.
|
||||
(initialize_argp_doc): New function.
|
||||
(decode_options): Use it.
|
||||
|
||||
* bootstrap: Redo po file retrieval to match Bison's method,
|
||||
since the translation project changed its index format.
|
||||
Don't use --assume-autoconf; it's now replaced
|
||||
by looking in configure.ac.
|
||||
(m4/codeset.m4, m4/intdiv.m4, m4/inttypes-pri.m4, m4/isc-posix.m4):
|
||||
(m4/lcmessage.m4, m4/onceonly_2_57.m4, m4/gettext.m4, m4/glibc21.m4):
|
||||
(m4/inttypes_h.m4, m4/lib-ld.m4, m4/lib-prefix.m4, m4/po.m4):
|
||||
(m4/stdint_h.m4, m4/uintmax_t.m4, m4/ulonglong.m4):
|
||||
Don't rename to ..._gl.m4, as this is no longer needed.
|
||||
(m4/geteext.m4): Patch to remove the need for intl/*.
|
||||
Use autopoint manually, then remove the intl files,
|
||||
then undo changes to gnulib files that autoreconf made,
|
||||
and then run aclocal/autoconf/autoheader/automake.
|
||||
This makes our bootstrap procedure closer to Bison's.
|
||||
(po/Makevars): Generate automatically.
|
||||
* configure.ac (AC_PREREQ): Update from 2.59 to 2.60.
|
||||
(gl_AC_TYPE_INTMAX_T, jm_AC_TYPE_UINTMAX_T): Remove.
|
||||
* gnulib.modules: Add inttypes, stdint.
|
||||
* lib/.cvsignore: Add close-stream.c, close-stream.h,
|
||||
stdint.h, stdint_.h.
|
||||
* po/Makefile: Remove; now automatically generated.
|
||||
|
||||
* src/incremen.c (read_incr_db_01): Check input strings more
|
||||
carefully. Do not pass arbitrary char values to isspace, as
|
||||
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.
|
||||
(read_num): Use read_unsigned_num. New arg MAX_VAL;
|
||||
all callers changed.
|
||||
(read_incr_db_2): Use these new functions.
|
||||
Use a consistent diagnostic for unexpected EOF.
|
||||
(read_directory_file): Do not assign arbitrary uintmax_t value
|
||||
to int.
|
||||
(read_timespec, write_directory_file_entry, write_directory_file):
|
||||
Handle negative time_t values correctly. We don't bother to do
|
||||
this with pre-2 formats, since presumably the time stamps were
|
||||
output incorrectly.
|
||||
|
||||
* src/tar.c (doc): Don't use \v in an argument to gettext;
|
||||
gettext 0.15 rejects this.
|
||||
|
||||
2006-07-24 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/tar.c (decode_options): Do not require -L with -M -Hpax.
|
||||
It could be needed in future, but currently it is not.
|
||||
* src/create.c (to_chars_subst): Update comment regarding OLDGNU
|
||||
vs. GNU format differences.
|
||||
(mode_to_chars): Treat OLDGNU_FORMAT same as GNU_FORMAT. Fixes bug
|
||||
reported by TAMUKI Shoichi <tamuki@linet.gr.jp>, which caused
|
||||
equivalent `tar cf ...' and `tar rf ...' commands to produce
|
||||
different archives.
|
||||
|
||||
* tests/append02.at: New test case
|
||||
* tests/Makefile.am, tests/testsuite.at: Add append02.at
|
||||
|
||||
2006-07-20 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* bootstrap: Adjust to today's change to gnulib-tool by invoking
|
||||
it with --assume-autoconf='latest-stable'.
|
||||
|
||||
2006-07-16 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Adjust to recent gnulib changes.
|
||||
* lib/.cvsignore: Remove atexit.c, exit.c, getndelim2.c, getndelim2.h,
|
||||
pathmax.h, paxconvert.c, paxerror.h, xstrdup.c.
|
||||
Add inttypes.h, mktime.c, wcwidth.h, xstrndup.c, xstrndup.h.
|
||||
* src/create.c (start_header): Adjust to API change to mode_adjust.
|
||||
|
||||
2006-07-09 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* THANKS: Add Ralf Wildenhues
|
||||
* NEWS: Update
|
||||
|
||||
2006-07-09 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
|
||||
* doc/dumpdir.texi, doc/snapshot.texi, doc/sparse.texi,
|
||||
doc/tar.texi: Fix some typos.
|
||||
|
||||
2006-07-06 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
tar --index-file=FILE --file=- sent the archive to FILE, and
|
||||
the listing to stderr. Bug reported by Marcin Gryszkalis
|
||||
<mg@fork.pl>
|
||||
|
||||
* src/buffer.c (_open_archive): Remove stdlis initialization
|
||||
* src/tar.c (decode_options): Initialize stdlis
|
||||
* tests/indexfile.at: New test case
|
||||
* tests/testsuite.at: Include indexfile.at
|
||||
* tests/Makefile.am (TESTSUITE_AT): Add indexfile.at
|
||||
|
||||
2006-07-05 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/Makefile.am (manual): Fix TEXINPUTS
|
||||
* doc/rendition.texi (FIXME): Do not use deprecated @quote-args.
|
||||
Do not use @allow-recursion. In its current form the macro is not
|
||||
recursive.
|
||||
|
||||
2006-07-03 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* bootstrap (update_po): Fix single translation update
|
||||
|
||||
2006-07-03 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* configure.ac (AC_CHECK_FUNCS): Check for getdtablesize
|
||||
* src/common.h (closeopen): New function
|
||||
* src/misc.c (chdir_arg): Use x2nrealloc to reallocate wd.
|
||||
(get_max_open_files,closeopen): New functions
|
||||
(chdir_do): Do not use save_cwd if it was already used more than
|
||||
max_open_files-4 times to avoid running off the file
|
||||
descriptors.
|
||||
* src/tar.c (main): Call closeopen
|
||||
* doc/tar.texi: Update --directory description
|
||||
* NEWS: Update
|
||||
|
||||
2006-06-26 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi: Update. Add cross-references.
|
||||
* doc/sparse.texi: Add cross-references.
|
||||
|
||||
2006-06-25 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* scripts/xsparse.c: A sample utility to expand sparse files
|
||||
extracted by third-party tars. It is not meant to be installed nor
|
||||
to be included in the distribution. It is here, so that it can be
|
||||
obtained either from CVS or from the tar web site.
|
||||
* doc/Makefile.am (tar_TEXINFOS): Sorted
|
||||
* doc/tar.texi (Other Tars): New node describing how to extract
|
||||
GNU-specific member formats using third-party tars.
|
||||
* src/common.h (sparse_file_p): Remove
|
||||
* src/sparse.c: Likewise
|
||||
* src/create.c: Use ST_IS_SPARSE instead of sparse_file_p (update
|
||||
paxutils first)
|
||||
* src/tar.c: --sparse-version turns on --sparse
|
||||
|
||||
2006-06-24 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/buffer.c (print_total_stats): Add default case.
|
||||
* src/common.h (name_init): New prototype.
|
||||
(xheader_string_end): Return bool.
|
||||
* src/extract.c (extract_volhdr): Add missing return
|
||||
* src/incremen.c: Remove not used variables
|
||||
* src/sparse.c (pax_dump_header_0): Return false if
|
||||
xheader_string_end fails (for 0.1 formats).
|
||||
(pax_dump_header): Return meaningful value
|
||||
* src/transform.c (segm_count): Change type to size_t
|
||||
* src/xheader.c (xhdr_tab.decoder): pass keyword as a second
|
||||
argument. All callers changed.
|
||||
(decode_record): Check for numeric overflow
|
||||
(xheader_string_end): Return boolean value. Check for possible
|
||||
numeric overflow
|
||||
|
||||
2006-06-23 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/sparse.texi: New file
|
||||
* doc/Makefile.am (tar_TEXINFOS): Add sparse.texi
|
||||
* doc/intern.texi (Sparse Formats): New node
|
||||
* doc/tar.texi: Update master menu
|
||||
|
||||
* src/common.h (tar_sparse_major,tar_sparse_minor): New globals.
|
||||
* src/sparse.c: Implement sparse format versioning. Implement new
|
||||
version (1.0) of PAX sparse format.
|
||||
(pax_sparse_member_p): Fix condition
|
||||
(pax_dump_header): A dispatcher function
|
||||
(pax_dump_header_0,pax_dump_header_1): New functions.
|
||||
(pax_optab): Update
|
||||
(oldgnu_dump_header): Minor fix: make sure
|
||||
sparse_header.isextended is set before calling
|
||||
set_next_block_after
|
||||
* src/tar.c: New option --sparse-version
|
||||
* src/tar.h (struct tar_stat_info.sparse_major,sparse_minor): New
|
||||
members.
|
||||
* src/xheader.c: Implement new keywords: GNU.sparse.name,
|
||||
GNU.sparse.major, GNU.sparse.minor, GNU.sparse.realsize
|
||||
|
||||
* tests/spmpv00.at, tests/spmvp01.at, tests/spmvp10.at: New
|
||||
testcases.
|
||||
|
||||
* tests/Makefile.am: Add spmvp00.at, spmpv01.at, spmpv10.at
|
||||
* tests/shortrec.at: Explicitely give `-f -' to the tar invocation
|
||||
* tests/sparsemvp.at: Rewritten as an include file.
|
||||
(TAR_MVP_TEST): New macro
|
||||
* tests/testsuite.at: Include sparsemvp.at, spmvp00.at,
|
||||
spmvp01.at, spmvp10.at
|
||||
|
||||
2006-06-21 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi (Overriding File Metadata): New node
|
||||
Document --mtime option.
|
||||
* src/common.h (set_mtime_option,mtime_option): New globals
|
||||
* src/create.c (start_header): Override mtime if requested
|
||||
* src/tar.c: Implement new option, --mtime, allowing to set
|
||||
modification times for all archive members during creation.
|
||||
(struct tar_args): textual_date_option replaced with a linked list
|
||||
textual_date. All references updated.
|
||||
(get_date_or_file,report_textual_dates): New functions.
|
||||
* configure.ac: Raise version number to 1.15.92
|
||||
* NEWS: Update
|
||||
|
||||
2006-06-20 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/common.h (struct name.explicit): Remove
|
||||
Use variable names in all declarations
|
||||
(name_scan): Remove second argument
|
||||
* 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
|
||||
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
|
||||
* src/names.c (name_next_elt): Call register_individual_file
|
||||
(namelist_match): Remove third argument
|
||||
(name_match): Change return type to bool
|
||||
(name_scan): Remove second argument
|
||||
* src/sparse.c (pax_dump_header): Store original sparse file name
|
||||
in GNU.sparse.name variable. The name field in the ustar header
|
||||
now contains generated name (%d/GNUSparseFile.%p/%f), so that
|
||||
non-pax-aware tars won't extract the file under the original
|
||||
filename.
|
||||
* src/xheader.c (GNU.sparse.name): New variable for storing sparse
|
||||
file name.
|
||||
|
||||
2006-06-13 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/Makefile.am (check-options): Expand macros before grepping
|
||||
in $(info_TEXINFOS)
|
||||
* doc/rendition.texi (FIXME) [!PROOF_FOOTNOTED]: Enclose in a
|
||||
cartouche
|
||||
* doc/tar.texi: Define op as codeindex. Use special macros to
|
||||
populate it
|
||||
Consequently prefer @dfn{long options} over @dfn{mnemonic
|
||||
options}.
|
||||
Document --unquote, --no-unquote
|
||||
(Short Option Summary): Build a table of cross-references to the
|
||||
corresponding long options.
|
||||
(Using Multiple Tapes,Multi-Volume Archives): Rewritten
|
||||
|
||||
* doc/value.texi (xopindex,opsummary): New macros
|
||||
|
||||
* doc/Makefile.am (check-options): New goal
|
||||
* doc/tar.texi: Update
|
||||
* src/tar.c: Implement --overwrite-dir option (long ago
|
||||
documented).
|
||||
|
||||
2006-06-12 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi: Document better the --totals option
|
||||
* NEWS: Update
|
||||
* src/buffer.c (total_blocks_deleted): New variable
|
||||
(set_start_time): Set volume_start_time and last_stat_time as well
|
||||
(set_volume_start_time): New function
|
||||
(compute_duration): Do not call set_start_time, update
|
||||
last_stat_time instead. Use it in calculation instead of
|
||||
start_time, which is now set only once, upon startup.
|
||||
(print_total_written): Removed.
|
||||
(print_total_stats): New function for printing byte/speed statistics.
|
||||
(_open_archive): Detect attempts to update compressed archives.
|
||||
(_gnu_flush_write): Always update prev_written.
|
||||
(open_archive): Call set_volume_start_time.
|
||||
* src/common.h (volume_start_time,last_stat_time): New globals
|
||||
(print_total_written): Replaced with:
|
||||
(print_total_stats): New function
|
||||
* 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.
|
||||
* 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.
|
||||
(main): Call print_total_stats if total_option is set.
|
||||
|
||||
2006-06-11 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/xheader.c (xheader_set_single_keyword): Fix typo.
|
||||
(decode_time): Avoid using gotos.
|
||||
|
||||
* doc/mastermenu.el: New file
|
||||
* doc/Makefile.am (master-menu): New goal
|
||||
* doc/tar.texi: Update master menu
|
||||
|
||||
2006-06-10 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi: Remove leftover include
|
||||
|
||||
2006-06-09 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/Makefile.am (tar_TEXINFOS): Add intern.texi
|
||||
(EXTRA_DIST): Remove convtexi.pl, add texify.sed
|
||||
* doc/intern.texi: New file
|
||||
* doc/convtexi.pl: Remove
|
||||
* doc/texify.sed: Auxiliary script to convert ../src/tar.h to
|
||||
header.texi
|
||||
* doc/rendition.texi: Fix typo
|
||||
* doc/tar.texi: Update
|
||||
* src/tar.h: Fix indentation, introduce end-of-format marker for
|
||||
texify.sed
|
||||
|
||||
* THANKS: Add Jason Armistead
|
||||
* doc/tar.texi: Update
|
||||
* NEWS: Update
|
||||
* src/buffer.c: Implement more flexible checkpoint style
|
||||
* src/common.h (checkpoint_option): Change type to unsigned
|
||||
(checkpoint_style): New variable.
|
||||
* src/tar.c: --checkpoint takes an optional argument specifying
|
||||
number of records between two successive checkpoints (proposed
|
||||
by Jason Armistead on 2004-06-22). Optional dot starting the
|
||||
argument means "print dots instead of textual checkpoints".
|
||||
(tar_help): New function
|
||||
* src/transform.c: Minor fixes.
|
||||
|
||||
2006-06-08 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* gnulib.modules: Add mkdtemp
|
||||
* doc/dumpdir.texi: New file
|
||||
* doc/Makefile.am (tar_TEXINFOS): Add dumpdir.texi
|
||||
* doc/tar.texi: Document dumpdir format
|
||||
* src/incremen.c (dumpdir_locate,obstack_code_rename):
|
||||
(purge_directory): Re-implement renaming. Introduce
|
||||
'X' control code.
|
||||
(make_tmp_dir_name): Remove
|
||||
|
||||
* src/transform.c (set_transform_expr,_transform_name_to_obstack):
|
||||
Implement NUMBER flag.
|
||||
(add_char_segment): Fix length assignement
|
||||
|
||||
* doc/tar.texi: Update
|
||||
|
||||
2006-06-07 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/transform.c (transform_name_fp): Run fun even if
|
||||
_transform_name_to_obstack returns false.
|
||||
(_transform_name_to_obstack,set_transform_expr): Implement GNU
|
||||
extension case conversion operations.
|
||||
|
||||
* doc/tar.texi (transform): Document the option.
|
||||
|
||||
2006-06-02 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* NEWS: Update
|
||||
* src/common.h (set_transform_expr): New function
|
||||
* tests/Makefile.am: Add incr04.at
|
||||
* tests/testsuite.at: Likewise
|
||||
* tests/incr04.at: New test case
|
||||
* tests/long01.at: Fix typo in the comment
|
||||
* tests/multiv04.at: Use genfile --files-from
|
||||
|
||||
(Above changes need new genfile.c from paxutils)
|
||||
|
||||
* TODO: Update
|
||||
* NEWS: Update
|
||||
* doc/tar.texi: Update
|
||||
* src/transform.c: New file
|
||||
* src/Makefile.am (tar_SOURCES): New module transform.c
|
||||
* src/common.h (transform_name, transform_name_fp): New functions
|
||||
(show_stored_names_option): Renamed to
|
||||
show_transformed_names_option. All uses changed
|
||||
* src/create.c (dump_file0): Transform file name
|
||||
* src/extract.c (extract_archive): safer_name_suffix and
|
||||
stripped_prefix_len are now called by decode_header
|
||||
* src/list.c (print_header): Update displayable name selection.
|
||||
* src/tar.c: New option --transform
|
||||
New option --show-transformed-names generalizes
|
||||
--show-stored-names. The latter is retained as an alias.
|
||||
|
||||
2006-05-31 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/incremen.c (make_directory): Fix initialization of struct
|
||||
directory.
|
||||
|
||||
2006-05-25 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi: Document use of globbing patterns.
|
||||
* src/tar.c (parse_opt): Add comment before --preserve case.
|
||||
|
||||
2006-05-24 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* NEWS: Update
|
||||
* 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
|
||||
(warn_regex_usage): New variable.
|
||||
(dump_file): First argument is const char*.
|
||||
(name_init,name_add): Removed
|
||||
(name_add_name,name_add_dir): New functions
|
||||
(name_next): Return const char*.
|
||||
* src/create.c: (dump_file,dump_file0): First argument is const
|
||||
char*. All callers updated.
|
||||
* src/names.c: Rewritten handling of member names in the command
|
||||
line. Tar no longer attempts to guess globbing patterns, instead
|
||||
it relies on --wildcard option.
|
||||
(init_names): Removed.
|
||||
(struct name_elt): New structure.
|
||||
(name_array): Change type to struct name_elt. All references updated
|
||||
(name_add_name,name_add_dir): New functions
|
||||
(name_next_elt): New function
|
||||
(name_next): Rewritten using name_next_elt.
|
||||
(namelist_match): Rewritten pattern matching using
|
||||
exclude_fnmatch.
|
||||
(names_notfound): Warn if globbing patterns were used without
|
||||
--wildcards option
|
||||
* src/tar.c (options): Move globbing-related options into a
|
||||
separate group. Set -l as an alias to --check-links, as required
|
||||
by UNIX98
|
||||
(struct tar_args): New fields
|
||||
wildcards,matching_flags,include_anchored
|
||||
(MAKE_EXCL_OPTIONS,MAKE_INCL_OPTIONS): New macros
|
||||
(parse_opt): Use x2nrealloc to grow archive_name_array.
|
||||
Use MAKE_EXCL_OPTIONS,MAKE_INCL_OPTIONS to create appropriate
|
||||
fnmatch options, and name_add_name,name_add_dir to handle member
|
||||
name and -C arguments.
|
||||
(decode_options): Likewise
|
||||
(main): Remove call to init_names.
|
||||
|
||||
* tests/append.at, tests/append01.at, tests/extrac01.at,
|
||||
tests/options.at, tests/options02.at, tests/same-order01.at,
|
||||
tests/same-order02.at: Make AT_SETUP more readable.
|
||||
|
||||
2006-05-23 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/buffer.c (change_tape_menu): Fix typo (uninitialized
|
||||
variable) introduced yesterday.
|
||||
|
||||
2006-05-22 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* doc/tar.texi: Use @var{file_name} instead of @var{file name}
|
||||
* src/buffer.c (change_tape_menu): Break the loop after obtaining
|
||||
new archive name. Check for empty input line.
|
||||
|
||||
2006-05-15 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* tests/atlocal.in (XFAILFILE): New variable
|
||||
* tests/version.at: Create $XFAILFILE on failure
|
||||
* tests/testsuite.at (AT_TAR_CHECK): Declare expected failure if
|
||||
$XFAILFILE exists.
|
||||
|
||||
2006-05-13 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* THANKS: Update
|
||||
* src/buffer.c (read_header0): Use read_header_primitive to avoid
|
||||
clubbering current_tar_info. All callers updated.
|
||||
* src/common.h (read_header_primitive): New function
|
||||
* src/extract.c (extract_volhdr): New function
|
||||
(prepare_to_extract): Use extract_volhdr as extractor for volume
|
||||
names.
|
||||
* src/list.c (read_header_primitive): New function
|
||||
(read_header): Front end for read_header_primitive
|
||||
* tests/chtype.at: New file
|
||||
* tests/volsize.at: New file
|
||||
* tests/Makefile.am (TESTSUITE_AT): Add chtype.at, volsize.at
|
||||
(check-full): New target.
|
||||
* tests/atlocal.in (TEST_DATA_URL,STAR_DATA_URL)
|
||||
(STAR_TESTSCRIPTS): Provide default values.
|
||||
(tarball_prereq): New function
|
||||
* tests/testsuite.at (AT_TARBALL_PREREQ): New defun
|
||||
(AT_STAR_PREREQ): Rewrite using tarball_prereq
|
||||
Include chtype.at and volsize.at
|
||||
* tests/volume.at: Add keywords.
|
||||
|
||||
* tests/star/gtarfail.at, tests/star/gtarfail2.at,
|
||||
tests/star/multi-fail.at, tests/star/pax-big-10g.at,
|
||||
tests/star/ustar-big-2g.at, tests/star/ustar-big-8g.at
|
||||
(AT_STAR_PREREQ): Provide md5 sum.
|
||||
|
||||
* lib/.cvsignore: Update
|
||||
|
||||
2006-05-08 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* tests/testsuite.at (AT_SORT_PREREQ, AT_UNPRIVILEGED_PREREQ): New
|
||||
defines
|
||||
|
||||
* tests/extrac04.at, tests/incr03.at, tests/listed02.at,
|
||||
tests/pipe.at, tests/rename01.at, tests/rename02.at,
|
||||
tests/rename03.at, tests/same-order01.at: Call
|
||||
AT_SORT_PREREQ. Remove fd 2 redirection after calls to sort
|
||||
* ignfail.at: Call AT_UNPRIVILEGED_PREREQ
|
||||
|
||||
2006-05-08 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
Listed incremental backups: keep more information about
|
||||
directories. Handle renamed directories more effectively
|
||||
(initial implementation, more updates to follow).
|
||||
Source tree before this point is tagged
|
||||
alpha_1_15_90_incremental_1.
|
||||
|
||||
* NEWS: Update
|
||||
* configure.ac: Raise version number to 1.15.91
|
||||
* src/common.h (rename_directory,append_incremental_renames): New
|
||||
functions.
|
||||
* src/extract.c (rename_directory): New function
|
||||
* src/incremen.c (struct directory.contents, flags): New members
|
||||
(nfs,found,new): Remove. Replaced by appropriate bitmask values in
|
||||
`flags' field. All uses updated.
|
||||
(directory_meta_table): New table.
|
||||
(hash_directory): Rename to hash_directory_name
|
||||
(compare_directories): Rename to compare_directory_names
|
||||
(hash_directory_meta,compare_directory_meta,find_directory_meta):
|
||||
New functions
|
||||
(compare_dirents): Removed
|
||||
(note_directory): Get 7th argument: directory contents.
|
||||
All callers updated
|
||||
(dumpdir_locate,makedumpdir): New functions
|
||||
(scan_directory): Rewritten. Use makedumpdir to create a sorted
|
||||
dumpdir array. This makes the obstack argument unnecessary. Besides,
|
||||
ALL_CHILDREN flag is set only for new directories.
|
||||
(procdir): Change return type to struct directory. Return
|
||||
immediately if the directory was already initialized. Discover
|
||||
directory renames using directory_meta_table.
|
||||
(append_incremental_renames): New function.
|
||||
(read_directory_file, write_directory_file): Use new snapshot file
|
||||
format.
|
||||
* src/names.c (collect_and_sort_names): Update dir_contents of the
|
||||
first non-fake name entry when in listed incremental mode.
|
||||
|
||||
* tests/incr03.at: New testcase
|
||||
* tests/rename01.at: New testcase
|
||||
* tests/rename02.at: New testcase
|
||||
* tests/rename03.at: New testcase
|
||||
* tests/Makefile.am: Add
|
||||
incr03.at,rename01.at,rename02.at,rename03.at
|
||||
* tests/testsuite.at: Likewise.
|
||||
* tests/listed02.at: Update for the new behavior
|
||||
* tests/multiv04.at (AT_KEYWORDS): Add missing incremental kw.
|
||||
|
||||
2006-05-02 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/buffer.c (try_new_volume): Attempt to continue if the name
|
||||
@@ -9,12 +640,12 @@
|
||||
tests/pipe.at, tests/same-order01.at, tests/same-order02.at,
|
||||
tests/sparse01.at, tests/sparse03.at: Always use genfile --file,
|
||||
this enables extra error checking.
|
||||
|
||||
|
||||
* tests/multiv03.at: Attempt to extract a member with truncated
|
||||
file name from the archive.
|
||||
|
||||
|
||||
* src/buffer.c (_open_archive): Remove unnecessary argument to
|
||||
check_compressed_archive.
|
||||
check_compressed_archive.
|
||||
|
||||
2006-04-25 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -28,7 +659,7 @@
|
||||
|
||||
* src/extract.c (extract_dir): Fix toggling existing directory
|
||||
permissions (Debian bug #361077). Use parts of patch provided by
|
||||
Ian Jackson <iwj@ubuntu.com>.
|
||||
Ian Jackson <iwj@ubuntu.com>.
|
||||
* src/compare.c: Minor changes
|
||||
* src/incremen.c (directory.new): New member
|
||||
(note_directory,find_directory: Use make_directory to create
|
||||
@@ -36,8 +667,8 @@
|
||||
(procdir): Avoid duplicating directories in the incremental
|
||||
backup map.
|
||||
* tests/Makefile.am (TESTSUITE_AT): Add extrac06.at
|
||||
* tests/testsuite.at: Include extrac06.at
|
||||
|
||||
* tests/testsuite.at: Include extrac06.at
|
||||
|
||||
2006-03-18 Ralf Wildenhues <Ralf.Wildenhues@gmx.de> (trivial change)
|
||||
|
||||
* tests/atlocal.in (PATH): Add build-aux from the source tree,
|
||||
|
||||
@@ -22,3 +22,10 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = ChangeLog.1 PORTS
|
||||
SUBDIRS = doc lib rmt src scripts po tests
|
||||
|
||||
dist-hook:
|
||||
-rm -f $(distdir).cpio
|
||||
find $(distdir) | cpio -Hcrc -o | \
|
||||
GZIP=$(GZIP_ENV) gzip -c > $(distdir).cpio.gz
|
||||
|
||||
distclean-local:
|
||||
-rm -f $(PACKAGE)-$(VERSION).cpio.gz
|
||||
129
NEWS
129
NEWS
@@ -1,11 +1,114 @@
|
||||
GNU tar NEWS - User visible changes.
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
version 1.16 - Sergey Poznyakoff, 2006-10-21
|
||||
|
||||
* After creating an archive, tar exits with code 1 if some files were
|
||||
changed while being read. Previous versions exited with code 2 (fatal
|
||||
error), and only if some files were truncated while being archived.
|
||||
|
||||
* New option --mtime allows to set modification times for all archive
|
||||
members during creation.
|
||||
|
||||
* Bug fixes
|
||||
** Avoid running off file descriptors when using multiple -C options.
|
||||
** tar --index-file=FILE --file=- sent the archive to FILE, and
|
||||
the listing to stderr.
|
||||
|
||||
|
||||
version 1.15.91 - Sergey Poznyakoff, 2006-06-16
|
||||
|
||||
* Incompatible changes
|
||||
|
||||
** Globbing
|
||||
|
||||
Previous versions of GNU tar assumed shell-style globbing when
|
||||
extracting from or listing an archive. For example:
|
||||
|
||||
tar xf foo.tar '*.c'
|
||||
|
||||
would extract all files whose names end in '.c'. This behavior
|
||||
was not documented and was incompatible with traditional tar
|
||||
implementations. Therefore, starting from this version, GNU tar
|
||||
no longer uses globbing by default. For example, the above invocation
|
||||
is now interpreted as a request to extract from the archive the file
|
||||
named '*.c'.
|
||||
|
||||
To treat member names as globbing patterns, use --wildcards option.
|
||||
If you wish tar to mimic the behavior of versions up to 1.15.90,
|
||||
add --wildcards to the value of the environment variable TAR_OPTIONS.
|
||||
|
||||
The exact way in which tar interprets member names is controlled by the
|
||||
following command line options:
|
||||
|
||||
--wildcards use wildcards
|
||||
--anchored patterns match file name start
|
||||
--ignore-case ignore case
|
||||
--wildcards-match-slash wildcards match `/'
|
||||
|
||||
Each of these options has a '--no-' counterpart that disables its
|
||||
effect (e.g. --no-wildcards).
|
||||
|
||||
These options affect both the interpretation of member names from
|
||||
command line and that of the exclusion patterns (given with --exclude
|
||||
and --exclude-from options). The defaults are:
|
||||
|
||||
1. For member names: --no-wildcards --anchored
|
||||
2. For exclusion patterns: --wildcards --no-anchored --wildcards-match-slash
|
||||
|
||||
The options can appear multiple times in the command line, thereby
|
||||
changing the way command line arguments are interpreted. For example,
|
||||
to use case-insensitive matching in exclude patterns and to revert to
|
||||
case-sensitive matching for the rest of command line, one could write:
|
||||
|
||||
tar xf foo.tar --ignore-case --exclude-from=FILE --no-ignore-case file.name
|
||||
|
||||
** Short option -l is now an alias of --check-links option, which complies
|
||||
with UNIX98. This ends the transition period started with version 1.14.
|
||||
|
||||
* New features
|
||||
|
||||
** New option --transform allows to transform file names before storing them
|
||||
in the archive or member names before extracting. The option takes a
|
||||
sed replace expression as its argument. For example,
|
||||
|
||||
tar cf foo.tar --transform 's,^,prefix/,'
|
||||
|
||||
will add 'prefix/' to all file names stored in foo.tar.
|
||||
|
||||
** --strip-components option works when deleting and comparing. In previous
|
||||
versions it worked only with --extract.
|
||||
|
||||
** New option --show-transformed-names enables display of transformed file
|
||||
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.
|
||||
|
||||
** New incremental snapshot file format keeps information about file names
|
||||
as well as that about directories.
|
||||
|
||||
** The --checkpoint option takes an optional argument specifying the number
|
||||
of records between the two successive checkpoints. Optional dot
|
||||
starting the argument intructs tar to print dots instead of textual
|
||||
checkpoints.
|
||||
|
||||
** The --totals option can be used with any tar operation (previous versions
|
||||
understood it only with --create). If an argument to this option is
|
||||
given, it specifies the signal upon delivery of which the statistics
|
||||
is to be printed. Both forms of this option (with and without
|
||||
argument) can be given to in a single invocation of tar.
|
||||
|
||||
* Bug fixes
|
||||
** Detect attempts to update compressed archives.
|
||||
|
||||
|
||||
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.
|
||||
** 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,
|
||||
including another -T option.
|
||||
Compatibility note: older versions of tar would only recognize -C
|
||||
@@ -13,14 +116,14 @@ as an option name within the file list file. Now any file whose name
|
||||
starts with - is handled as an option. To insert file names starting with
|
||||
dash, use the --add-file option.
|
||||
|
||||
* List files containing null-separated file names are detected and processed
|
||||
** List files containing null-separated file names are detected and processed
|
||||
automatically. It is no longer necessary to give the --null option.
|
||||
|
||||
* New option --no-unquote disables the unquoting of input file names.
|
||||
** New option --no-unquote disables the unquoting of input file names.
|
||||
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.
|
||||
** New option --test-label tests the archive volume label.
|
||||
If an argument is specified, the label is compared against its value.
|
||||
Tar exits with code 0 if the two strings match, and with code 2 if
|
||||
they do not.
|
||||
@@ -28,28 +131,28 @@ they do not.
|
||||
If no argument is given, the --verbose option is implied. In this case,
|
||||
tar prints the label name if present and exits with code 0.
|
||||
|
||||
* New option --show-stored-names. When creating an archive in verbose mode,
|
||||
** 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.
|
||||
|
||||
* New option --to-command pipes the contents of archive members to the
|
||||
** New option --to-command pipes the contents of archive members to the
|
||||
specified command.
|
||||
|
||||
* New option --atime-preserve=system, which uses the O_NOATIME feature
|
||||
** New option --atime-preserve=system, which uses the O_NOATIME feature
|
||||
of recent Linux kernels to avoid some problems when preserving file
|
||||
access times.
|
||||
|
||||
* New option --delay-directory-restore delays restoring modification times
|
||||
** New option --delay-directory-restore delays restoring modification times
|
||||
and permissions of extracted directories until the end of extraction.
|
||||
This is necessary for restoring from archives with unusual member
|
||||
ordering (in particular, those created with --no-recursion option).
|
||||
This option is implied when restoring from incremental archives.
|
||||
|
||||
* New option --restrict prohibits use of some potentially harmful tar
|
||||
** New option --restrict prohibits use of some potentially harmful tar
|
||||
options. Currently it disables '!' escape in multi-volume name menu.
|
||||
|
||||
* New options --quoting-style and --quote-chars control the way tar
|
||||
** New options --quoting-style and --quote-chars control the way tar
|
||||
quotes member names on output. The --quoting-style takes an argument
|
||||
specifying the quoting style to use (literal, shell, shell-always,
|
||||
c, escape, locale, clocale). The argument to --quote-chars is a string
|
||||
@@ -57,17 +160,17 @@ specifying characters to quote, even if the selected quoting style
|
||||
would not quote them otherwise. The option --no-quote-chars is
|
||||
provided to disable quoting certain characters.
|
||||
|
||||
* The end-of-volume script (introduced with --info-script option) can
|
||||
** The end-of-volume script (introduced with --info-script option) can
|
||||
get current archive name from the environment variable TAR_ARCHIVE and
|
||||
the volume number from the variable TAR_VOLUME. It can alter the
|
||||
archive name by writing new name to the file descriptor 3.
|
||||
|
||||
* Better support for full-resolution time stamps. Tar cannot restore
|
||||
** Better support for full-resolution time stamps. Tar cannot restore
|
||||
time stamps to full nanosecond resolution, though, until the kernel
|
||||
guys get their act together and give us a system call to set file time
|
||||
stamps to nanosecond resolution.
|
||||
|
||||
* The -v option now prints time stamps only to 1-minute resolution,
|
||||
** The -v option now prints time stamps only to 1-minute resolution,
|
||||
not full resolution, to avoid using up too many output columns.
|
||||
Nanosecond resolution is now supported, but that would be too much.
|
||||
|
||||
|
||||
2
README
2
README
@@ -78,7 +78,7 @@ scripts.
|
||||
|
||||
** `--disable-largefile' omits support for large files, even if the
|
||||
operating system supports large files. Typically, large files are
|
||||
those larger on 2 GB on a 32-bit host.
|
||||
those larger than 2 GB on a 32-bit host.
|
||||
|
||||
* Installation hints
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ that you have the latest stable version.
|
||||
- Gettext <http://www.gnu.org/software/gettext/>
|
||||
- Gzip <http://www.gnu.org/software/gzip/>
|
||||
- M4 <http://www.gnu.org/software/m4/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Wget <http://www.gnu.org/software/wget/>
|
||||
|
||||
As of this writing, the latest stable version of Gzip is 1.2.4 but we
|
||||
|
||||
5
THANKS
5
THANKS
@@ -220,6 +220,7 @@ Jan Djarv jan.djarv@mbox200.swipnet.se
|
||||
Janice Burton r06a165@bcc25.kodak.com
|
||||
Janne Snabb snabb@niksula.hut.fi
|
||||
Jason R. Mastaler jason@webmaster.net
|
||||
Jason Armistead Jason.Armistead@otis.com
|
||||
Jay Fenlason hack@gnu.org
|
||||
Jean-Michel Soenen soenen@lectra.fr
|
||||
Jean-Ph. Martin-Flatin syj@ecmwf.int
|
||||
@@ -268,6 +269,7 @@ Jurgen Botz jbotz@orixa.mtholyoke.edu
|
||||
Jyh-Shyang Wang erik@vsp.ee.nctu.edu.tw
|
||||
Jörg Schilling schilling@fokus.fraunhofer.de
|
||||
Jörg Weule weule@cs.uni-duesseldorf.de
|
||||
Jörg Weilbier gnu@weilbier.net
|
||||
Jörgen Hågg Jorgen.Hagg@axis.se
|
||||
Jörgen Weigert jw@suse.de
|
||||
Jürgen Lüters jlueters@t-online.de
|
||||
@@ -390,6 +392,7 @@ Pierce Cantrell cantrell@ee.tamu.edu
|
||||
R. Kent Dybvig dyb@cadence.bloomington.in.us
|
||||
R. Scott Butler butler@prism.es.dupont.com
|
||||
Rainer Orth ro@TechFak.Uni-Bielefeld.DE
|
||||
Ralf Wildenhues Ralf.Wildenhues@gmx.de
|
||||
Ralf S. Engelschall rse@engelschall.com
|
||||
Ralf Suckow suckow@contrib.de
|
||||
Ralph Corderoy ralph@inputplus.co.uk
|
||||
@@ -463,6 +466,7 @@ Sylvain Rougier un@grolier.fr
|
||||
Tarang Kumar Patel mombasa@ptolemy.arc.nasa.gov
|
||||
Ted Rule Ted_Rule@flextech.co.uk
|
||||
The King elvis@gnu.org
|
||||
Thomas metaf4@users.askja.de
|
||||
Thomas Bushnell n/BSG thomas@gnu.org
|
||||
Thomas Krebs krebs@faps.uni-erlangen.de
|
||||
Thomas König Thomas.Koenig@ciw.uni-karlsruhe.de
|
||||
@@ -509,6 +513,7 @@ William Kucharski kucharsk@netcom.com
|
||||
Wojciech Polak polak@gnu.org
|
||||
Wolfgang Rupprecht wolfgang@wsrcc.com
|
||||
Wolfram Gloger Wolfram.Gloger@dent.med.uni-muenchen.de
|
||||
Wolfram Kleff bugreport@wkleff.intergenia.de
|
||||
Wolfram Wagner ww@mpi-sb.mpg.de
|
||||
Włodzimierz Jan Martin wjm@pg.gda.pl
|
||||
Yasushi Suzudo SGR00413@niftyserve.or.jp
|
||||
|
||||
12
TODO
12
TODO
@@ -17,18 +17,6 @@ so that the GNU extensions (--incremental, --label and
|
||||
* Add support for a 'pax' command that conforms to POSIX 1003.1-2001.
|
||||
This would unify paxutils with tar.
|
||||
|
||||
* Remove command-line incompatibilities between GNU tar and UNIX tar
|
||||
as specified by UNIX98. The main problem is:
|
||||
|
||||
l GNU tar doesn't cross filesystem boundaries.
|
||||
UNIX98 tar warns if all links cannot be resolved.
|
||||
(GNU tar --check-links option)
|
||||
|
||||
Currently tar prints a warning when this option is used. Sometime
|
||||
in the future its semantics will be changed to that of --check-links.
|
||||
In the meanwhile we should announce a phase-in period where "l"
|
||||
changes in semantics.
|
||||
|
||||
* Interoperate better with Joerg Schilling's star implementation.
|
||||
|
||||
* Add an option to remove files that compare successfully.
|
||||
|
||||
215
bootstrap
215
bootstrap
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Bootstrap 'tar' from CVS.
|
||||
# Bootstrap this package from CVS.
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
|
||||
# Written by Paul Eggert and Sergey Poznyakoff.
|
||||
|
||||
# URL of our text domain page in Translation Project
|
||||
TP_URL="http://www.iro.umontreal.ca/translation/maint/tar/"
|
||||
package=tar
|
||||
|
||||
# Ensure file names are sorted consistently across platforms;
|
||||
# e.g., m4/ulonglong_gl.m4 should follow m4/ulonglong.m4.
|
||||
# Translation Project URL, for the registry of all projects.
|
||||
TP_URL='http://www.iro.umontreal.ca/translation/registry.cgi?domain='
|
||||
|
||||
# Ensure file names are sorted consistently across platforms.
|
||||
# Also, ensure diagnostics are in English, e.g., "wget --help" below.
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
@@ -64,25 +66,6 @@ to
|
||||
EOF
|
||||
}
|
||||
|
||||
update_po() {
|
||||
if [ $# = 1 ]; then
|
||||
case $1 in
|
||||
*.po) POFILE=$1;;
|
||||
*) POFILE=${1}.po;;
|
||||
esac
|
||||
echo "$0: getting translation for $1..."
|
||||
wget -r --cache=off $TP_URL/$POFILE
|
||||
else
|
||||
echo "$0: getting translations into po..."
|
||||
(cd po &&
|
||||
rm -f dummy `ls | sed -n '/\.gmo$/p; /\.po/p'` &&
|
||||
wget -nv -nd -r -l 1 -A .po --cache off $TP_URL &&
|
||||
rm -f index.html index.html.[0-9]*
|
||||
ls *.po | sed 's/\.po$//' >LINGUAS
|
||||
) || exit
|
||||
fi
|
||||
}
|
||||
|
||||
# Read configuration file
|
||||
if [ -r .bootstrap ]; then
|
||||
echo "$0: Reading configuration file .bootstrap"
|
||||
@@ -118,16 +101,87 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
# Get translations.
|
||||
|
||||
get_translations() {
|
||||
subdir=$1
|
||||
domain=$2
|
||||
po_file=$3
|
||||
|
||||
echo "$0: getting translations into $subdir for $domain..."
|
||||
|
||||
case $po_file in
|
||||
'') (cd $subdir && rm -f dummy `ls | sed -n '/\.gmo$/p; /\.po/p'`);;
|
||||
esac &&
|
||||
|
||||
$WGET_COMMAND -O "$subdir/$domain.html" "$TP_URL$domain" &&
|
||||
|
||||
sed -n 's|.*"http://[^"]*/translation/teams/PO/\([^/"]*\)/'"$domain"'-\([^/"]*\)\.[^."]*\.po".*|\1.\2|p' <"$subdir/$domain.html" |
|
||||
sort -k 1,1 -k 2,2n -k2,2 -k3,3n -k3,3 -k4,4n -k4,4 -k5,5n -k5.5 |
|
||||
awk -F. '
|
||||
{ if (lang && $1 != lang) print lang, ver }
|
||||
{ lang = $1; ver = substr($0, index($0, ".") + 1) }
|
||||
END { if (lang) print lang, ver }
|
||||
' |
|
||||
awk -v domain="$domain" -v po_file="$po_file" -v subdir="$subdir" '
|
||||
{
|
||||
lang = $1
|
||||
if (po_file && po_file != (lang ".po")) next
|
||||
|
||||
# Work around bugs in translations uncovered by gettext 0.15.
|
||||
# This workaround can be removed once the translations are fixed.
|
||||
if (lang == "hu" || lang == "zh_TW") next
|
||||
|
||||
ver = $2
|
||||
urlfmt = ""
|
||||
printf "$WGET_COMMAND -O %s/%s.po 'http://www.iro.umontreal.ca/translation/teams/PO/%s/%s-%s.%s.po' &&\n", subdir, lang, lang, domain, ver, lang
|
||||
}
|
||||
END { print ":" }
|
||||
' |
|
||||
sh &&
|
||||
ls "$subdir"/*.po | sed 's|.*/||; s|\.po$||' >"$subdir/LINGUAS" &&
|
||||
rm "$subdir/$domain.html"
|
||||
}
|
||||
|
||||
update_po() {
|
||||
if [ $# = 1 ]; then
|
||||
case $1 in
|
||||
*.po) POFILE=$1;;
|
||||
*) POFILE=${1}.po;;
|
||||
esac
|
||||
get_translations po $package "$POFILE"
|
||||
else
|
||||
get_translations po $package
|
||||
fi
|
||||
}
|
||||
|
||||
case $DOWNLOAD_PO in
|
||||
no) ;;
|
||||
*)
|
||||
case `wget --help` in
|
||||
*'--no-cache'*)
|
||||
no_cache='--no-cache';;
|
||||
*'--cache=on/off'*)
|
||||
no_cache='--cache=off';;
|
||||
*)
|
||||
no_cache='';;
|
||||
esac
|
||||
|
||||
WGET_COMMAND="wget -nv $no_cache"
|
||||
export WGET_COMMAND
|
||||
esac
|
||||
|
||||
case $DOWNLOAD_PO in
|
||||
only) update_po
|
||||
exit 0
|
||||
exit
|
||||
;;
|
||||
no|yes) ;;
|
||||
*) update_po $DOWNLOAD_PO
|
||||
exit 0
|
||||
exit
|
||||
esac
|
||||
|
||||
echo "$0: Bootstrapping CVS tar..."
|
||||
|
||||
echo "$0: Bootstrapping CVS $package..."
|
||||
|
||||
build_cvs_prefix() {
|
||||
CVS_PREFIX=:${1}:
|
||||
@@ -212,7 +266,7 @@ copy_files ${PAXUTILS_SRCDIR}/m4 m4
|
||||
echo "$0: Creating m4/paxutils.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([tar_PAXUTILS],["
|
||||
echo "AC_DEFUN([${package}_PAXUTILS],["
|
||||
cat ${PAXUTILS_SRCDIR}/m4/DISTFILES | sed '/^#/d;s/\(.*\)\.m4/pu_\1/' | tr a-z A-Z
|
||||
echo "])") > ./m4/paxutils.m4
|
||||
|
||||
@@ -236,7 +290,8 @@ case ${GNULIB_SRCDIR--} in
|
||||
GNULIB_SRCDIR=gnulib
|
||||
esac
|
||||
|
||||
<$GNULIB_SRCDIR/gnulib-tool || exit
|
||||
gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
|
||||
<$gnulib_tool || exit
|
||||
|
||||
get_modules gnulib.modules
|
||||
|
||||
@@ -247,14 +302,14 @@ while [ "$gnulib_modules" != "$previous_gnulib_modules" ]; do
|
||||
gnulib_modules=`
|
||||
(echo "$gnulib_modules"
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-dependencies $gnulib_module
|
||||
$gnulib_tool --extract-dependencies $gnulib_module
|
||||
done) | sort -u
|
||||
`
|
||||
done
|
||||
|
||||
gnulib_files=`
|
||||
(for gnulib_module in $gnulib_modules; do
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-filelist $gnulib_module
|
||||
$gnulib_tool --extract-filelist $gnulib_module
|
||||
done) | sort -u
|
||||
`
|
||||
|
||||
@@ -263,34 +318,28 @@ mkdir -p $gnulib_dirs || exit
|
||||
|
||||
for gnulib_file in $gnulib_files; do
|
||||
dest=$gnulib_file
|
||||
|
||||
case $gnulib_file in
|
||||
m4/codeset.m4) continue;;
|
||||
m4/intdiv0.m4) continue;;
|
||||
m4/inttypes-pri.m4) continue;;
|
||||
m4/isc-posix.m4) continue;;
|
||||
m4/lcmessage.m4) continue;;
|
||||
m4/onceonly_2_57.m4) dest=m4/onceonly.m4;;
|
||||
# These will be overwritten by autopoint, which still uses
|
||||
# old jm_.* macro names, so we have to keep both copies.
|
||||
m4/gettext.m4 | m4/glibc21.m4 | m4/inttypes_h.m4 | m4/lib-ld.m4 | \
|
||||
m4/lib-prefix.m4 | m4/po.m4 | m4/stdint_h.m4 | m4/uintmax_t.m4 | \
|
||||
m4/ulonglong.m4)
|
||||
dest=`expr $gnulib_file : '\(.*\).m4'`_gl.m4;;
|
||||
esac
|
||||
|
||||
rm -f $dest &&
|
||||
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file" &&
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
|
||||
done
|
||||
|
||||
# This suppresses a bogus diagnostic
|
||||
# "warning: macro `AM_LANGINFO_CODESET' not found in library".
|
||||
echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
|
||||
sed '
|
||||
/^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
|
||||
AC_DEFUN([AM_INTL_SUBDIR], [])
|
||||
/^AC_DEFUN(\[gt_INTL_SUBDIR_CORE],/,/^]/c\
|
||||
AC_DEFUN([gt_INTL_SUBDIR_CORE], [])
|
||||
' m4/gettext.m4 >m4/gettext_gl.m4 || exit
|
||||
|
||||
echo "$0: Creating m4/gnulib.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([tar_GNULIB],["
|
||||
echo "AC_DEFUN([${package}_GNULIB],["
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-autoconf-snippet $gnulib_module
|
||||
$gnulib_tool --extract-autoconf-snippet $gnulib_module
|
||||
done | sed '/AM_GNU_GETTEXT/d'
|
||||
echo "])") > ./m4/gnulib.m4
|
||||
|
||||
@@ -300,8 +349,8 @@ echo "$0: Creating lib/Makefile.am"
|
||||
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-automake-snippet $gnulib_module
|
||||
done | sed 's/lib_SOURCES/libtar_a_SOURCES/g' ) > lib/Makefile.am
|
||||
$gnulib_tool --extract-automake-snippet $gnulib_module
|
||||
done | sed "s/lib_SOURCES/lib${package}_a_SOURCES/g" ) > lib/Makefile.am
|
||||
|
||||
# Get translations.
|
||||
if test "$DOWNLOAD_PO" = "yes"; then
|
||||
@@ -310,8 +359,68 @@ fi
|
||||
|
||||
# Reconfigure, getting other files.
|
||||
|
||||
echo "$0: autoreconf --verbose --install --force ..."
|
||||
autoreconf --verbose --install --force || exit 1
|
||||
echo "$0: autopoint --force ..."
|
||||
autopoint --force || exit
|
||||
|
||||
# We don't need intl, so remove it.
|
||||
intl_files_to_remove='
|
||||
intl
|
||||
m4/gettext.m4
|
||||
m4/glibc2.m4
|
||||
m4/intdiv0.m4
|
||||
m4/intmax.m4
|
||||
m4/lcmessage.m4
|
||||
m4/lock.m4
|
||||
m4/printf-posix.m4
|
||||
m4/visibility.m4
|
||||
'
|
||||
echo $0: rm -fr $intl_files_to_remove ...
|
||||
rm -fr $intl_files_to_remove || exit
|
||||
|
||||
|
||||
# Undo changes to gnulib files that autoreconf made.
|
||||
|
||||
for gnulib_file in $gnulib_files; do
|
||||
test ! -f $gnulib_file || cmp -s $gnulib_file $GNULIB_SRCDIR/$gnulib_file || {
|
||||
rm -f $gnulib_file &&
|
||||
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file again" &&
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $gnulib_file || exit
|
||||
}
|
||||
done
|
||||
|
||||
# Make sure aclocal.m4 is not older than input files.
|
||||
sleep 1
|
||||
|
||||
for command in \
|
||||
'aclocal --force -I m4' \
|
||||
'autoconf --force' \
|
||||
'autoheader --force' \
|
||||
'automake --add-missing --copy --force-missing';
|
||||
do
|
||||
echo "$0: $command ..."
|
||||
$command || exit
|
||||
done
|
||||
|
||||
|
||||
# Create gettext configuration.
|
||||
echo "$0: Creating po/Makevars from po/Makevars.template ..."
|
||||
sed '
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
--flag=_:1:pass-c-format \\\
|
||||
--flag=N_:1:pass-c-format \\\
|
||||
--flag=error:3:c-format --flag=error_at_line:5:c-format \\\
|
||||
--flag=asnprintf:3:c-format --flag=vasnprintf:3:c-format \\\
|
||||
--flag=argp_error:2:c-format \\\
|
||||
--flag=__argp_error:2:c-format \\\
|
||||
--flag=argp_failure:4:c-format \\\
|
||||
--flag=__argp_failure:4:c-format \\\
|
||||
--flag=argp_fmtstream_printf:2:c-format \\\
|
||||
--flag=__argp_fmtstream_printf:2:c-format
|
||||
}
|
||||
' po/Makevars.template >po/Makevars
|
||||
|
||||
|
||||
echo "$0: done. Now you can run './configure'."
|
||||
|
||||
15
configure.ac
15
configure.ac
@@ -18,12 +18,12 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AC_INIT([GNU tar], [1.15.90], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.16], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h:config.hin])
|
||||
AC_PREREQ([2.59])
|
||||
AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2 dist-shar std-options])
|
||||
AC_PREREQ([2.60])
|
||||
AM_INIT_AUTOMAKE([1.9 gnits tar-ustar dist-bzip2 dist-shar std-options])
|
||||
|
||||
gl_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
@@ -80,15 +80,13 @@ AC_CHECK_TYPE(dev_t, unsigned)
|
||||
AC_CHECK_TYPE(ino_t, unsigned)
|
||||
|
||||
gt_TYPE_SSIZE_T
|
||||
gl_AC_TYPE_INTMAX_T
|
||||
jm_AC_TYPE_UINTMAX_T
|
||||
|
||||
# gnulib modules
|
||||
tar_GNULIB
|
||||
# paxutils modules
|
||||
tar_PAXUTILS
|
||||
|
||||
AC_CHECK_FUNCS(fsync lstat mkfifo readlink strerror symlink setlocale utimes)
|
||||
AC_CHECK_FUNCS(fsync getdtablesize lstat mkfifo readlink strerror symlink setlocale utimes)
|
||||
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
|
||||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||||
AC_CHECK_DECLS([time],,, [#include <time.h>])
|
||||
@@ -214,8 +212,8 @@ AC_CHECK_TYPE(iconv_t,:,
|
||||
])
|
||||
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-ngettext])
|
||||
AM_GNU_GETTEXT_VERSION(0.12.1)
|
||||
AM_GNU_GETTEXT([external], [need-formatstring-macros])
|
||||
AM_GNU_GETTEXT_VERSION([0.15])
|
||||
|
||||
# Initialize the test suite.
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
@@ -240,7 +238,6 @@ else
|
||||
BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
|
||||
fi
|
||||
|
||||
|
||||
AC_OUTPUT([Makefile\
|
||||
doc/Makefile\
|
||||
lib/Makefile\
|
||||
|
||||
@@ -24,6 +24,9 @@ tar.kw
|
||||
tar.kws
|
||||
tar.ky
|
||||
tar.log
|
||||
tar.op
|
||||
tar.ops
|
||||
tar.pdf
|
||||
tar.pg
|
||||
tar.pgs
|
||||
tar.ps
|
||||
@@ -31,6 +34,4 @@ tar.toc
|
||||
tar.tp
|
||||
tar.vr
|
||||
tar.vrs
|
||||
tmp-tar.*
|
||||
tmp2-tar.*
|
||||
version.texi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Makefile for GNU tar documentation.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2006 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,15 +19,18 @@
|
||||
|
||||
info_TEXINFOS = tar.texi
|
||||
tar_TEXINFOS = \
|
||||
dumpdir.texi\
|
||||
fdl.texi\
|
||||
freemanuals.texi\
|
||||
genfile.texi\
|
||||
getdate.texi\
|
||||
header.texi\
|
||||
intern.texi\
|
||||
rendition.texi\
|
||||
snapshot.texi\
|
||||
sparse.texi\
|
||||
value.texi
|
||||
EXTRA_DIST = convtexi.pl gendocs_template
|
||||
EXTRA_DIST = gendocs_template mastermenu.el texify.sed
|
||||
DISTCLEANFILES=*.info*
|
||||
|
||||
# The rendering level is anyone of PUBLISH, DISTRIB or PROOF.
|
||||
@@ -37,8 +40,33 @@ RENDITION = DISTRIB
|
||||
MAKEINFOFLAGS=-D$(RENDITION)
|
||||
|
||||
header.texi: $(top_srcdir)/src/tar.h
|
||||
sed -n '/Archive Format/,/End of Format/p' $(top_srcdir)/src/tar.h \
|
||||
| expand | sed 's/\([{}]\)/@\1/g' >$@
|
||||
sed -f $(srcdir)/texify.sed $(top_srcdir)/src/tar.h \
|
||||
| expand >$@
|
||||
|
||||
master-menu: $(tar_TEXINFOS)
|
||||
emacs -batch -l mastermenu.el -f make-master-menu $(info_TEXINFOS)
|
||||
|
||||
check-options:
|
||||
@ARGP_HELP_FMT='usage-indent=0,short-opt-col=0,long-opt-col=0,\
|
||||
doc-opt-col=0,opt-doc-col=0,header-col=0,rmargin=1' \
|
||||
$(top_builddir)/src/tar --usage | \
|
||||
sed -n 's/^\[--\([^]\=\[]*\).*/\1/p' | sort | uniq > opts.$$$$;\
|
||||
$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -E - \
|
||||
$(info_TEXINFOS) | \
|
||||
sed -n '/^@macro/,/^@end macro/d;s/@opindex *\([^@,]*\).*/\1/p' \
|
||||
| sort | uniq > docs.$$$$;\
|
||||
(echo 'Not documented options:';\
|
||||
join -v1 opts.$$$$ docs.$$$$;\
|
||||
echo 'Non-existing options:';\
|
||||
join -v2 opts.$$$$ docs.$$$$) > report.$$$$;\
|
||||
rm opts.$$$$ docs.$$$$;\
|
||||
if [ -n "`sed '1,2d' report.$$$$`" ]; then \
|
||||
cat report.$$$$;\
|
||||
rm report.$$$$;\
|
||||
exit 1;\
|
||||
fi;\
|
||||
rm report.$$$$
|
||||
|
||||
|
||||
clean-local:
|
||||
rm -rf manual
|
||||
@@ -51,7 +79,7 @@ TEXI2DVI=texi2dvi -t '@set $(RENDITION)' -E
|
||||
# Usual value is:
|
||||
# /usr/share/texmf/pdftex/plain/misc:/usr/share/texmf/pdftex/config
|
||||
manual:
|
||||
TEXINPUTS=$(srcdir):$(top_srcdir)/config:$(TEXINPUTS) \
|
||||
TEXINPUTS=$(srcdir):$(top_srcdir)/build-tex:$(TEXINPUTS) \
|
||||
MAKEINFO="$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
TEXI2DVI="$(TEXI2DVI) -t @finalout" \
|
||||
$(GENDOCS) tar 'GNU tar manual'
|
||||
|
||||
134
doc/convtexi.pl
134
doc/convtexi.pl
@@ -1,134 +0,0 @@
|
||||
#!/usr/local/bin/perl -- # -*-Perl-*-
|
||||
eval "exec /usr/local/bin/perl -S $0 $*"
|
||||
if 0;
|
||||
|
||||
# Copy a Texinfo file, replacing @value's, @FIXME's and other gooddies.
|
||||
|
||||
# Copyright (C) 1996, 2001 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 2, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
# François Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
$_ = <>;
|
||||
while ($_)
|
||||
{
|
||||
if (/^\@c()$/ || /^\@c (.*)/ || /^\@(include .*)/)
|
||||
{
|
||||
if ($topseen)
|
||||
{
|
||||
print "\@format\n";
|
||||
print "\@strong{\@\@c} $1\n";
|
||||
$_ = <>;
|
||||
while (/\@c (.*)/)
|
||||
{
|
||||
print "\@strong{\@\@c} $1\n";
|
||||
$_ = <>;
|
||||
}
|
||||
print "\@end format\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$delay .= "\@format\n";
|
||||
$delay .= "\@strong{\@\@c} $1\n";
|
||||
$_ = <>;
|
||||
while (/\@c (.*)/)
|
||||
{
|
||||
$delay .= "\@strong{\@\@c} $1\n";
|
||||
$_ = <>;
|
||||
}
|
||||
$delay .= "\@end format\n";
|
||||
}
|
||||
}
|
||||
elsif (/^\@chapter /)
|
||||
{
|
||||
print;
|
||||
# print $delay;
|
||||
$delay = '';
|
||||
$topseen = 1;
|
||||
$_ = <>;
|
||||
}
|
||||
elsif (/^\@macro /)
|
||||
{
|
||||
$_ = <> while ($_ && ! /^\@end macro/);
|
||||
$_ = <>;
|
||||
}
|
||||
elsif (/^\@set ([^ ]+) (.*)/)
|
||||
{
|
||||
$set{$1} = $2;
|
||||
$_ = <>;
|
||||
}
|
||||
elsif (/^\@UNREVISED/)
|
||||
{
|
||||
print "\@quotation\n";
|
||||
print "\@emph{(This message will disappear, once this node is revised.)}\n";
|
||||
print "\@end quotation\n";
|
||||
$_ = <>;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (/\@value{([^\}]*)}/)
|
||||
{
|
||||
if (defined $set{$1})
|
||||
{
|
||||
$_ = "$`$set{$1}$'";
|
||||
}
|
||||
else
|
||||
{
|
||||
$_ = "$`\@strong{<UNDEFINED>}$1\@strong{</UNDEFINED>}$'";
|
||||
}
|
||||
}
|
||||
while (/\@FIXME-?([a-z]*)\{/)
|
||||
{
|
||||
$tag = $1 eq '' ? 'fixme' : $1;
|
||||
$tag =~ y/a-z/A-Z/;
|
||||
print "$`\@strong{<$tag>}";
|
||||
$_ = $';
|
||||
$level = 1;
|
||||
while ($level > 0)
|
||||
{
|
||||
if (/([{}])/)
|
||||
{
|
||||
if ($1 eq '{')
|
||||
{
|
||||
$level++;
|
||||
print "$`\{";
|
||||
$_ = $';
|
||||
}
|
||||
elsif ($level > 1)
|
||||
{
|
||||
$level--;
|
||||
print "$`\}";
|
||||
$_ = $';
|
||||
}
|
||||
else
|
||||
{
|
||||
$level = 0;
|
||||
print "$`\@strong{</$tag>}";
|
||||
$_ = $';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print;
|
||||
$_ = <>;
|
||||
}
|
||||
}
|
||||
}
|
||||
print;
|
||||
$_ = <>;
|
||||
}
|
||||
}
|
||||
exit 0;
|
||||
132
doc/dumpdir.texi
Normal file
132
doc/dumpdir.texi
Normal file
@@ -0,0 +1,132 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 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.
|
||||
|
||||
Incremental archives keep information about contents of each
|
||||
dumped directory in special data blocks called @dfn{dumpdirs}.
|
||||
|
||||
Dumpdir is a sequence of entries of the following form:
|
||||
|
||||
@smallexample
|
||||
@var{C} @var{filename} \0
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
where @var{C} is one of the @dfn{control codes} described below,
|
||||
@var{filename} is the name of the file @var{C} operates upon, and
|
||||
@samp{\0} represents a nul character (ASCII 0). The white space
|
||||
characters were added for readability, real dumpdirs do not contain
|
||||
them.
|
||||
|
||||
Each dumpdir ends with a single nul character.
|
||||
|
||||
The following table describes control codes and their meanings:
|
||||
|
||||
@table @samp
|
||||
@item Y
|
||||
@var{filename} is contained in the archive.
|
||||
|
||||
@item N
|
||||
@var{filename} was present in the directory at the time the archive
|
||||
was made, yet it was not dumped to the archive, because it had not
|
||||
changed since the last backup.
|
||||
|
||||
@item D
|
||||
@var{filename} is a directory.
|
||||
|
||||
@item R
|
||||
This code requests renaming of the @var{filename} to the name
|
||||
specified with the following @samp{T} command.
|
||||
|
||||
@item T
|
||||
Specify target file name for @samp{R} command (see below).
|
||||
|
||||
@item X
|
||||
Specify @dfn{temporary directory} name for a rename operation (see below).
|
||||
@end table
|
||||
|
||||
Codes @samp{Y}, @samp{N} and @samp{D} require @var{filename} argument
|
||||
to be a relative file name to the directory this dumpdir describes,
|
||||
whereas codes @samp{R}, @samp{T} and @samp{X} require their argument
|
||||
to be an absolute file name.
|
||||
|
||||
The three codes @samp{R}, @samp{T} and @samp{X} specify a
|
||||
@dfn{renaming operation}. In the simplest case it is:
|
||||
|
||||
@smallexample
|
||||
R@file{source}\0T@file{dest}\0
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
which means ``rename file @file{source} to file @file{dest}''.
|
||||
|
||||
However, there are cases that require using a @dfn{temporary
|
||||
directory}. For example, consider the following scenario:
|
||||
|
||||
@enumerate 1
|
||||
@item
|
||||
Previous run dumped a directory @file{foo} which contained the
|
||||
following three directories:
|
||||
|
||||
@smallexample
|
||||
a
|
||||
b
|
||||
c
|
||||
@end smallexample
|
||||
|
||||
@item
|
||||
They were renamed @emph{cyclically}, so that:
|
||||
|
||||
@example
|
||||
@file{a} became @file{b}
|
||||
@file{b} became @file{c}
|
||||
@file{c} became @file{a}
|
||||
@end example
|
||||
|
||||
@item
|
||||
New incremental dump was made.
|
||||
@end enumerate
|
||||
|
||||
This case cannot be handled by three successive renames, since
|
||||
renaming @file{a} to @file{b} will destroy existing directory.
|
||||
To handle such case a temporary directory is required. @GNUTAR{}
|
||||
will create the following dumpdir (newlines have been added for
|
||||
readability):
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
Xfoo\0
|
||||
Rfoo/a\0T\0
|
||||
Rfoo/b\0Tfoo/c\0
|
||||
Rfoo/c\0Tfoo/a\0
|
||||
R\0Tfoo/a\0
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
The first command, @samp{Xfoo\0}, instructs the extractor to create a
|
||||
temporary directory in the directory @file{foo}. Second command,
|
||||
@samp{Rfoo/aT\0}, says ``rename file @file{foo/a} to the temporary
|
||||
directory that has just been created'' (empty file name after a
|
||||
command means use temporary directory). Third and fourth commands
|
||||
work as usual, and, finally, the last command, @samp{R\0Tfoo/a\0}
|
||||
tells tar to rename the temporary directory to @file{foo/a}.
|
||||
|
||||
The exact placement of a dumpdir in the archive depends on the
|
||||
archive format (@pxref{Formats}):
|
||||
|
||||
@itemize
|
||||
@item PAX archives
|
||||
|
||||
In PAX archives, dumpdir is stored in the extended header of the
|
||||
corresponding directory, in variable @code{GNU.dumpdir}.
|
||||
|
||||
@item GNU and old GNU archives
|
||||
|
||||
These formats implement special header type @samp{D}, which is similar
|
||||
to ustar header @samp{5} (directory), except that it precedes a data
|
||||
block containing the dumpdir.
|
||||
@end itemize
|
||||
|
||||
@c End of dumpdir.texi
|
||||
335
doc/intern.texi
Normal file
335
doc/intern.texi
Normal file
@@ -0,0 +1,335 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@menu
|
||||
* Standard:: Basic Tar Format
|
||||
* Extensions:: @acronym{GNU} Extensions to the Archive Format
|
||||
* Sparse Formats:: Storing Sparse Files
|
||||
* Snapshot Files::
|
||||
* Dumpdir::
|
||||
@end menu
|
||||
|
||||
@node Standard
|
||||
@unnumberedsec Basic Tar Format
|
||||
@UNREVISED
|
||||
|
||||
While an archive may contain many files, the archive itself is a
|
||||
single ordinary file. Like any other file, an archive file can be
|
||||
written to a storage device such as a tape or disk, sent through a
|
||||
pipe or over a network, saved on the active file system, or even
|
||||
stored in another archive. An archive file is not easy to read or
|
||||
manipulate without using the @command{tar} utility or Tar mode in
|
||||
@acronym{GNU} Emacs.
|
||||
|
||||
Physically, an archive consists of a series of file entries terminated
|
||||
by an end-of-archive entry, which consists of two 512 blocks of zero
|
||||
bytes. A file
|
||||
entry usually describes one of the files in the archive (an
|
||||
@dfn{archive member}), and consists of a file header and the contents
|
||||
of the file. File headers contain file names and statistics, checksum
|
||||
information which @command{tar} uses to detect file corruption, and
|
||||
information about file types.
|
||||
|
||||
Archives are permitted to have more than one member with the same
|
||||
member name. One way this situation can occur is if more than one
|
||||
version of a file has been stored in the archive. For information
|
||||
about adding new versions of a file to an archive, see @ref{update}.
|
||||
@FIXME-xref{To learn more about having more than one archive member with the
|
||||
same name, see -backup node, when it's written.}
|
||||
|
||||
In addition to entries describing archive members, an archive may
|
||||
contain entries which @command{tar} itself uses to store information.
|
||||
@xref{label}, for an example of such an archive entry.
|
||||
|
||||
A @command{tar} archive file contains a series of blocks. Each block
|
||||
contains @code{BLOCKSIZE} bytes. Although this format may be thought
|
||||
of as being on magnetic tape, other media are often used.
|
||||
|
||||
Each file archived is represented by a header block which describes
|
||||
the file, followed by zero or more blocks which give the contents
|
||||
of the file. At the end of the archive file there are two 512-byte blocks
|
||||
filled with binary zeros as an end-of-file marker. A reasonable system
|
||||
should write such end-of-file marker at the end of an archive, but
|
||||
must not assume that such a block exists when reading an archive. In
|
||||
particular @GNUTAR{} always issues a warning if it does not encounter it.
|
||||
|
||||
The blocks may be @dfn{blocked} for physical I/O operations.
|
||||
Each record of @var{n} blocks (where @var{n} is set by the
|
||||
@option{--blocking-factor=@var{512-size}} (@option{-b @var{512-size}}) option to @command{tar}) is written with a single
|
||||
@w{@samp{write ()}} operation. On magnetic tapes, the result of
|
||||
such a write is a single record. When writing an archive,
|
||||
the last record of blocks should be written at the full size, with
|
||||
blocks after the zero block containing all zeros. When reading
|
||||
an archive, a reasonable system should properly handle an archive
|
||||
whose last record is shorter than the rest, or which contains garbage
|
||||
records after a zero block.
|
||||
|
||||
The header block is defined in C as follows. In the @GNUTAR{}
|
||||
distribution, this is part of file @file{src/tar.h}:
|
||||
|
||||
@smallexample
|
||||
@include header.texi
|
||||
@end smallexample
|
||||
|
||||
All characters in header blocks are represented by using 8-bit
|
||||
characters in the local variant of ASCII. Each field within the
|
||||
structure is contiguous; that is, there is no padding used within
|
||||
the structure. Each character on the archive medium is stored
|
||||
contiguously.
|
||||
|
||||
Bytes representing the contents of files (after the header block
|
||||
of each file) are not translated in any way and are not constrained
|
||||
to represent characters in any character set. The @command{tar} format
|
||||
does not distinguish text files from binary files, and no translation
|
||||
of file contents is performed.
|
||||
|
||||
The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and
|
||||
@code{gname} are null-terminated character strings. All other fields
|
||||
are zero-filled octal numbers in ASCII. Each numeric field of width
|
||||
@var{w} contains @var{w} minus 1 digits, and a null.
|
||||
|
||||
The @code{name} field is the file name of the file, with directory names
|
||||
(if any) preceding the file name, separated by slashes.
|
||||
|
||||
@FIXME{how big a name before field overflows?}
|
||||
|
||||
The @code{mode} field provides nine bits specifying file permissions
|
||||
and three bits to specify the Set UID, Set GID, and Save Text
|
||||
(@dfn{sticky}) modes. Values for these bits are defined above.
|
||||
When special permissions are required to create a file with a given
|
||||
mode, and the user restoring files from the archive does not hold such
|
||||
permissions, the mode bit(s) specifying those special permissions
|
||||
are ignored. Modes which are not supported by the operating system
|
||||
restoring files from the archive will be ignored. Unsupported modes
|
||||
should be faked up when creating or updating an archive; e.g., the
|
||||
group permission could be copied from the @emph{other} permission.
|
||||
|
||||
The @code{uid} and @code{gid} fields are the numeric user and group
|
||||
ID of the file owners, respectively. If the operating system does
|
||||
not support numeric user or group IDs, these fields should be ignored.
|
||||
|
||||
The @code{size} field is the size of the file in bytes; linked files
|
||||
are archived with this field specified as zero. @FIXME-xref{Modifiers, in
|
||||
particular the @option{--incremental} (@option{-G}) option.}
|
||||
|
||||
The @code{mtime} field is the data modification time of the file at
|
||||
the time it was archived. It is the ASCII representation of the octal
|
||||
value of the last time the file's contents were modified, represented
|
||||
as an integer number of
|
||||
seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
||||
|
||||
The @code{chksum} field is the ASCII representation of the octal value
|
||||
of the simple sum of all bytes in the header block. Each 8-bit
|
||||
byte in the header is added to an unsigned integer, initialized to
|
||||
zero, the precision of which shall be no less than seventeen bits.
|
||||
When calculating the checksum, the @code{chksum} field is treated as
|
||||
if it were all blanks.
|
||||
|
||||
The @code{typeflag} field specifies the type of file archived. If a
|
||||
particular implementation does not recognize or permit the specified
|
||||
type, the file will be extracted as if it were a regular file. As this
|
||||
action occurs, @command{tar} issues a warning to the standard error.
|
||||
|
||||
The @code{atime} and @code{ctime} fields are used in making incremental
|
||||
backups; they store, respectively, the particular file's access and
|
||||
status change times.
|
||||
|
||||
The @code{offset} is used by the @option{--multi-volume} (@option{-M}) option, when
|
||||
making a multi-volume archive. The offset is number of bytes into
|
||||
the file that we need to restart at to continue the file on the next
|
||||
tape, i.e., where we store the location that a continued file is
|
||||
continued at.
|
||||
|
||||
The following fields were added to deal with sparse files. A file
|
||||
is @dfn{sparse} if it takes in unallocated blocks which end up being
|
||||
represented as zeros, i.e., no useful data. A test to see if a file
|
||||
is sparse is to look at the number blocks allocated for it versus the
|
||||
number of characters in the file; if there are fewer blocks allocated
|
||||
for the file than would normally be allocated for a file of that
|
||||
size, then the file is sparse. This is the method @command{tar} uses to
|
||||
detect a sparse file, and once such a file is detected, it is treated
|
||||
differently from non-sparse files.
|
||||
|
||||
Sparse files are often @code{dbm} files, or other database-type files
|
||||
which have data at some points and emptiness in the greater part of
|
||||
the file. Such files can appear to be very large when an @samp{ls
|
||||
-l} is done on them, when in truth, there may be a very small amount
|
||||
of important data contained in the file. It is thus undesirable
|
||||
to have @command{tar} think that it must back up this entire file, as
|
||||
great quantities of room are wasted on empty blocks, which can lead
|
||||
to running out of room on a tape far earlier than is necessary.
|
||||
Thus, sparse files are dealt with so that these empty blocks are
|
||||
not written to the tape. Instead, what is written to the tape is a
|
||||
description, of sorts, of the sparse file: where the holes are, how
|
||||
big the holes are, and how much data is found at the end of the hole.
|
||||
This way, the file takes up potentially far less room on the tape,
|
||||
and when the file is extracted later on, it will look exactly the way
|
||||
it looked beforehand. The following is a description of the fields
|
||||
used to handle a sparse file:
|
||||
|
||||
The @code{sp} is an array of @code{struct sparse}. Each @code{struct
|
||||
sparse} contains two 12-character strings which represent an offset
|
||||
into the file and a number of bytes to be written at that offset.
|
||||
The offset is absolute, and not relative to the offset in preceding
|
||||
array element.
|
||||
|
||||
The header can hold four of these @code{struct sparse} at the moment;
|
||||
if more are needed, they are not stored in the header.
|
||||
|
||||
The @code{isextended} flag is set when an @code{extended_header}
|
||||
is needed to deal with a file. Note that this means that this flag
|
||||
can only be set when dealing with a sparse file, and it is only set
|
||||
in the event that the description of the file will not fit in the
|
||||
allotted room for sparse structures in the header. In other words,
|
||||
an extended_header is needed.
|
||||
|
||||
The @code{extended_header} structure is used for sparse files which
|
||||
need more sparse structures than can fit in the header. The header can
|
||||
fit 4 such structures; if more are needed, the flag @code{isextended}
|
||||
gets set and the next block is an @code{extended_header}.
|
||||
|
||||
Each @code{extended_header} structure contains an array of 21
|
||||
sparse structures, along with a similar @code{isextended} flag
|
||||
that the header had. There can be an indeterminate number of such
|
||||
@code{extended_header}s to describe a sparse file.
|
||||
|
||||
@table @asis
|
||||
|
||||
@item @code{REGTYPE}
|
||||
@itemx @code{AREGTYPE}
|
||||
These flags represent a regular file. In order to be compatible
|
||||
with older versions of @command{tar}, a @code{typeflag} value of
|
||||
@code{AREGTYPE} should be silently recognized as a regular file.
|
||||
New archives should be created using @code{REGTYPE}. Also, for
|
||||
backward compatibility, @command{tar} treats a regular file whose name
|
||||
ends with a slash as a directory.
|
||||
|
||||
@item @code{LNKTYPE}
|
||||
This flag represents a file linked to another file, of any type,
|
||||
previously archived. Such files are identified in Unix by each
|
||||
file having the same device and inode number. The linked-to name is
|
||||
specified in the @code{linkname} field with a trailing null.
|
||||
|
||||
@item @code{SYMTYPE}
|
||||
This represents a symbolic link to another file. The linked-to name
|
||||
is specified in the @code{linkname} field with a trailing null.
|
||||
|
||||
@item @code{CHRTYPE}
|
||||
@itemx @code{BLKTYPE}
|
||||
These represent character special files and block special files
|
||||
respectively. In this case the @code{devmajor} and @code{devminor}
|
||||
fields will contain the major and minor device numbers respectively.
|
||||
Operating systems may map the device specifications to their own
|
||||
local specification, or may ignore the entry.
|
||||
|
||||
@item @code{DIRTYPE}
|
||||
This flag specifies a directory or sub-directory. The directory
|
||||
name in the @code{name} field should end with a slash. On systems where
|
||||
disk allocation is performed on a directory basis, the @code{size} field
|
||||
will contain the maximum number of bytes (which may be rounded to
|
||||
the nearest disk block allocation unit) which the directory may
|
||||
hold. A @code{size} field of zero indicates no such limiting. Systems
|
||||
which do not support limiting in this manner should ignore the
|
||||
@code{size} field.
|
||||
|
||||
@item @code{FIFOTYPE}
|
||||
This specifies a FIFO special file. Note that the archiving of a
|
||||
FIFO file archives the existence of this file and not its contents.
|
||||
|
||||
@item @code{CONTTYPE}
|
||||
This specifies a contiguous file, which is the same as a normal
|
||||
file except that, in operating systems which support it, all its
|
||||
space is allocated contiguously on the disk. Operating systems
|
||||
which do not allow contiguous allocation should silently treat this
|
||||
type as a normal file.
|
||||
|
||||
@item @code{A} @dots{} @code{Z}
|
||||
These are reserved for custom implementations. Some of these are
|
||||
used in the @acronym{GNU} modified format, as described below.
|
||||
|
||||
@end table
|
||||
|
||||
Other values are reserved for specification in future revisions of
|
||||
the P1003 standard, and should not be used by any @command{tar} program.
|
||||
|
||||
The @code{magic} field indicates that this archive was output in
|
||||
the P1003 archive format. If this field contains @code{TMAGIC},
|
||||
the @code{uname} and @code{gname} fields will contain the ASCII
|
||||
representation of the owner and group of the file respectively.
|
||||
If found, the user and group IDs are used rather than the values in
|
||||
the @code{uid} and @code{gid} fields.
|
||||
|
||||
For references, see ISO/IEC 9945-1:1990 or IEEE Std 1003.1-1990, pages
|
||||
169-173 (section 10.1) for @cite{Archive/Interchange File Format}; and
|
||||
IEEE Std 1003.2-1992, pages 380-388 (section 4.48) and pages 936-940
|
||||
(section E.4.48) for @cite{pax - Portable archive interchange}.
|
||||
|
||||
@node Extensions
|
||||
@unnumberedsec @acronym{GNU} Extensions to the Archive Format
|
||||
@UNREVISED
|
||||
|
||||
The @acronym{GNU} format uses additional file types to describe new types of
|
||||
files in an archive. These are listed below.
|
||||
|
||||
@table @code
|
||||
@item GNUTYPE_DUMPDIR
|
||||
@itemx 'D'
|
||||
This represents a directory and a list of files created by the
|
||||
@option{--incremental} (@option{-G}) option. The @code{size} field gives the total
|
||||
size of the associated list of files. Each file name is preceded by
|
||||
either a @samp{Y} (the file should be in this archive) or an @samp{N}.
|
||||
(The file is a directory, or is not stored in the archive.) Each file
|
||||
name is terminated by a null. There is an additional null after the
|
||||
last file name.
|
||||
|
||||
@item GNUTYPE_MULTIVOL
|
||||
@itemx 'M'
|
||||
This represents a file continued from another volume of a multi-volume
|
||||
archive created with the @option{--multi-volume} (@option{-M}) option. The original
|
||||
type of the file is not given here. The @code{size} field gives the
|
||||
maximum size of this piece of the file (assuming the volume does
|
||||
not end before the file is written out). The @code{offset} field
|
||||
gives the offset from the beginning of the file where this part of
|
||||
the file begins. Thus @code{size} plus @code{offset} should equal
|
||||
the original size of the file.
|
||||
|
||||
@item GNUTYPE_SPARSE
|
||||
@itemx 'S'
|
||||
This flag indicates that we are dealing with a sparse file. Note
|
||||
that archiving a sparse file requires special operations to find
|
||||
holes in the file, which mark the positions of these holes, along
|
||||
with the number of bytes of data to be found after the hole.
|
||||
|
||||
@item GNUTYPE_VOLHDR
|
||||
@itemx 'V'
|
||||
This file type is used to mark the volume header that was given with
|
||||
the @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) option when the archive was created. The @code{name}
|
||||
field contains the @code{name} given after the @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) option.
|
||||
The @code{size} field is zero. Only the first file in each volume
|
||||
of an archive should have this type.
|
||||
|
||||
@end table
|
||||
|
||||
You may have trouble reading a @acronym{GNU} format archive on a
|
||||
non-@acronym{GNU} system if the options @option{--incremental} (@option{-G}),
|
||||
@option{--multi-volume} (@option{-M}), @option{--sparse} (@option{-S}), or @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) were
|
||||
used when writing the archive. In general, if @command{tar} does not
|
||||
use the @acronym{GNU}-added fields of the header, other versions of
|
||||
@command{tar} should be able to read the archive. Otherwise, the
|
||||
@command{tar} program will give an error, the most likely one being a
|
||||
checksum error.
|
||||
|
||||
@node Sparse Formats
|
||||
@unnumberedsec Storing Sparse Files
|
||||
@include sparse.texi
|
||||
|
||||
@node Snapshot Files
|
||||
@unnumberedsec Format of the Incremental Snapshot Files
|
||||
@include snapshot.texi
|
||||
|
||||
@node Dumpdir
|
||||
@unnumberedsec Dumpdir
|
||||
@include dumpdir.texi
|
||||
|
||||
91
doc/mastermenu.el
Normal file
91
doc/mastermenu.el
Normal file
@@ -0,0 +1,91 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright (C) 2006 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 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 2, or (at your option)
|
||||
;; any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program; if not, write to the Free Software Foundation,
|
||||
;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file redefines texinfo-master-menu-list so that it takes into
|
||||
;; account included files.
|
||||
|
||||
;; Known bugs: @menu without previous sectioning command will inherit
|
||||
;; documentation string from the previous menu. However, since such a
|
||||
;; menu is illegal in a texinfo file, we can live with it.
|
||||
|
||||
(require 'texinfo)
|
||||
(require 'texnfo-upd)
|
||||
|
||||
(defun texinfo-master-menu-list-recursive (title)
|
||||
"Auxiliary function used by `texinfo-master-menu-list'."
|
||||
(save-excursion
|
||||
(let (master-menu-list)
|
||||
(while (re-search-forward "\\(^@menu\\|^@include\\)" nil t)
|
||||
(cond
|
||||
((string= (match-string 0) "@include")
|
||||
(skip-chars-forward " \t")
|
||||
(let ((included-name (let ((start (point)))
|
||||
(end-of-line)
|
||||
(skip-chars-backward " \t")
|
||||
(buffer-substring start (point)))))
|
||||
(end-of-line)
|
||||
(let ((prev-title (texinfo-copy-menu-title)))
|
||||
(save-excursion
|
||||
(set-buffer (find-file-noselect included-name))
|
||||
(setq master-menu-list
|
||||
(append (texinfo-master-menu-list-recursive prev-title)
|
||||
master-menu-list))))))
|
||||
(t
|
||||
(setq master-menu-list
|
||||
(cons (list
|
||||
(texinfo-copy-menu)
|
||||
(let ((menu-title (texinfo-copy-menu-title)))
|
||||
(if (string= menu-title "")
|
||||
title
|
||||
menu-title)))
|
||||
master-menu-list)))))
|
||||
master-menu-list)))
|
||||
|
||||
(defun texinfo-master-menu-list ()
|
||||
"Return a list of menu entries and header lines for the master menu,
|
||||
recursing into included files.
|
||||
|
||||
Start with the menu for chapters and indices and then find each
|
||||
following menu and the title of the node preceding that menu.
|
||||
|
||||
The master menu list has this form:
|
||||
|
||||
\(\(\(... \"entry-1-2\" \"entry-1\"\) \"title-1\"\)
|
||||
\(\(... \"entry-2-2\" \"entry-2-1\"\) \"title-2\"\)
|
||||
...\)
|
||||
|
||||
However, there does not need to be a title field."
|
||||
|
||||
(reverse (texinfo-master-menu-list-recursive "")))
|
||||
|
||||
(defun make-master-menu ()
|
||||
"Create master menu in the first Emacs argument."
|
||||
(find-file (car command-line-args-left))
|
||||
(texinfo-master-menu nil)
|
||||
(save-buffer))
|
||||
|
||||
|
||||
;;; mastermenu.el ends here
|
||||
@@ -1,9 +1,9 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright (C) 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
@c 2003, 2004 Free Software Foundation, Inc.
|
||||
@c 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@c This file contains support for 'renditions' by Fra@,{c}ois Pinard
|
||||
@c This file contains support for 'renditions' by Fran@,{c}ois Pinard
|
||||
@c I extended it by adding a FIXME_FOOTNOTE variable, which controls
|
||||
@c whether FIXME information should be placed in footnotes or
|
||||
@c inlined. --gray
|
||||
@@ -55,28 +55,26 @@
|
||||
@c Output various FIXME information only in PROOF rendition.
|
||||
|
||||
@macro FIXME{string}
|
||||
@allow-recursion
|
||||
@quote-arg
|
||||
@ifset PROOF
|
||||
@ifset PROOF_FOOTNOTED
|
||||
@footnote{@strong{FIXME:} \string\}
|
||||
@end ifset
|
||||
@ifclear PROOF_FOOTNOTED
|
||||
@cartouche
|
||||
@strong{<FIXME>} \string\ @strong{</>}
|
||||
@end cartouche
|
||||
@end ifclear
|
||||
@end ifset
|
||||
|
||||
@end macro
|
||||
|
||||
@macro FIXME-ref{string}
|
||||
@quote-arg
|
||||
@ifset PROOF
|
||||
@strong{<REF>} \string\ @strong{</>}
|
||||
@end ifset
|
||||
@end macro
|
||||
|
||||
@macro FIXME-pxref{string}
|
||||
@quote-arg
|
||||
@ifset PROOF
|
||||
@strong{<PXREF>} \string\ @strong{</>}
|
||||
@end ifset
|
||||
@@ -84,7 +82,6 @@
|
||||
@end macro
|
||||
|
||||
@macro FIXME-xref{string}
|
||||
@quote-arg
|
||||
@ifset PROOF
|
||||
@strong{<XREF>} \string\ @strong{</>}
|
||||
@end ifset
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
A @dfn{snapshot file} (or @dfn{directory file}) is created during
|
||||
incremental backups (@pxref{Incremental Dumps}). It
|
||||
contains the status of the filesystem at the time of the dump and is
|
||||
contains the status of the file system at the time of the dump and is
|
||||
used to determine which files were modified since the last backup.
|
||||
|
||||
@GNUTAR{} version @value{VERSION} supports two snapshot file
|
||||
@@ -47,7 +47,7 @@ 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.
|
||||
|
||||
Following lines contain directory metadate, one line per
|
||||
Following lines contain directory metadata, one line per
|
||||
directory. The line format is:
|
||||
|
||||
@smallexample
|
||||
|
||||
235
doc/sparse.texi
Normal file
235
doc/sparse.texi
Normal file
@@ -0,0 +1,235 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 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 sparse formats
|
||||
@cindex sparse versions
|
||||
The notion of sparse file, and the ways of handling it from the point
|
||||
of view of @GNUTAR{} user have been described in detail in
|
||||
@ref{sparse}. This chapter describes the internal format @GNUTAR{}
|
||||
uses to store such files.
|
||||
|
||||
The support for sparse files in @GNUTAR{} has a long history. The
|
||||
earliest version featuring this support that I was able to find was 1.09,
|
||||
released in November, 1990. The format introduced back then is called
|
||||
@dfn{old GNU} sparse format and in spite of the fact that its design
|
||||
contained many flaws, it was the only format @GNUTAR{} supported
|
||||
until version 1.14 (May, 2004), which introduced initial support for
|
||||
sparse archives in @acronym{PAX} archives (@pxref{posix}). This
|
||||
format was not free from design flows, either and it was subsequently
|
||||
improved in versions 1.15.2 (November, 2005) and 1.15.92 (June,
|
||||
2006).
|
||||
|
||||
In addition to GNU sparse format, @GNUTAR{} is able to read and
|
||||
extract sparse files archived by @command{star}.
|
||||
|
||||
The following subsections describe each format in detail.
|
||||
|
||||
@menu
|
||||
* Old GNU Format::
|
||||
* PAX 0:: PAX Format, Versions 0.0 and 0.1
|
||||
* PAX 1:: PAX Format, Version 1.0
|
||||
@end menu
|
||||
|
||||
@node Old GNU Format
|
||||
@appendixsubsec Old GNU Format
|
||||
|
||||
@cindex sparse formats, Old GNU
|
||||
@cindex Old GNU sparse format
|
||||
The format introduced some time around 1990 (v. 1.09). It was
|
||||
designed on top of standard @code{ustar} headers in such an
|
||||
unfortunate way that some of its fields overwrote fields required by
|
||||
POSIX.
|
||||
|
||||
An old GNU sparse header is designated by type @samp{S}
|
||||
(@code{GNUTYPE_SPARSE}) and has the following layout:
|
||||
|
||||
@multitable @columnfractions 0.10 0.10 0.20 0.20 0.40
|
||||
@headitem Offset @tab Size @tab Name @tab Data type @tab Contents
|
||||
@item 0 @tab 345 @tab @tab N/A @tab Not used.
|
||||
@item 345 @tab 12 @tab atime @tab Number @tab @code{atime} of the file.
|
||||
@item 357 @tab 12 @tab ctime @tab Number @tab @code{ctime} of the file .
|
||||
@item 369 @tab 12 @tab offset @tab Number @tab For
|
||||
multivolume archives: the offset of the start of this volume.
|
||||
@item 381 @tab 4 @tab @tab N/A @tab Not used.
|
||||
@item 385 @tab 1 @tab @tab N/A @tab Not used.
|
||||
@item 386 @tab 96 @tab sp @tab @code{sparse_header} @tab (4 entries) File map.
|
||||
@item 482 @tab 1 @tab isextended @tab Bool @tab @code{1} if an
|
||||
extension sparse header follows, @code{0} otherwise.
|
||||
@item 483 @tab 12 @tab realsize @tab Number @tab Real size of the file.
|
||||
@end multitable
|
||||
|
||||
Each of @code{sparse_header} object at offset 386 describes a single
|
||||
data chunk. It has the following structure:
|
||||
|
||||
@multitable @columnfractions 0.10 0.10 0.20 0.60
|
||||
@headitem Offset @tab Size @tab Data type @tab Contents
|
||||
@item 0 @tab 12 @tab Number @tab Offset of the
|
||||
beginning of the chunk.
|
||||
@item 12 @tab 12 @tab Number @tab Size of the chunk.
|
||||
@end multitable
|
||||
|
||||
If the member contains more than four chunks, the @code{isextended}
|
||||
field of the header has the value @code{1} and the main header is
|
||||
followed by one or more @dfn{extension headers}. Each such header has
|
||||
the following structure:
|
||||
|
||||
@multitable @columnfractions 0.10 0.10 0.20 0.20 0.40
|
||||
@headitem Offset @tab Size @tab Name @tab Data type @tab Contents
|
||||
@item 0 @tab 21 @tab sp @tab @code{sparse_header} @tab
|
||||
(21 entires) File map.
|
||||
@item 504 @tab 1 @tab isextended @tab Bool @tab @code{1} if an
|
||||
extension sparse header follows, or @code{0} otherwise.
|
||||
@end multitable
|
||||
|
||||
A header with @code{isextended=0} ends the map.
|
||||
|
||||
@node PAX 0
|
||||
@appendixsubsec PAX Format, Versions 0.0 and 0.1
|
||||
|
||||
@cindex sparse formats, v.0.0
|
||||
There are two formats available in this branch. The version @code{0.0}
|
||||
is the initial version of sparse format used by @command{tar}
|
||||
versions 1.14--1.15.1. The sparse file map is kept in extended
|
||||
(@code{x}) PAX header variables:
|
||||
|
||||
@table @code
|
||||
@vrindex GNU.sparse.size, extended header variable
|
||||
@item GNU.sparse.size
|
||||
Real size of the stored file
|
||||
|
||||
@item GNU.sparse.numblocks
|
||||
@vrindex GNU.sparse.numblocks, extended header variable
|
||||
Number of blocks in the sparse map
|
||||
|
||||
@item GNU.sparse.offset
|
||||
@vrindex GNU.sparse.offset, extended header variable
|
||||
Offset of the data block
|
||||
|
||||
@item GNU.sparse.numbytes
|
||||
@vrindex GNU.sparse.numbytes, extended header variable
|
||||
Size of the data block
|
||||
@end table
|
||||
|
||||
The latter two variables repeat for each data block, so the overall
|
||||
structure is like this:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
GNU.sparse.size=@var{size}
|
||||
GNU.sparse.numblocks=@var{numblocks}
|
||||
repeat @var{numblocks} times
|
||||
GNU.sparse.offset=@var{offset}
|
||||
GNU.sparse.numbytes=@var{numbytes}
|
||||
end repeat
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
This format presented the following two problems:
|
||||
|
||||
@enumerate 1
|
||||
@item
|
||||
Whereas the POSIX specification allows a variable to appear multiple
|
||||
times in a header, it requires that only the last occurrence be
|
||||
meaningful. Thus, multiple occurrences of @code{GNU.sparse.offset} and
|
||||
@code{GNU.sparse.numbytes} are conflicting with the POSIX specs.
|
||||
|
||||
@item
|
||||
Attempting to extract such archives using a third-party @command{tar}s
|
||||
results in extraction of sparse files in @emph{compressed form}. If
|
||||
the @command{tar} implementation in question does not support POSIX
|
||||
format, it will also extract a file containing extension header
|
||||
attributes. This file can be used to expand the file to its original
|
||||
state. However, posix-aware @command{tar}s will usually ignore the
|
||||
unknown variables, which makes restoring the file more
|
||||
difficult. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
members in v.0.0 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
@end enumerate
|
||||
|
||||
@cindex sparse formats, v.0.1
|
||||
@GNUTAR{} 1.15.2 introduced sparse format version @code{0.1}, which
|
||||
attempted to solve these problems. As its predecessor, this format
|
||||
stores sparse map in the extended POSIX header. It retains
|
||||
@code{GNU.sparse.size} and @code{GNU.sparse.numblocks} variables, but
|
||||
instead of @code{GNU.sparse.offset}/@code{GNU.sparse.numbytes} pairs
|
||||
it uses a single variable:
|
||||
|
||||
@table @code
|
||||
@item GNU.sparse.map
|
||||
@vrindex GNU.sparse.map, extended header variable
|
||||
Map of non-null data chunks. It is a string consisting of
|
||||
comma-separated values "@var{offset},@var{size}[,@var{offset-1},@var{size-1}...]"
|
||||
@end table
|
||||
|
||||
To address the 2nd problem, the @code{name} field in @code{ustar}
|
||||
is replaced with a special name, constructed using the following pattern:
|
||||
|
||||
@smallexample
|
||||
%d/GNUSparseFile.%p/%f
|
||||
@end smallexample
|
||||
|
||||
@vrindex GNU.sparse.name, extended header variable
|
||||
The real name of the sparse file is stored in the variable
|
||||
@code{GNU.sparse.name}. Thus, those @command{tar} implementations
|
||||
that are not aware of GNU extensions will at least extract the files
|
||||
into separate directories, giving the user a possibility to expand it
|
||||
afterwards. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
members in v.0.1 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
|
||||
The resulting @code{GNU.sparse.map} string can be @emph{very} long.
|
||||
Although POSIX does not impose any limit on the length of a @code{x}
|
||||
header variable, this possibly can confuse some tars.
|
||||
|
||||
@node PAX 1
|
||||
@appendixsubsec PAX Format, Version 1.0
|
||||
|
||||
@cindex sparse formats, v.1.0
|
||||
The version @code{1.0} of sparse format was introduced with @GNUTAR{}
|
||||
1.15.92. Its main objective was to make the resulting file
|
||||
extractable with little effort even by non-posix aware @command{tar}
|
||||
implementations. Starting from this version, the extended header
|
||||
preceding a sparse member always contains the following variables that
|
||||
identify the format being used:
|
||||
|
||||
@table @code
|
||||
@item GNU.sparse.major
|
||||
@vrindex GNU.sparse.major, extended header variable
|
||||
Major version
|
||||
|
||||
@item GNU.sparse.minor
|
||||
@vrindex GNU.sparse.minor, extended header variable
|
||||
Minor version
|
||||
@end table
|
||||
|
||||
The @code{name} field in @code{ustar} header contains a special name,
|
||||
constructed using the following pattern:
|
||||
|
||||
@smallexample
|
||||
%d/GNUSparseFile.%p/%f
|
||||
@end smallexample
|
||||
|
||||
@vrindex GNU.sparse.name, extended header variable, in v.1.0
|
||||
@vrindex GNU.sparse.realsize, extended header variable
|
||||
The real name of the sparse file is stored in the variable
|
||||
@code{GNU.sparse.name}. The real size of the file is stored in the
|
||||
variable @code{GNU.sparse.realsize}.
|
||||
|
||||
The sparse map itself is stored in the file data block, preceding the actual
|
||||
file data. It consists of a series of octal numbers of arbitrary length, delimited
|
||||
by newlines. The map is padded with nulls to the nearest block boundary.
|
||||
|
||||
The first number gives the number of entries in the map. Following are map entries,
|
||||
each one consisting of two numbers giving the offset and size of the
|
||||
data block it describes.
|
||||
|
||||
The format is designed in such a way that non-posix aware tars and tars not
|
||||
supporting @code{GNU.sparse.*} keywords will extract each sparse file
|
||||
in its condensed form with the file map prepended and will place it
|
||||
into a separate directory. Then, using a simple program it would be
|
||||
possible to expand the file to its original form even without @GNUTAR{}.
|
||||
@xref{Sparse Recovery}, for the detailed information on how to extract
|
||||
sparse members without @GNUTAR{}.
|
||||
|
||||
4389
doc/tar.texi
4389
doc/tar.texi
File diff suppressed because it is too large
Load Diff
26
doc/texify.sed
Normal file
26
doc/texify.sed
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2006 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 2, 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
|
||||
|
||||
1{s,/\*,@comment ,
|
||||
b
|
||||
}
|
||||
2,/.*\*\//{s,\*/,,;s/^/@comment/
|
||||
b
|
||||
}
|
||||
/\/* END \*\//,$d
|
||||
s/\([{}]\)/@\1/g
|
||||
s,/\*,&@r{,
|
||||
s,\*/,}&,
|
||||
@@ -1,9 +1,22 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright (C) 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
@c 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
@c 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
@acronym{GNU} @command{tar}
|
||||
@end macro
|
||||
|
||||
@macro xopindex{option,text}
|
||||
@opindex \option\@r{, \text\}
|
||||
@end macro
|
||||
|
||||
@macro opsummary{option}
|
||||
@ifclear ANCHOR--\option\
|
||||
@set ANCHOR--\option\ 1
|
||||
@anchor{--\option\}
|
||||
@end ifclear
|
||||
@xopindex{\option\, summary}
|
||||
@end macro
|
||||
|
||||
|
||||
|
||||
@@ -22,9 +22,11 @@ gettext
|
||||
gettime
|
||||
hash
|
||||
human
|
||||
inttypes
|
||||
lchown
|
||||
localcharset
|
||||
memset
|
||||
mkdtemp
|
||||
modechange
|
||||
obstack
|
||||
quote
|
||||
@@ -37,6 +39,7 @@ savedir
|
||||
setenv
|
||||
stat-time
|
||||
stdbool
|
||||
stdint
|
||||
stpcpy
|
||||
strdup
|
||||
strtol
|
||||
|
||||
@@ -26,6 +26,7 @@ argp-pvh.c
|
||||
argp-xinl.c
|
||||
argp.h
|
||||
asnprintf.c
|
||||
at-func.c
|
||||
backupfile.c
|
||||
backupfile.h
|
||||
basename.c
|
||||
@@ -33,9 +34,12 @@ charset.alias
|
||||
chdir-long.c
|
||||
chdir-long.h
|
||||
chown.c
|
||||
close-stream.c
|
||||
close-stream.h
|
||||
closeout.c
|
||||
closeout.h
|
||||
config.charset
|
||||
configmake.h
|
||||
creat-safer.c
|
||||
dirname.c
|
||||
dirname.h
|
||||
@@ -47,9 +51,12 @@ exclude.h
|
||||
exit.h
|
||||
exitfail.c
|
||||
exitfail.h
|
||||
fchmodat.c
|
||||
fchown-stub.c
|
||||
fcntl--.h
|
||||
fcntl-safer.h
|
||||
fcntl.h
|
||||
fcntl_.h
|
||||
fd-safer.c
|
||||
fileblocks.c
|
||||
fnmatch.c
|
||||
@@ -85,11 +92,15 @@ imaxtostr.c
|
||||
intprops.h
|
||||
inttostr.c
|
||||
inttostr.h
|
||||
inttypes.h
|
||||
inttypes_.h
|
||||
lchown.c
|
||||
lchown.h
|
||||
localcharset.c
|
||||
localcharset.h
|
||||
localedir.h
|
||||
lstat.c
|
||||
lstat.h
|
||||
malloc.c
|
||||
mbchar.c
|
||||
mbchar.h
|
||||
@@ -102,6 +113,8 @@ memrchr.h
|
||||
memset.c
|
||||
minmax.h
|
||||
mkdirat.c
|
||||
mkdtemp.c
|
||||
mkdtemp.h
|
||||
mktime.c
|
||||
modechange.c
|
||||
modechange.h
|
||||
@@ -155,6 +168,8 @@ stat-macros.h
|
||||
stat-time.h
|
||||
stdbool.h
|
||||
stdbool_.h
|
||||
stdint.h
|
||||
stdint_.h
|
||||
stpcpy.c
|
||||
stpcpy.h
|
||||
strcase.h
|
||||
@@ -178,6 +193,7 @@ strtoul.c
|
||||
strtoull.c
|
||||
strtoumax.c
|
||||
sysexit_.h
|
||||
sysexits.h
|
||||
system-ioctl.h
|
||||
system.h
|
||||
time_r.c
|
||||
@@ -201,12 +217,15 @@ version-etc.c
|
||||
version-etc.h
|
||||
vsnprintf.c
|
||||
vsnprintf.h
|
||||
wcwidth.h
|
||||
xalloc-die.c
|
||||
xalloc.h
|
||||
xgetcwd.c
|
||||
xgetcwd.h
|
||||
xmalloc.c
|
||||
xsize.h
|
||||
xstrndup.c
|
||||
xstrndup.h
|
||||
xstrtol.c
|
||||
xstrtol.h
|
||||
xstrtoul.c
|
||||
|
||||
@@ -37,6 +37,7 @@ libtar_a_LIBADD = $(LIBOBJS) $(ALLOCA)
|
||||
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
|
||||
|
||||
BUILT_SOURCES =
|
||||
AM_CPPFLAGS =
|
||||
EXTRA_DIST = Makefile.tmpl
|
||||
MAINTAINERCLEANFILES =
|
||||
MOSTLYCLEANFILES =
|
||||
|
||||
@@ -2,6 +2,7 @@ index.html
|
||||
*.po
|
||||
LINGUAS
|
||||
Makefile.in.in
|
||||
Makevars
|
||||
Makevars.template
|
||||
Rules-quot
|
||||
boldquot.sed
|
||||
|
||||
41
po/Makevars
41
po/Makevars
@@ -1,41 +0,0 @@
|
||||
# Makefile variables for PO directory in any package using GNU gettext.
|
||||
|
||||
# Usually the message domain is the same as the package name.
|
||||
DOMAIN = $(PACKAGE)
|
||||
|
||||
# These two variables depend on the location of this directory.
|
||||
subdir = po
|
||||
top_builddir = ..
|
||||
|
||||
# These options get passed to xgettext.
|
||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
|
||||
|
||||
# This is the copyright holder that gets inserted into the header of the
|
||||
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
|
||||
# package. (Note that the msgstr strings, extracted from the package's
|
||||
# sources, belong to the copyright holder of the package.) Translators are
|
||||
# expected to transfer the copyright for their translations to this person
|
||||
# or entity, or to disclaim their copyright. The empty string stands for
|
||||
# the public domain; in this case the translators are expected to disclaim
|
||||
# their copyright.
|
||||
COPYRIGHT_HOLDER = Free Software Foundation, Inc.
|
||||
|
||||
# This is the email address or URL to which the translators shall report
|
||||
# bugs in the untranslated strings:
|
||||
# - Strings which are not entire sentences, see the maintainer guidelines
|
||||
# in the GNU gettext documentation, section 'Preparing Strings'.
|
||||
# - Strings which use unclear terms or require additional context to be
|
||||
# understood.
|
||||
# - Strings which make invalid assumptions about notation of date, time or
|
||||
# money.
|
||||
# - Pluralisation problems.
|
||||
# - Incorrect English spelling.
|
||||
# - Incorrect formatting.
|
||||
# It can be your email address, or a mailing list address where translators
|
||||
# can write to without being subscribed, or the URL of a web page through
|
||||
# which the translators can contact you.
|
||||
MSGID_BUGS_ADDRESS = bug-tar@gnu.org
|
||||
|
||||
# This is the list of locale categories, beyond LC_MESSAGES, for which the
|
||||
# message catalogs shall be used. It is usually empty.
|
||||
EXTRA_LOCALE_CATEGORIES =
|
||||
468
scripts/xsparse.c
Normal file
468
scripts/xsparse.c
Normal file
@@ -0,0 +1,468 @@
|
||||
/* xsparse - expands compressed sparse file images extracted from GNU tar
|
||||
archives.
|
||||
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Bound on length of the string representing an off_t.
|
||||
See INT_STRLEN_BOUND in intprops.h for explanation */
|
||||
#define OFF_T_STRLEN_BOUND ((sizeof (off_t) * CHAR_BIT) * 146 / 485 + 1)
|
||||
#define OFF_T_STRSIZE_BOUND (OFF_T_STRLEN_BOUND+1)
|
||||
|
||||
#define BLOCKSIZE 512
|
||||
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
};
|
||||
|
||||
char *progname;
|
||||
int verbose;
|
||||
|
||||
void
|
||||
die (int code, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
exit (code);
|
||||
}
|
||||
|
||||
void *
|
||||
emalloc (size_t size)
|
||||
{
|
||||
char *p = malloc (size);
|
||||
if (!p)
|
||||
die (1, "not enough memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
off_t
|
||||
string_to_off (char *p, char **endp)
|
||||
{
|
||||
off_t v = 0;
|
||||
|
||||
for (; *p; p++)
|
||||
{
|
||||
int digit = *p - '0';
|
||||
off_t x = v * 10;
|
||||
if (9 < (unsigned) digit)
|
||||
{
|
||||
if (endp)
|
||||
{
|
||||
*endp = p;
|
||||
break;
|
||||
}
|
||||
die (1, "number parse error near %s", p);
|
||||
}
|
||||
else if (x / 10 != v)
|
||||
die (1, "number out of allowed range, near %s", p);
|
||||
v = x + digit;
|
||||
if (v < 0)
|
||||
die (1, "negative number");
|
||||
}
|
||||
if (endp)
|
||||
*endp = p;
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t
|
||||
string_to_size (char *p, char **endp)
|
||||
{
|
||||
off_t v = string_to_off (p, endp);
|
||||
size_t ret = v;
|
||||
if (ret != v)
|
||||
die (1, "number too big");
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t sparse_map_size;
|
||||
struct sp_array *sparse_map;
|
||||
|
||||
void
|
||||
get_line (char *s, int size, FILE *stream)
|
||||
{
|
||||
char *p = fgets (s, size, stream);
|
||||
size_t len;
|
||||
|
||||
if (!p)
|
||||
die (1, "unexpected end of file");
|
||||
len = strlen (p);
|
||||
if (s[len - 1] != '\n')
|
||||
die (1, "buffer overflow");
|
||||
s[len - 1] = 0;
|
||||
}
|
||||
|
||||
int
|
||||
get_var (FILE *fp, char **name, char **value)
|
||||
{
|
||||
static char *buffer;
|
||||
static size_t bufsize = OFF_T_STRSIZE_BOUND;
|
||||
char *p, *q;
|
||||
|
||||
buffer = emalloc (bufsize);
|
||||
do
|
||||
{
|
||||
size_t len, s;
|
||||
|
||||
if (!fgets (buffer, bufsize, fp))
|
||||
return 0;
|
||||
len = strlen (buffer);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
s = string_to_size (buffer, &p);
|
||||
if (*p != ' ')
|
||||
die (1, "malformed header: expected space but found %s", p);
|
||||
if (buffer[len-1] != '\n')
|
||||
{
|
||||
if (bufsize < s + 1)
|
||||
{
|
||||
bufsize = s + 1;
|
||||
buffer = realloc (buffer, bufsize);
|
||||
if (!buffer)
|
||||
die (1, "not enough memory");
|
||||
}
|
||||
if (!fgets (buffer + len, s - len + 1, fp))
|
||||
die (1, "unexpected end of file or read error");
|
||||
}
|
||||
p++;
|
||||
}
|
||||
while (memcmp (p, "GNU.sparse.", 11));
|
||||
|
||||
p += 11;
|
||||
q = strchr (p, '=');
|
||||
if (!q)
|
||||
die (1, "malformed header: expected `=' not found");
|
||||
*q++ = 0;
|
||||
q[strlen (q) - 1] = 0;
|
||||
*name = p;
|
||||
*value = q;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *outname;
|
||||
off_t outsize;
|
||||
unsigned version_major;
|
||||
unsigned version_minor;
|
||||
|
||||
void
|
||||
read_xheader (char *name)
|
||||
{
|
||||
char *kw, *val;
|
||||
FILE *fp = fopen (name, "r");
|
||||
char *expect = NULL;
|
||||
size_t i = 0;
|
||||
|
||||
if (verbose)
|
||||
printf ("Reading extended header file\n");
|
||||
|
||||
while (get_var (fp, &kw, &val))
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Found variable GNU.sparse.%s = %s\n", kw, val);
|
||||
|
||||
if (expect && strcmp (kw, expect))
|
||||
die (1, "bad keyword sequence: expected `%s' but found `%s'",
|
||||
expect, kw);
|
||||
expect = NULL;
|
||||
if (strcmp (kw, "name") == 0)
|
||||
{
|
||||
outname = emalloc (strlen (val) + 1);
|
||||
strcpy (outname, val);
|
||||
}
|
||||
else if (strcmp (kw, "major") == 0)
|
||||
{
|
||||
version_major = string_to_size (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "minor") == 0)
|
||||
{
|
||||
version_minor = string_to_size (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "realsize") == 0
|
||||
|| strcmp (kw, "size") == 0)
|
||||
{
|
||||
outsize = string_to_off (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "numblocks") == 0)
|
||||
{
|
||||
sparse_map_size = string_to_size (val, NULL);
|
||||
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
|
||||
}
|
||||
else if (strcmp (kw, "offset") == 0)
|
||||
{
|
||||
sparse_map[i].offset = string_to_off (val, NULL);
|
||||
expect = "numbytes";
|
||||
}
|
||||
else if (strcmp (kw, "numbytes") == 0)
|
||||
{
|
||||
sparse_map[i++].numbytes = string_to_size (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "map") == 0)
|
||||
{
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
{
|
||||
sparse_map[i].offset = string_to_off (val, &val);
|
||||
if (*val != ',')
|
||||
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
|
||||
*val);
|
||||
sparse_map[i].numbytes = string_to_size (val+1, &val);
|
||||
if (*val != ',')
|
||||
{
|
||||
if (!(*val == 0 && i == sparse_map_size-1))
|
||||
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
|
||||
*val);
|
||||
}
|
||||
else
|
||||
val++;
|
||||
}
|
||||
if (*val)
|
||||
die (1, "bad GNU.sparse.map: garbage at the end");
|
||||
}
|
||||
}
|
||||
if (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)
|
||||
die (1, "not all sparse entries supplied");
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
void
|
||||
read_map (FILE *ifp)
|
||||
{
|
||||
size_t i;
|
||||
char nbuf[OFF_T_STRSIZE_BOUND];
|
||||
|
||||
if (verbose)
|
||||
printf ("Reading v.1.0 sparse map\n");
|
||||
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map_size = string_to_size (nbuf, NULL);
|
||||
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
{
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map[i].offset = string_to_off (nbuf, NULL);
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map[i].numbytes = string_to_size (nbuf, NULL);
|
||||
}
|
||||
|
||||
fseek (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
|
||||
SEEK_SET);
|
||||
}
|
||||
|
||||
void
|
||||
expand_sparse (FILE *sfp, int ofd)
|
||||
{
|
||||
size_t i;
|
||||
size_t maxbytes = 0;
|
||||
char *buffer;
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
if (maxbytes < sparse_map[i].numbytes)
|
||||
maxbytes = sparse_map[i].numbytes;
|
||||
|
||||
for (buffer = malloc (maxbytes); !buffer; maxbytes /= 2)
|
||||
if (maxbytes == 0)
|
||||
die (1, "not enough memory");
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
{
|
||||
size_t size = sparse_map[i].numbytes;
|
||||
|
||||
lseek (ofd, sparse_map[i].offset, SEEK_SET);
|
||||
while (size)
|
||||
{
|
||||
size_t rdsize = (size < maxbytes) ? size : maxbytes;
|
||||
if (rdsize != fread (buffer, 1, rdsize, sfp))
|
||||
die (1, "read error (%d)", errno);
|
||||
if (rdsize != write (ofd, buffer, rdsize))
|
||||
die (1, "write error (%d)", errno);
|
||||
size -= rdsize;
|
||||
}
|
||||
}
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
usage (int code)
|
||||
{
|
||||
printf ("Usage: %s [OPTIONS] infile [outfile]\n", progname);
|
||||
printf ("%s: expand sparse files extracted from GNU archives\n",
|
||||
progname);
|
||||
printf ("\nOPTIONS are:\n\n");
|
||||
printf (" -h Display this help list\n");
|
||||
printf (" -n Dry run: do nothing, print what would have been done\n");
|
||||
printf (" -v Increase verbosity level\n");
|
||||
printf (" -x FILE Parse extended header FILE\n\n");
|
||||
|
||||
exit (code);
|
||||
}
|
||||
|
||||
void
|
||||
guess_outname (char *name)
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
|
||||
if (name[0] == '.' && name[1] == '/')
|
||||
name += 2;
|
||||
|
||||
p = name + strlen (name) - 1;
|
||||
s = NULL;
|
||||
|
||||
for (; p > name && *p != '/'; p--)
|
||||
;
|
||||
if (*p == '/')
|
||||
s = p + 1;
|
||||
if (p != name)
|
||||
{
|
||||
for (p--; p > name && *p != '/'; p--)
|
||||
;
|
||||
}
|
||||
|
||||
if (*p != '/')
|
||||
{
|
||||
if (s)
|
||||
outname = s;
|
||||
else
|
||||
{
|
||||
outname = emalloc (4 + strlen (name));
|
||||
strcpy (outname, "../");
|
||||
strcpy (outname + 3, name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t len = p - name + 1;
|
||||
outname = emalloc (len + strlen (s) + 1);
|
||||
memcpy (outname, name, len);
|
||||
strcpy (outname + len, s);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
int dry_run = 0;
|
||||
char *xheader_file = NULL;
|
||||
char *inname;
|
||||
FILE *ifp;
|
||||
struct stat st;
|
||||
int ofd;
|
||||
|
||||
progname = argv[0];
|
||||
while ((c = getopt (argc, argv, "hnvx:")) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'h':
|
||||
usage (0);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
xheader_file = optarg;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
dry_run = 1;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
default:
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0 || argc > 2)
|
||||
usage (1);
|
||||
|
||||
if (xheader_file)
|
||||
read_xheader (xheader_file);
|
||||
|
||||
inname = argv[0];
|
||||
if (argv[1])
|
||||
outname = argv[1];
|
||||
|
||||
if (stat (inname, &st))
|
||||
die (1, "cannot stat %s (%d)", inname, errno);
|
||||
|
||||
ifp = fopen (inname, "r");
|
||||
if (ifp == NULL)
|
||||
die (1, "cannot open file %s (%d)", inname, errno);
|
||||
|
||||
if (!xheader_file || version_major == 1)
|
||||
read_map (ifp);
|
||||
|
||||
if (!outname)
|
||||
guess_outname (inname);
|
||||
|
||||
ofd = open (outname, O_RDWR|O_CREAT|O_TRUNC, st.st_mode);
|
||||
if (ofd == -1)
|
||||
die (1, "cannot open file %s (%d)", outname, errno);
|
||||
|
||||
if (verbose)
|
||||
printf ("Expanding file `%s' to `%s'\n", inname, outname);
|
||||
|
||||
if (dry_run)
|
||||
{
|
||||
printf ("Finished dry run\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
expand_sparse (ifp, ofd);
|
||||
|
||||
fclose (ifp);
|
||||
close (ofd);
|
||||
|
||||
if (verbose)
|
||||
printf ("Done\n");
|
||||
|
||||
if (outsize)
|
||||
{
|
||||
if (stat (outname, &st))
|
||||
die (1, "cannot stat output file %s (%d)", outname, errno);
|
||||
if (st.st_size != outsize)
|
||||
die (1, "expanded file has wrong size");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ tar_SOURCES = \
|
||||
sparse.c\
|
||||
system.c\
|
||||
tar.c\
|
||||
transform.c\
|
||||
update.c\
|
||||
utf8.c
|
||||
|
||||
|
||||
254
src/buffer.c
254
src/buffer.c
@@ -56,6 +56,8 @@ union block *current_block; /* current block of archive */
|
||||
enum access_mode access_mode; /* how do we handle the archive */
|
||||
off_t records_read; /* number of records read from this archive */
|
||||
off_t records_written; /* likewise, for records written */
|
||||
extern off_t records_skipped; /* number of records skipped at the start
|
||||
of the archive, defined in delete.c */
|
||||
|
||||
static off_t record_start_block; /* block ordinal at record_start */
|
||||
|
||||
@@ -74,7 +76,7 @@ static int read_error_count;
|
||||
static bool hit_eof;
|
||||
|
||||
/* Checkpointing counter */
|
||||
static int checkpoint;
|
||||
static unsigned checkpoint;
|
||||
|
||||
static bool read_full_records = false;
|
||||
|
||||
@@ -166,6 +168,15 @@ void
|
||||
set_start_time ()
|
||||
{
|
||||
gettime (&start_time);
|
||||
volume_start_time = start_time;
|
||||
last_stat_time = start_time;
|
||||
}
|
||||
|
||||
void
|
||||
set_volume_start_time ()
|
||||
{
|
||||
gettime (&volume_start_time);
|
||||
last_stat_time = volume_start_time;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -173,9 +184,9 @@ compute_duration ()
|
||||
{
|
||||
struct timespec now;
|
||||
gettime (&now);
|
||||
duration += ((now.tv_sec - start_time.tv_sec)
|
||||
+ (now.tv_nsec - start_time.tv_nsec) / 1e9);
|
||||
set_start_time ();
|
||||
duration += ((now.tv_sec - last_stat_time.tv_sec)
|
||||
+ (now.tv_nsec - last_stat_time.tv_nsec) / 1e9);
|
||||
gettime (&last_stat_time);
|
||||
}
|
||||
|
||||
|
||||
@@ -274,26 +285,65 @@ open_compressed_archive ()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_total_written (void)
|
||||
static void
|
||||
print_stats (FILE *fp, const char *text, tarlong numbytes)
|
||||
{
|
||||
tarlong written = prev_written + bytes_written;
|
||||
char bytes[sizeof (tarlong) * CHAR_BIT];
|
||||
char abbr[LONGEST_HUMAN_READABLE + 1];
|
||||
char rate[LONGEST_HUMAN_READABLE + 1];
|
||||
|
||||
int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
|
||||
|
||||
sprintf (bytes, TARLONG_FORMAT, written);
|
||||
sprintf (bytes, TARLONG_FORMAT, numbytes);
|
||||
|
||||
/* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
|
||||
fprintf (stderr, _("Total bytes written: %s (%s, %s/s)\n"), bytes,
|
||||
human_readable (written, abbr, human_opts, 1, 1),
|
||||
(0 < duration && written / duration < (uintmax_t) -1
|
||||
? human_readable (written / duration, rate, human_opts, 1, 1)
|
||||
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)
|
||||
: "?"));
|
||||
}
|
||||
|
||||
void
|
||||
print_total_stats ()
|
||||
{
|
||||
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);
|
||||
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));
|
||||
}
|
||||
break;
|
||||
|
||||
case EXTRACT_SUBCOMMAND:
|
||||
case LIST_SUBCOMMAND:
|
||||
case DIFF_SUBCOMMAND:
|
||||
print_stats (stderr, _("Total bytes read"),
|
||||
records_read * record_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute and return the block ordinal at current_block. */
|
||||
off_t
|
||||
current_block_ordinal (void)
|
||||
@@ -386,16 +436,6 @@ _open_archive (enum access_mode wanted_access)
|
||||
{
|
||||
int backed_up_flag = 0;
|
||||
|
||||
if (index_file_name)
|
||||
{
|
||||
stdlis = freopen (index_file_name, "w", stdout);
|
||||
if (! stdlis)
|
||||
open_error (index_file_name);
|
||||
close_stdout_set_file_name (index_file_name);
|
||||
}
|
||||
else
|
||||
stdlis = to_stdout_option ? stderr : stdout;
|
||||
|
||||
if (record_size == 0)
|
||||
FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
|
||||
|
||||
@@ -435,7 +475,8 @@ _open_archive (enum access_mode wanted_access)
|
||||
break;
|
||||
}
|
||||
|
||||
if (wanted_access == ACCESS_WRITE
|
||||
if (!index_file_name
|
||||
&& wanted_access == ACCESS_WRITE
|
||||
&& strcmp (archive_name_array[0], "-") == 0)
|
||||
stdlis = stderr;
|
||||
}
|
||||
@@ -463,13 +504,16 @@ _open_archive (enum access_mode wanted_access)
|
||||
|
||||
case ACCESS_WRITE:
|
||||
archive = STDOUT_FILENO;
|
||||
stdlis = stderr;
|
||||
if (!index_file_name)
|
||||
stdlis = stderr;
|
||||
break;
|
||||
|
||||
case ACCESS_UPDATE:
|
||||
archive = STDIN_FILENO;
|
||||
stdlis = stderr;
|
||||
write_archive_to_stdout = true;
|
||||
record_end = record_start; /* set up for 1st record = # 0 */
|
||||
if (!index_file_name)
|
||||
stdlis = stderr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -494,8 +538,13 @@ _open_archive (enum access_mode wanted_access)
|
||||
break;
|
||||
|
||||
case ACCESS_UPDATE:
|
||||
archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
|
||||
archive = rmtopen (archive_name_array[0],
|
||||
O_RDWR | O_CREAT | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
|
||||
if (check_compressed_archive () != ct_none)
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("Cannot update compressed archives")));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -516,33 +565,54 @@ _open_archive (enum access_mode wanted_access)
|
||||
|
||||
switch (wanted_access)
|
||||
{
|
||||
case ACCESS_UPDATE:
|
||||
records_written = 0;
|
||||
record_end = record_start; /* set up for 1st record = # 0 */
|
||||
|
||||
case ACCESS_READ:
|
||||
find_next_block (); /* read it in, check for EOF */
|
||||
break;
|
||||
|
||||
case ACCESS_UPDATE:
|
||||
case ACCESS_WRITE:
|
||||
records_written = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_checkpoint (bool write)
|
||||
{
|
||||
if (checkpoint_option && !(++checkpoint % checkpoint_option))
|
||||
{
|
||||
switch (checkpoint_style)
|
||||
{
|
||||
case checkpoint_dot:
|
||||
fputc ('.', stdlis);
|
||||
fflush (stdlis);
|
||||
break;
|
||||
|
||||
case checkpoint_text:
|
||||
if (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'' */
|
||||
WARN ((0, 0, _("Write checkpoint %u"), checkpoint));
|
||||
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'' */
|
||||
WARN ((0, 0, _("Read checkpoint %u"), checkpoint));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform a write to flush the buffer. */
|
||||
ssize_t
|
||||
_flush_write (void)
|
||||
{
|
||||
ssize_t status;
|
||||
|
||||
if (checkpoint_option && !(++checkpoint % 10))
|
||||
/* 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'' */
|
||||
WARN ((0, 0, _("Write checkpoint %d"), checkpoint));
|
||||
|
||||
do_checkpoint (true);
|
||||
if (tape_length_option && tape_length_option <= bytes_written)
|
||||
{
|
||||
errno = ENOSPC;
|
||||
@@ -567,7 +637,7 @@ archive_write_error (ssize_t status)
|
||||
if (totals_option)
|
||||
{
|
||||
int e = errno;
|
||||
print_total_written ();
|
||||
print_total_stats ();
|
||||
errno = e;
|
||||
}
|
||||
|
||||
@@ -646,39 +716,6 @@ short_read (size_t status)
|
||||
records_read++;
|
||||
}
|
||||
|
||||
/* Perform a read to flush the buffer. */
|
||||
size_t
|
||||
_flush_read (void)
|
||||
{
|
||||
size_t status; /* result from system call */
|
||||
|
||||
if (checkpoint_option && !(++checkpoint % 10))
|
||||
/* 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'' */
|
||||
WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
|
||||
|
||||
/* Clear the count of errors. This only applies to a single call to
|
||||
flush_read. */
|
||||
|
||||
read_error_count = 0; /* clear error count */
|
||||
|
||||
if (write_archive_to_stdout && record_start_block != 0)
|
||||
{
|
||||
archive = STDOUT_FILENO;
|
||||
status = sys_write_archive_buffer ();
|
||||
archive = STDIN_FILENO;
|
||||
if (status != record_size)
|
||||
archive_write_error (status);
|
||||
}
|
||||
|
||||
status = rmtread (archive, record_start->buffer, record_size);
|
||||
if (status == record_size)
|
||||
records_read++;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Flush the current buffer to/from the archive. */
|
||||
void
|
||||
flush_archive (void)
|
||||
@@ -874,8 +911,9 @@ change_tape_menu (FILE *read_file)
|
||||
{
|
||||
char *input_buffer = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
while (1)
|
||||
bool stop = false;
|
||||
|
||||
while (!stop)
|
||||
{
|
||||
fputc ('\007', stderr);
|
||||
fprintf (stderr,
|
||||
@@ -905,7 +943,7 @@ change_tape_menu (FILE *read_file)
|
||||
case '?':
|
||||
{
|
||||
fprintf (stderr, _("\
|
||||
n [name] Give a new file name for the next (and subsequent) volume(s)\n\
|
||||
n name Give a new file name for the next (and subsequent) volume(s)\n\
|
||||
q Abort tar\n\
|
||||
y or newline Continue operation\n"));
|
||||
if (!restrict_option)
|
||||
@@ -942,8 +980,15 @@ change_tape_menu (FILE *read_file)
|
||||
;
|
||||
*cursor = '\0';
|
||||
|
||||
/* FIXME: the following allocation is never reclaimed. */
|
||||
*archive_name_cursor = xstrdup (name);
|
||||
if (name[0])
|
||||
{
|
||||
/* FIXME: the following allocation is never reclaimed. */
|
||||
*archive_name_cursor = xstrdup (name);
|
||||
stop = true;
|
||||
}
|
||||
else
|
||||
fprintf (stderr, "%s",
|
||||
_("File name not specified. Try again.\n"));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -984,7 +1029,8 @@ new_volume (enum access_mode mode)
|
||||
assign_string (&volume_label, NULL);
|
||||
assign_string (&continued_file_name, NULL);
|
||||
continued_file_size = continued_file_offset = 0;
|
||||
|
||||
current_block = record_start;
|
||||
|
||||
if (rmtclose (archive) != 0)
|
||||
close_warn (*archive_name_cursor);
|
||||
|
||||
@@ -1057,10 +1103,12 @@ new_volume (enum access_mode mode)
|
||||
}
|
||||
|
||||
static bool
|
||||
read_header0 ()
|
||||
read_header0 (struct tar_stat_info *info)
|
||||
{
|
||||
enum read_header rc = read_header (false);
|
||||
enum read_header rc;
|
||||
|
||||
tar_stat_init (info);
|
||||
rc = read_header_primitive (false, info);
|
||||
if (rc == HEADER_SUCCESS)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
@@ -1075,22 +1123,25 @@ try_new_volume ()
|
||||
{
|
||||
size_t status;
|
||||
union block *header;
|
||||
|
||||
struct tar_stat_info dummy;
|
||||
int access;
|
||||
|
||||
switch (subcommand_option)
|
||||
{
|
||||
case APPEND_SUBCOMMAND:
|
||||
case CAT_SUBCOMMAND:
|
||||
case UPDATE_SUBCOMMAND:
|
||||
if (!new_volume (ACCESS_UPDATE))
|
||||
return true;
|
||||
access = ACCESS_UPDATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!new_volume (ACCESS_READ))
|
||||
return true;
|
||||
access = ACCESS_READ;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new_volume (access))
|
||||
return true;
|
||||
|
||||
while ((status = rmtread (archive, record_start->buffer, record_size))
|
||||
== SAFE_READ_ERROR)
|
||||
archive_read_error ();
|
||||
@@ -1101,14 +1152,13 @@ try_new_volume ()
|
||||
header = find_next_block ();
|
||||
if (!header)
|
||||
return false;
|
||||
|
||||
switch (header->header.typeflag)
|
||||
{
|
||||
case XGLTYPE:
|
||||
{
|
||||
struct tar_stat_info dummy;
|
||||
if (!read_header0 ())
|
||||
if (!read_header0 (&dummy))
|
||||
return false;
|
||||
tar_stat_init (&dummy);
|
||||
xheader_decode (&dummy); /* decodes values from the global header */
|
||||
tar_stat_destroy (&dummy);
|
||||
if (!real_s_name)
|
||||
@@ -1122,8 +1172,9 @@ try_new_volume ()
|
||||
}
|
||||
|
||||
case GNUTYPE_VOLHDR:
|
||||
if (!read_header0 ())
|
||||
if (!read_header0 (&dummy))
|
||||
return false;
|
||||
tar_stat_destroy (&dummy);
|
||||
assign_string (&volume_label, current_header->header.name);
|
||||
set_next_block_after (header);
|
||||
header = find_next_block ();
|
||||
@@ -1132,8 +1183,9 @@ try_new_volume ()
|
||||
/* FALL THROUGH */
|
||||
|
||||
case GNUTYPE_MULTIVOL:
|
||||
if (!read_header0 ())
|
||||
if (!read_header0 (&dummy))
|
||||
return false;
|
||||
tar_stat_destroy (&dummy);
|
||||
assign_string (&continued_file_name, current_header->header.name);
|
||||
continued_file_size =
|
||||
UINTMAX_FROM_HEADER (current_header->header.size);
|
||||
@@ -1400,13 +1452,8 @@ simple_flush_read (void)
|
||||
{
|
||||
size_t status; /* result from system call */
|
||||
|
||||
if (checkpoint_option && !(++checkpoint % 10))
|
||||
/* 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'' */
|
||||
WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
|
||||
|
||||
do_checkpoint (false);
|
||||
|
||||
/* Clear the count of errors. This only applies to a single call to
|
||||
flush_read. */
|
||||
|
||||
@@ -1464,13 +1511,8 @@ _gnu_flush_read (void)
|
||||
{
|
||||
size_t status; /* result from system call */
|
||||
|
||||
if (checkpoint_option && !(++checkpoint % 10))
|
||||
/* 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'' */
|
||||
WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
|
||||
|
||||
do_checkpoint (false);
|
||||
|
||||
/* Clear the count of errors. This only applies to a single call to
|
||||
flush_read. */
|
||||
|
||||
@@ -1562,8 +1604,7 @@ _gnu_flush_write (size_t buffer_level)
|
||||
xheader_destroy (&extended_header);
|
||||
|
||||
increase_volume_number ();
|
||||
if (totals_option)
|
||||
prev_written += bytes_written;
|
||||
prev_written += bytes_written;
|
||||
bytes_written = 0;
|
||||
|
||||
copy_ptr = record_start->buffer + status;
|
||||
@@ -1641,4 +1682,5 @@ open_archive (enum access_mode wanted_access)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
set_volume_start_time ();
|
||||
}
|
||||
|
||||
243
src/common.h
243
src/common.h
@@ -129,7 +129,15 @@ GLOBAL enum backup_type backup_type;
|
||||
|
||||
GLOBAL bool block_number_option;
|
||||
|
||||
GLOBAL bool checkpoint_option;
|
||||
GLOBAL unsigned checkpoint_option;
|
||||
|
||||
enum checkpoint_style
|
||||
{
|
||||
checkpoint_text,
|
||||
checkpoint_dot
|
||||
};
|
||||
|
||||
GLOBAL enum checkpoint_style checkpoint_style;
|
||||
|
||||
/* Specified name of compression program, or "gzip" as implied by -z. */
|
||||
GLOBAL const char *use_compress_program_option;
|
||||
@@ -189,6 +197,11 @@ GLOBAL bool multi_volume_option;
|
||||
do not get archived (also see after_date_option above). */
|
||||
GLOBAL struct timespec newer_mtime_option;
|
||||
|
||||
/* If true, override actual mtime (see below) */
|
||||
GLOBAL bool set_mtime_option;
|
||||
/* Value to be put in mtime header field instead of the actual mtime */
|
||||
GLOBAL struct timespec mtime_option;
|
||||
|
||||
/* Return true if newer_mtime_option is initialized. */
|
||||
#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
|
||||
|
||||
@@ -239,7 +252,9 @@ GLOBAL size_t strip_name_components;
|
||||
GLOBAL bool show_omitted_dirs_option;
|
||||
|
||||
GLOBAL bool sparse_option;
|
||||
|
||||
GLOBAL unsigned tar_sparse_major;
|
||||
GLOBAL unsigned tar_sparse_minor;
|
||||
|
||||
GLOBAL bool starting_file_option;
|
||||
|
||||
/* Specified maximum byte length of each tape volume (multiple of 1024). */
|
||||
@@ -281,16 +296,20 @@ GLOBAL int archive;
|
||||
/* Nonzero when outputting to /dev/null. */
|
||||
GLOBAL bool dev_null_output;
|
||||
|
||||
/* Timestamp for when we started execution. */
|
||||
GLOBAL struct timespec start_time;
|
||||
/* Timestamps: */
|
||||
GLOBAL struct timespec start_time; /* when we started execution */
|
||||
GLOBAL struct timespec volume_start_time; /* when the current volume was
|
||||
opened*/
|
||||
GLOBAL struct timespec last_stat_time; /* when the statistics was last
|
||||
computed */
|
||||
|
||||
GLOBAL struct tar_stat_info current_stat_info;
|
||||
|
||||
/* List of tape drive names, number of such tape drives, allocated number,
|
||||
and current cursor in list. */
|
||||
GLOBAL const char **archive_name_array;
|
||||
GLOBAL int archive_names;
|
||||
GLOBAL int allocated_archive_names;
|
||||
GLOBAL size_t archive_names;
|
||||
GLOBAL size_t allocated_archive_names;
|
||||
GLOBAL const char **archive_name_cursor;
|
||||
|
||||
/* Output index file name. */
|
||||
@@ -299,16 +318,15 @@ GLOBAL char const *index_file_name;
|
||||
/* Structure for keeping track of filenames and lists thereof. */
|
||||
struct name
|
||||
{
|
||||
struct name *next;
|
||||
size_t length; /* cached strlen(name) */
|
||||
struct name *next; /* Link to the next element */
|
||||
int change_dir; /* Number of the directory to change to.
|
||||
Set with the -C option. */
|
||||
uintmax_t found_count; /* number of times a matching file has
|
||||
been found */
|
||||
int explicit; /* was explicitely given in the command line */
|
||||
char firstch; /* first char is literally matched */
|
||||
char regexp; /* this name is a regexp, not literal */
|
||||
int change_dir; /* set with the -C option */
|
||||
int matching_flags; /* this name is a regexp, not literal */
|
||||
char const *dir_contents; /* for incremental_option */
|
||||
char fake; /* dummy entry */
|
||||
|
||||
size_t length; /* cached strlen(name) */
|
||||
char name[1];
|
||||
};
|
||||
|
||||
@@ -325,9 +343,10 @@ GLOBAL bool unquote_option;
|
||||
|
||||
GLOBAL bool test_label_option; /* Test archive volume label and exit */
|
||||
|
||||
/* When creating archive in verbose mode, list member names as stored in the
|
||||
archive */
|
||||
GLOBAL bool show_stored_names_option;
|
||||
/* Show file or archive names after transformation.
|
||||
In particular, when creating archive in verbose mode, list member names
|
||||
as stored in the archive */
|
||||
GLOBAL bool show_transformed_names_option;
|
||||
|
||||
/* Delay setting modification times and permissions of extracted directories
|
||||
until the end of extraction. This variable helps correctly restore directory
|
||||
@@ -335,6 +354,9 @@ GLOBAL bool show_stored_names_option;
|
||||
set for incremental archives. */
|
||||
GLOBAL bool delay_directory_restore_option;
|
||||
|
||||
/* Warn about implicit use of the wildcards in command line arguments.
|
||||
(Default for tar prior to 1.15.91, but changed afterwards */
|
||||
GLOBAL bool warn_regex_usage;
|
||||
|
||||
/* Declarations for each module. */
|
||||
|
||||
@@ -358,22 +380,23 @@ extern char *continued_file_name;
|
||||
extern uintmax_t continued_file_size;
|
||||
extern uintmax_t continued_file_offset;
|
||||
|
||||
size_t available_space_after (union block *);
|
||||
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);
|
||||
union block *find_next_block (void);
|
||||
void flush_read (void);
|
||||
void flush_write (void);
|
||||
void flush_archive (void);
|
||||
void init_volume_number (void);
|
||||
void open_archive (enum access_mode);
|
||||
void print_total_written (void);
|
||||
void open_archive (enum access_mode mode);
|
||||
void print_total_stats (void);
|
||||
void reset_eof (void);
|
||||
void set_next_block_after (union block *);
|
||||
void set_next_block_after (union block *block);
|
||||
void clear_read_error_count (void);
|
||||
void xclose (int fd);
|
||||
void archive_write_error (ssize_t) __attribute__ ((noreturn));
|
||||
void archive_write_error (ssize_t status) __attribute__ ((noreturn));
|
||||
void archive_read_error (void);
|
||||
off_t seek_archive (off_t size);
|
||||
void set_start_time (void);
|
||||
@@ -394,12 +417,13 @@ enum dump_status
|
||||
dump_status_not_implemented
|
||||
};
|
||||
|
||||
bool file_dumpable_p (struct tar_stat_info *);
|
||||
bool file_dumpable_p (struct tar_stat_info *st);
|
||||
void create_archive (void);
|
||||
void pad_archive (off_t size_left);
|
||||
void dump_file (char *, int, dev_t);
|
||||
void dump_file (const char *st, int top_level, dev_t parent_device);
|
||||
union block *start_header (struct tar_stat_info *st);
|
||||
void finish_header (struct tar_stat_info *, union block *, off_t);
|
||||
void finish_header (struct tar_stat_info *st, union block *header,
|
||||
off_t block_ordinal);
|
||||
void simple_finish_header (union block *header);
|
||||
union block * write_extended (bool global, struct tar_stat_info *st,
|
||||
union block *old_header);
|
||||
@@ -419,16 +443,16 @@ void check_links (void);
|
||||
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
|
||||
bool gid_to_chars (gid_t, char *, size_t);
|
||||
bool major_to_chars (major_t, char *, size_t);
|
||||
bool minor_to_chars (minor_t, char *, size_t);
|
||||
bool mode_to_chars (mode_t, char *, size_t);
|
||||
bool off_to_chars (off_t, char *, size_t);
|
||||
bool size_to_chars (size_t, char *, size_t);
|
||||
bool time_to_chars (time_t, char *, size_t);
|
||||
bool uid_to_chars (uid_t, char *, size_t);
|
||||
bool uintmax_to_chars (uintmax_t, char *, size_t);
|
||||
void string_to_chars (char const *, char *, size_t);
|
||||
bool gid_to_chars (gid_t gid, char *buf, size_t size);
|
||||
bool major_to_chars (major_t m, char *buf, size_t size);
|
||||
bool minor_to_chars (minor_t m, char *buf, size_t size);
|
||||
bool mode_to_chars (mode_t m, char *buf, size_t size);
|
||||
bool off_to_chars (off_t off, char *buf, size_t size);
|
||||
bool size_to_chars (size_t v, char *buf, size_t size);
|
||||
bool time_to_chars (time_t t, char *buf, size_t size);
|
||||
bool uid_to_chars (uid_t uid, char *buf, size_t size);
|
||||
bool uintmax_to_chars (uintmax_t v, char *buf, size_t size);
|
||||
void string_to_chars (char const *s, char *buf, size_t size);
|
||||
|
||||
/* Module diffarch.c. */
|
||||
|
||||
@@ -443,6 +467,7 @@ void verify_volume (void);
|
||||
void extr_init (void);
|
||||
void extract_archive (void);
|
||||
void extract_finish (void);
|
||||
bool rename_directory (char *src, char *dst);
|
||||
|
||||
/* Module delete.c. */
|
||||
|
||||
@@ -450,10 +475,11 @@ void delete_archive_members (void);
|
||||
|
||||
/* Module incremen.c. */
|
||||
|
||||
char *get_directory_contents (char *, dev_t);
|
||||
char *get_directory_contents (char *dir_name, dev_t device);
|
||||
const char *append_incremental_renames (const char *dump);
|
||||
void read_directory_file (void);
|
||||
void write_directory_file (void);
|
||||
void purge_directory (char const *);
|
||||
void purge_directory (char const *directory_name);
|
||||
void list_dumpdir (char *buffer, size_t size);
|
||||
void update_parent_directory (const char *name);
|
||||
|
||||
@@ -485,9 +511,9 @@ extern enum archive_format current_format;
|
||||
extern size_t recent_long_name_blocks;
|
||||
extern size_t recent_long_link_blocks;
|
||||
|
||||
void decode_header (union block *, struct tar_stat_info *,
|
||||
enum archive_format *, int);
|
||||
char const *tartime (struct timespec, bool);
|
||||
void decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
enum archive_format *format_pointer, int do_user_group);
|
||||
char const *tartime (struct timespec t, bool full_time);
|
||||
|
||||
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
|
||||
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
|
||||
@@ -499,23 +525,25 @@ char const *tartime (struct timespec, bool);
|
||||
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
|
||||
#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
|
||||
|
||||
gid_t gid_from_header (const char *, size_t);
|
||||
major_t major_from_header (const char *, size_t);
|
||||
minor_t minor_from_header (const char *, size_t);
|
||||
mode_t mode_from_header (const char *, size_t);
|
||||
off_t off_from_header (const char *, size_t);
|
||||
size_t size_from_header (const char *, size_t);
|
||||
time_t time_from_header (const char *, size_t);
|
||||
uid_t uid_from_header (const char *, size_t);
|
||||
uintmax_t uintmax_from_header (const char *, size_t);
|
||||
gid_t gid_from_header (const char *buf, size_t size);
|
||||
major_t major_from_header (const char *buf, size_t size);
|
||||
minor_t minor_from_header (const char *buf, size_t size);
|
||||
mode_t mode_from_header (const char *buf, size_t size);
|
||||
off_t off_from_header (const char *buf, size_t size);
|
||||
size_t size_from_header (const char *buf, size_t size);
|
||||
time_t time_from_header (const char *buf, size_t size);
|
||||
uid_t uid_from_header (const char *buf, size_t size);
|
||||
uintmax_t uintmax_from_header (const char * buf, size_t size);
|
||||
|
||||
void list_archive (void);
|
||||
void print_for_mkdir (char *, int, mode_t);
|
||||
void print_header (struct tar_stat_info *, off_t);
|
||||
void read_and (void (*) (void));
|
||||
enum read_header read_header (bool);
|
||||
void print_for_mkdir (char *dirname, int length, mode_t mode);
|
||||
void print_header (struct tar_stat_info *st, off_t block_ordinal);
|
||||
void read_and (void (*do_something) (void));
|
||||
enum read_header read_header_primitive (bool raw_extended_headers,
|
||||
struct tar_stat_info *info);
|
||||
enum read_header read_header (bool raw_extended_headers);
|
||||
enum read_header tar_checksum (union block *header, bool silent);
|
||||
void skip_file (off_t);
|
||||
void skip_file (off_t size);
|
||||
void skip_member (void);
|
||||
|
||||
/* Module mangle.c. */
|
||||
@@ -524,18 +552,16 @@ void extract_mangle (void);
|
||||
|
||||
/* Module misc.c. */
|
||||
|
||||
void assign_string (char **, const char *);
|
||||
char *quote_copy_string (const char *);
|
||||
int unquote_string (char *);
|
||||
void assign_string (char **dest, const char *src);
|
||||
char *quote_copy_string (const char *str);
|
||||
int unquote_string (char *str);
|
||||
|
||||
void code_ns_fraction (int, char *);
|
||||
char const *code_timespec (struct timespec, char *);
|
||||
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 };
|
||||
|
||||
size_t dot_dot_prefix_len (char const *);
|
||||
|
||||
enum remove_option
|
||||
{
|
||||
ORDINARY_REMOVE_OPTION,
|
||||
@@ -550,31 +576,32 @@ enum remove_option
|
||||
meta-info to the incremental dumps, this should become unnecessary */
|
||||
WANT_DIRECTORY_REMOVE_OPTION
|
||||
};
|
||||
int remove_any_file (const char *, enum remove_option);
|
||||
bool maybe_backup_file (const char *, int);
|
||||
int remove_any_file (const char *file_name, enum remove_option option);
|
||||
bool maybe_backup_file (const char *file_name, bool this_is_the_archive);
|
||||
void undo_last_backup (void);
|
||||
|
||||
int deref_stat (bool, char const *, struct stat *);
|
||||
int deref_stat (bool deref, char const *name, struct stat *buf);
|
||||
|
||||
int chdir_arg (char const *);
|
||||
void chdir_do (int);
|
||||
void closeopen (void);
|
||||
int chdir_arg (char const *dir);
|
||||
void chdir_do (int dir);
|
||||
|
||||
void close_diag (char const *name);
|
||||
void open_diag (char const *name);
|
||||
void read_diag_details (char const *name, off_t offset, size_t size);
|
||||
void readlink_diag (char const *name);
|
||||
void savedir_diag (char const *name);
|
||||
void seek_diag_details (char const *, off_t);
|
||||
void seek_diag_details (char const *name, off_t offset);
|
||||
void stat_diag (char const *name);
|
||||
void write_error_details (char const *, size_t, size_t);
|
||||
void write_fatal (char const *) __attribute__ ((noreturn));
|
||||
void write_fatal_details (char const *, ssize_t, size_t)
|
||||
void write_error_details (char const *name, size_t status, size_t size);
|
||||
void write_fatal (char const *name) __attribute__ ((noreturn));
|
||||
void write_fatal_details (char const *name, ssize_t status, size_t size)
|
||||
__attribute__ ((noreturn));
|
||||
|
||||
pid_t xfork (void);
|
||||
void xpipe (int[2]);
|
||||
void xpipe (int fd[2]);
|
||||
|
||||
void *page_aligned_alloc (void **, size_t);
|
||||
void *page_aligned_alloc (void **ptr, size_t size);
|
||||
int set_file_atime (int fd, char const *file,
|
||||
struct timespec const timespec[2]);
|
||||
|
||||
@@ -582,35 +609,35 @@ int set_file_atime (int fd, char const *file,
|
||||
|
||||
extern struct name *gnu_list_name;
|
||||
|
||||
void gid_to_gname (gid_t, char **gname);
|
||||
int gname_to_gid (char const *, gid_t *);
|
||||
void uid_to_uname (uid_t, char **uname);
|
||||
int uname_to_uid (char const *, uid_t *);
|
||||
void gid_to_gname (gid_t gid, char **gname);
|
||||
int gname_to_gid (char const *gname, gid_t *pgid);
|
||||
void uid_to_uname (uid_t uid, char **uname);
|
||||
int uname_to_uid (char const *uname, uid_t *puid);
|
||||
|
||||
void init_names (void);
|
||||
void name_add (const char *);
|
||||
void name_init (void);
|
||||
void name_add_name (const char *name, int matching_flags);
|
||||
void name_add_dir (const char *name);
|
||||
void name_term (void);
|
||||
char *name_next (int);
|
||||
const char *name_next (int change_dirs);
|
||||
void name_gather (void);
|
||||
struct name *addname (char const *, int);
|
||||
int name_match (const char *);
|
||||
struct name *addname (char const *string, int change_dir);
|
||||
bool name_match (const char *name);
|
||||
void names_notfound (void);
|
||||
void collect_and_sort_names (void);
|
||||
struct name *name_scan (const char *, bool);
|
||||
struct name *name_scan (const char *name);
|
||||
char *name_from_list (void);
|
||||
void blank_name_list (void);
|
||||
char *new_name (const char *, const char *);
|
||||
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 *);
|
||||
bool all_names_found (struct tar_stat_info *st);
|
||||
|
||||
bool excluded_name (char const *);
|
||||
bool excluded_name (char const *name);
|
||||
|
||||
void add_avoided_name (char const *);
|
||||
bool is_avoided_name (char const *);
|
||||
bool is_individual_file (char const *);
|
||||
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 *);
|
||||
bool contains_dot_dot (char const *name);
|
||||
|
||||
#define ISFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
(c)->found_count == occurrence_option)
|
||||
@@ -621,8 +648,8 @@ bool contains_dot_dot (char const *);
|
||||
|
||||
void usage (int);
|
||||
|
||||
int confirm (const char *, const char *);
|
||||
void request_stdin (const char *);
|
||||
int confirm (const char *message_action, const char *name);
|
||||
void request_stdin (const char *option);
|
||||
|
||||
void tar_stat_init (struct tar_stat_info *st);
|
||||
void tar_stat_destroy (struct tar_stat_info *st);
|
||||
@@ -639,22 +666,23 @@ void update_archive (void);
|
||||
|
||||
/* Module xheader.c. */
|
||||
|
||||
void xheader_decode (struct tar_stat_info *);
|
||||
void xheader_decode (struct tar_stat_info *stat);
|
||||
void xheader_decode_global (void);
|
||||
void xheader_store (char const *, struct tar_stat_info const *, void const *);
|
||||
void xheader_read (union block *, size_t);
|
||||
void xheader_store (char const *keyword, struct tar_stat_info const *st,
|
||||
void const *data);
|
||||
void xheader_read (union block *header, size_t size);
|
||||
void xheader_write (char type, char *name, struct xheader *xhdr);
|
||||
void xheader_write_global (void);
|
||||
void xheader_finish (struct xheader *);
|
||||
void xheader_destroy (struct xheader *);
|
||||
void xheader_finish (struct xheader *hdr);
|
||||
void xheader_destroy (struct xheader *hdr);
|
||||
char *xheader_xhdr_name (struct tar_stat_info *st);
|
||||
char *xheader_ghdr_name (void);
|
||||
void xheader_write (char, char *, struct xheader *);
|
||||
void xheader_write (char type, char *name, struct xheader *xhdr);
|
||||
void xheader_write_global (void);
|
||||
void xheader_set_option (char *string);
|
||||
void xheader_string_begin (void);
|
||||
void xheader_string_add (char const *s);
|
||||
void xheader_string_end (char const *keyword);
|
||||
bool xheader_string_end (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);
|
||||
@@ -683,14 +711,21 @@ int sys_exec_info_script (const char **archive_name, int volume_number);
|
||||
void report_difference (struct tar_stat_info *st, const char *message, ...);
|
||||
|
||||
/* Module sparse.c */
|
||||
bool sparse_file_p (struct tar_stat_info *);
|
||||
bool sparse_member_p (struct tar_stat_info *);
|
||||
bool sparse_fixup_header (struct tar_stat_info *);
|
||||
enum dump_status sparse_dump_file (int, struct tar_stat_info *);
|
||||
enum dump_status sparse_extract_file (int, struct tar_stat_info *, off_t *);
|
||||
enum dump_status sparse_skip_file (struct tar_stat_info *);
|
||||
bool sparse_diff_file (int, struct tar_stat_info *);
|
||||
bool sparse_member_p (struct tar_stat_info *st);
|
||||
bool sparse_fixup_header (struct tar_stat_info *st);
|
||||
enum dump_status sparse_dump_file (int, struct tar_stat_info *st);
|
||||
enum dump_status sparse_extract_file (int fd, struct tar_stat_info *st,
|
||||
off_t *size);
|
||||
enum dump_status sparse_skip_file (struct tar_stat_info *st);
|
||||
bool sparse_diff_file (int, struct tar_stat_info *st);
|
||||
|
||||
/* Module utf8.c */
|
||||
bool string_ascii_p (const char *str);
|
||||
bool utf8_convert (bool to_utf, char const *input, char **output);
|
||||
|
||||
/* Module transform.c */
|
||||
void set_transform_expr (const char *expr);
|
||||
bool transform_name (char **pinput);
|
||||
bool transform_name_fp (char **pinput, char *(*fun)(char *));
|
||||
|
||||
|
||||
|
||||
57
src/create.c
57
src/create.c
@@ -128,7 +128,7 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
|
||||
char const *minval_string;
|
||||
char const *maxval_string = STRINGIFY_BIGINT (maxval, maxbuf);
|
||||
char const *value_string;
|
||||
|
||||
|
||||
if (gnu_format)
|
||||
{
|
||||
uintmax_t m = maxval + 1 ? maxval + 1 : maxval / 2 + 1;
|
||||
@@ -138,7 +138,7 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
|
||||
}
|
||||
else
|
||||
minval_string = "0";
|
||||
|
||||
|
||||
if (negative)
|
||||
{
|
||||
char *p = STRINGIFY_BIGINT (- value, valbuf + 1);
|
||||
@@ -147,13 +147,18 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize,
|
||||
}
|
||||
else
|
||||
value_string = STRINGIFY_BIGINT (value, valbuf);
|
||||
|
||||
|
||||
if (substitute)
|
||||
{
|
||||
int negsub;
|
||||
uintmax_t sub = substitute (&negsub) & maxval;
|
||||
/* FIXME: This is the only place where GNU_FORMAT differs from
|
||||
OLDGNU_FORMAT. Apart from this they are completely identical. */
|
||||
/* NOTE: This is one of the few places where GNU_FORMAT differs from
|
||||
OLDGNU_FORMAT. The actual differences are:
|
||||
|
||||
1. In OLDGNU_FORMAT all strings in a tar header end in \0
|
||||
2. Incremental archives use oldgnu_header.
|
||||
|
||||
Apart from this they are completely identical. */
|
||||
uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
|
||||
char subbuf[UINTMAX_STRSIZE_BOUND + 1];
|
||||
char *sub_string = STRINGIFY_BIGINT (s, subbuf + 1);
|
||||
@@ -236,7 +241,7 @@ to_chars (int negative, uintmax_t value, size_t valsize,
|
||||
}
|
||||
else
|
||||
substitute = NULL; /* No substitution for formats, other than GNU */
|
||||
|
||||
|
||||
return to_chars_subst (negative, gnu_format, value, valsize, substitute,
|
||||
where, size, type);
|
||||
}
|
||||
@@ -291,7 +296,8 @@ mode_to_chars (mode_t v, char *p, size_t s)
|
||||
&& S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
|
||||
&& archive_format != POSIX_FORMAT
|
||||
&& archive_format != USTAR_FORMAT
|
||||
&& archive_format != GNU_FORMAT)
|
||||
&& archive_format != GNU_FORMAT
|
||||
&& archive_format != OLDGNU_FORMAT)
|
||||
{
|
||||
negative = v < 0;
|
||||
u = v;
|
||||
@@ -380,7 +386,7 @@ bool
|
||||
file_dumpable_p (struct tar_stat_info *st)
|
||||
{
|
||||
if (dev_null_output)
|
||||
return totals_option && sparse_option && sparse_file_p (st);
|
||||
return totals_option && sparse_option && ST_IS_SPARSE (st->stat);
|
||||
return !(st->archive_file_size == 0
|
||||
&& (st->stat.st_mode & MODE_R) == MODE_R);
|
||||
}
|
||||
@@ -663,7 +669,8 @@ start_header (struct tar_stat_info *st)
|
||||
if (mode_option)
|
||||
st->stat.st_mode =
|
||||
((st->stat.st_mode & ~MODE_ALL)
|
||||
| mode_adjust (st->stat.st_mode, mode_option, initial_umask));
|
||||
| mode_adjust (st->stat.st_mode, S_ISDIR (st->stat.st_mode) != 0,
|
||||
initial_umask, mode_option, NULL));
|
||||
|
||||
/* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
|
||||
for a few tars and came up with the following interoperability
|
||||
@@ -730,7 +737,7 @@ start_header (struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
{
|
||||
struct timespec mtime = st->mtime;
|
||||
struct timespec mtime = set_mtime_option ? mtime_option : st->mtime;
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
|
||||
@@ -967,8 +974,8 @@ dump_regular_file (int fd, struct tar_stat_info *st)
|
||||
size_left),
|
||||
quotearg_colon (st->orig_file_name),
|
||||
STRINGIFY_BIGINT (size_left, buf)));
|
||||
if (! ignore_failed_read_option)
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
if (! ignore_failed_read_option)
|
||||
exit_status = TAREXIT_DIFFERS;
|
||||
pad_archive (size_left - (bufsize-count));
|
||||
return dump_status_short;
|
||||
}
|
||||
@@ -1182,7 +1189,7 @@ dump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device)
|
||||
void
|
||||
create_archive (void)
|
||||
{
|
||||
char *p;
|
||||
const char *p;
|
||||
|
||||
open_archive (ACCESS_WRITE);
|
||||
xheader_write_global ();
|
||||
@@ -1387,11 +1394,12 @@ check_links (void)
|
||||
exit_status to failure, a clear diagnostic has been issued. */
|
||||
|
||||
static void
|
||||
dump_file0 (struct tar_stat_info *st, char const *p,
|
||||
dump_file0 (struct tar_stat_info *st, const char *p,
|
||||
int top_level, dev_t parent_device)
|
||||
{
|
||||
union block *header;
|
||||
char type;
|
||||
off_t original_size;
|
||||
struct timespec original_ctime;
|
||||
struct timespec restore_times[2];
|
||||
off_t block_ordinal = -1;
|
||||
@@ -1404,12 +1412,14 @@ dump_file0 (struct tar_stat_info *st, char const *p,
|
||||
assign_string (&st->file_name,
|
||||
safer_name_suffix (p, false, absolute_names_option));
|
||||
|
||||
transform_name (&st->file_name);
|
||||
|
||||
if (deref_stat (dereference_option, p, &st->stat) != 0)
|
||||
{
|
||||
stat_diag (p);
|
||||
return;
|
||||
}
|
||||
st->archive_file_size = st->stat.st_size;
|
||||
st->archive_file_size = original_size = st->stat.st_size;
|
||||
st->atime = restore_times[0] = get_stat_atime (&st->stat);
|
||||
st->mtime = restore_times[1] = get_stat_mtime (&st->stat);
|
||||
st->ctime = original_ctime = get_stat_ctime (&st->stat);
|
||||
@@ -1497,7 +1507,7 @@ dump_file0 (struct tar_stat_info *st, char const *p,
|
||||
{
|
||||
enum dump_status status;
|
||||
|
||||
if (fd != -1 && sparse_option && sparse_file_p (st))
|
||||
if (fd != -1 && sparse_option && ST_IS_SPARSE (st->stat))
|
||||
{
|
||||
status = sparse_dump_file (fd, st);
|
||||
if (status == dump_status_not_implemented)
|
||||
@@ -1521,7 +1531,7 @@ dump_file0 (struct tar_stat_info *st, char const *p,
|
||||
}
|
||||
|
||||
file_count_links (st);
|
||||
|
||||
|
||||
ok = status == dump_status_ok;
|
||||
}
|
||||
|
||||
@@ -1546,9 +1556,14 @@ dump_file0 (struct tar_stat_info *st, char const *p,
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0)
|
||||
WARN ((0, 0, _("%s: file changed as we read it"),
|
||||
quotearg_colon (p)));
|
||||
if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
|
||||
|| original_size < final_stat.st_size)
|
||||
{
|
||||
WARN ((0, 0, _("%s: file changed as we read it"),
|
||||
quotearg_colon (p)));
|
||||
if (exit_status == TAREXIT_SUCCESS)
|
||||
exit_status = TAREXIT_DIFFERS;
|
||||
}
|
||||
else if (atime_preserve_option == replace_atime_preserve
|
||||
&& set_file_atime (fd, p, restore_times) != 0)
|
||||
utime_error (p);
|
||||
@@ -1667,7 +1682,7 @@ dump_file0 (struct tar_stat_info *st, char const *p,
|
||||
}
|
||||
|
||||
void
|
||||
dump_file (char *p, int top_level, dev_t parent_device)
|
||||
dump_file (const char *p, int top_level, dev_t parent_device)
|
||||
{
|
||||
struct tar_stat_info st;
|
||||
tar_stat_init (&st);
|
||||
|
||||
@@ -39,7 +39,7 @@ extern off_t records_written;
|
||||
|
||||
/* The number of records skipped at the start of the archive, when
|
||||
passing over members that are not deleted. */
|
||||
static off_t records_skipped;
|
||||
off_t records_skipped;
|
||||
|
||||
/* Move archive descriptor by COUNT records worth. If COUNT is
|
||||
positive we move forward, else we move negative. If it's a tape,
|
||||
@@ -174,7 +174,7 @@ delete_archive_members (void)
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
if ((name = name_scan (current_stat_info.file_name, false)) == NULL)
|
||||
if ((name = name_scan (current_stat_info.file_name)) == NULL)
|
||||
{
|
||||
skip_member ();
|
||||
break;
|
||||
@@ -285,7 +285,7 @@ delete_archive_members (void)
|
||||
|
||||
/* Found another header. */
|
||||
|
||||
if ((name = name_scan (current_stat_info.file_name, false)) != NULL)
|
||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
name->found_count++;
|
||||
if (ISFOUND(name))
|
||||
@@ -294,7 +294,7 @@ delete_archive_members (void)
|
||||
set_next_block_after (current_header);
|
||||
blocks_to_skip = (current_stat_info.stat.st_size
|
||||
+ BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
|
||||
|
||||
while (record_end - current_block <= blocks_to_skip)
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
|
||||
@@ -193,7 +193,7 @@ check_time (char const *file_name, struct timespec t)
|
||||
if (t.tv_sec <= 0)
|
||||
WARN ((0, 0, _("%s: implausibly old time stamp %s"),
|
||||
file_name, tartime (t, true)));
|
||||
else if (timespec_cmp (start_time, t) < 0)
|
||||
else if (timespec_cmp (volume_start_time, t) < 0)
|
||||
{
|
||||
struct timespec now;
|
||||
gettime (&now);
|
||||
@@ -392,13 +392,12 @@ static int
|
||||
make_directories (char *file_name)
|
||||
{
|
||||
char *cursor0 = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
char *cursor; /* points into the file name */
|
||||
char *cursor; /* points into the file name */
|
||||
int did_something = 0; /* did we do anything yet? */
|
||||
int mode;
|
||||
int invert_permissions;
|
||||
int status;
|
||||
|
||||
|
||||
for (cursor = cursor0; *cursor; cursor++)
|
||||
{
|
||||
if (! ISSLASH (*cursor))
|
||||
@@ -1031,6 +1030,14 @@ extract_mangle_wrapper (char *file_name, int typeflag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extract_volhdr (char *file_name, int typeflag)
|
||||
{
|
||||
if (verbose_option)
|
||||
fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name));
|
||||
skip_member ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extract_failure (char *file_name, int typeflag)
|
||||
@@ -1111,9 +1118,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
break;
|
||||
|
||||
case GNUTYPE_VOLHDR:
|
||||
if (verbose_option)
|
||||
fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name));
|
||||
*fun = NULL;
|
||||
*fun = extract_volhdr;
|
||||
break;
|
||||
|
||||
case GNUTYPE_NAMES:
|
||||
@@ -1178,51 +1183,36 @@ void
|
||||
extract_archive (void)
|
||||
{
|
||||
char typeflag;
|
||||
char *file_name;
|
||||
tar_extractor_t fun;
|
||||
|
||||
set_next_block_after (current_header);
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
|
||||
|
||||
if (interactive_option && !confirm ("extract", current_stat_info.file_name))
|
||||
if (!current_stat_info.file_name[0]
|
||||
|| (interactive_option
|
||||
&& !confirm ("extract", current_stat_info.file_name)))
|
||||
{
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print the block from current_header and current_stat. */
|
||||
|
||||
if (verbose_option)
|
||||
print_header (¤t_stat_info, -1);
|
||||
|
||||
file_name = safer_name_suffix (current_stat_info.file_name,
|
||||
false, absolute_names_option);
|
||||
if (strip_name_components)
|
||||
{
|
||||
size_t prefix_len = stripped_prefix_len (file_name,
|
||||
strip_name_components);
|
||||
if (prefix_len == (size_t) -1)
|
||||
{
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
file_name += prefix_len;
|
||||
}
|
||||
|
||||
/* Restore stats for all non-ancestor directories, unless
|
||||
it is an incremental archive.
|
||||
(see NOTICE in the comment to delay_set_stat above) */
|
||||
if (!delay_directory_restore_option)
|
||||
apply_nonancestor_delayed_set_stat (file_name, 0);
|
||||
apply_nonancestor_delayed_set_stat (current_stat_info.file_name, 0);
|
||||
|
||||
/* Take a safety backup of a previously existing file. */
|
||||
|
||||
if (backup_option)
|
||||
if (!maybe_backup_file (file_name, 0))
|
||||
if (!maybe_backup_file (current_stat_info.file_name, 0))
|
||||
{
|
||||
int e = errno;
|
||||
ERROR ((0, e, _("%s: Was unable to backup this file"),
|
||||
quotearg_colon (file_name)));
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
@@ -1232,9 +1222,10 @@ extract_archive (void)
|
||||
typeflag = sparse_member_p (¤t_stat_info) ?
|
||||
GNUTYPE_SPARSE : current_header->header.typeflag;
|
||||
|
||||
if (prepare_to_extract (file_name, typeflag, &fun))
|
||||
if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun))
|
||||
{
|
||||
if (fun && (*fun) (file_name, typeflag) && backup_option)
|
||||
if (fun && (*fun) (current_stat_info.file_name, typeflag)
|
||||
&& backup_option)
|
||||
undo_last_backup ();
|
||||
}
|
||||
else
|
||||
@@ -1323,6 +1314,39 @@ extract_finish (void)
|
||||
apply_nonancestor_delayed_set_stat ("", 1);
|
||||
}
|
||||
|
||||
bool
|
||||
rename_directory (char *src, char *dst)
|
||||
{
|
||||
if (rename (src, dst))
|
||||
{
|
||||
int e = errno;
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case ENOENT:
|
||||
if (make_directories (dst))
|
||||
{
|
||||
if (rename (src, dst) == 0)
|
||||
return true;
|
||||
e = errno;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXDEV:
|
||||
/* FIXME: Fall back to recursive copying */
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ERROR ((0, e, _("Cannot rename %s to %s"),
|
||||
quote_n (0, src),
|
||||
quote_n (1, dst)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
fatal_exit (void)
|
||||
{
|
||||
|
||||
1417
src/incremen.c
1417
src/incremen.c
File diff suppressed because it is too large
Load Diff
65
src/list.c
65
src/list.c
@@ -281,8 +281,8 @@ tar_checksum (union block *header, bool silent)
|
||||
}
|
||||
|
||||
/* Read a block that's supposed to be a header block. Return its
|
||||
address in "current_header", and if it is good, the file's size in
|
||||
current_stat_info.stat.st_size.
|
||||
address in "current_header", and if it is good, the file's size
|
||||
and names (file name, link name) in *info.
|
||||
|
||||
Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
|
||||
block full of zeros (EOF marker).
|
||||
@@ -294,7 +294,7 @@ tar_checksum (union block *header, bool silent)
|
||||
the header which this routine reads. */
|
||||
|
||||
enum read_header
|
||||
read_header (bool raw_extended_headers)
|
||||
read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
|
||||
{
|
||||
union block *header;
|
||||
union block *header_copy;
|
||||
@@ -321,9 +321,9 @@ read_header (bool raw_extended_headers)
|
||||
/* Good block. Decode file size and return. */
|
||||
|
||||
if (header->header.typeflag == LNKTYPE)
|
||||
current_stat_info.stat.st_size = 0; /* links 0 size on tape */
|
||||
info->stat.st_size = 0; /* links 0 size on tape */
|
||||
else
|
||||
current_stat_info.stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
info->stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK
|
||||
@@ -336,14 +336,13 @@ read_header (bool raw_extended_headers)
|
||||
else if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
||||
{
|
||||
size_t name_size = current_stat_info.stat.st_size;
|
||||
size_t name_size = info->stat.st_size;
|
||||
size_t n = name_size % BLOCKSIZE;
|
||||
size = name_size + BLOCKSIZE;
|
||||
if (n)
|
||||
size += BLOCKSIZE - n;
|
||||
|
||||
if (name_size != current_stat_info.stat.st_size
|
||||
|| size < name_size)
|
||||
if (name_size != info->stat.st_size || size < name_size)
|
||||
xalloc_die ();
|
||||
|
||||
header_copy = xmalloc (size + 1);
|
||||
@@ -434,9 +433,9 @@ read_header (bool raw_extended_headers)
|
||||
recent_long_name = 0;
|
||||
recent_long_name_blocks = 0;
|
||||
}
|
||||
assign_string (¤t_stat_info.orig_file_name, name);
|
||||
assign_string (¤t_stat_info.file_name, name);
|
||||
current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name);
|
||||
assign_string (&info->orig_file_name, name);
|
||||
assign_string (&info->file_name, name);
|
||||
info->had_trailing_slash = strip_trailing_slashes (info->file_name);
|
||||
|
||||
if (recent_long_link)
|
||||
free (recent_long_link);
|
||||
@@ -455,13 +454,34 @@ read_header (bool raw_extended_headers)
|
||||
recent_long_link = 0;
|
||||
recent_long_link_blocks = 0;
|
||||
}
|
||||
assign_string (¤t_stat_info.link_name, name);
|
||||
assign_string (&info->link_name, name);
|
||||
|
||||
return HEADER_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum read_header
|
||||
read_header (bool raw_extended_headers)
|
||||
{
|
||||
return read_header_primitive (raw_extended_headers, ¤t_stat_info);
|
||||
}
|
||||
|
||||
static char *
|
||||
decode_xform (char *file_name)
|
||||
{
|
||||
file_name = safer_name_suffix (file_name, false, absolute_names_option);
|
||||
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;
|
||||
}
|
||||
|
||||
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
|
||||
|
||||
/* Decode things from a file HEADER block into STAT_INFO, also setting
|
||||
@@ -579,6 +599,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
|| stat_info->dumpdir)
|
||||
stat_info->is_dumpdir = true;
|
||||
}
|
||||
|
||||
transform_name_fp (&stat_info->file_name, decode_xform);
|
||||
}
|
||||
|
||||
/* Convert buffer at WHERE0 of size DIGS from external format to
|
||||
@@ -975,7 +997,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
char modes[11];
|
||||
char const *time_stamp;
|
||||
int time_stamp_len;
|
||||
char *temp_name = st->orig_file_name ? st->orig_file_name : st->file_name;
|
||||
char *temp_name;
|
||||
|
||||
/* These hold formatted ints. */
|
||||
char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
|
||||
@@ -989,21 +1011,8 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
if (test_label_option && current_header->header.typeflag != GNUTYPE_VOLHDR)
|
||||
return;
|
||||
|
||||
if (show_stored_names_option)
|
||||
{
|
||||
switch (subcommand_option)
|
||||
{
|
||||
case CAT_SUBCOMMAND:
|
||||
case UPDATE_SUBCOMMAND:
|
||||
case APPEND_SUBCOMMAND:
|
||||
case CREATE_SUBCOMMAND:
|
||||
temp_name = st->file_name ? st->file_name : st->orig_file_name;
|
||||
break;
|
||||
|
||||
default:
|
||||
temp_name = st->orig_file_name ? st->orig_file_name : st->file_name;
|
||||
}
|
||||
}
|
||||
if (show_transformed_names_option)
|
||||
temp_name = st->file_name ? st->file_name : st->orig_file_name;
|
||||
else
|
||||
temp_name = st->orig_file_name ? st->orig_file_name : st->file_name;
|
||||
|
||||
|
||||
55
src/misc.c
55
src/misc.c
@@ -18,10 +18,13 @@
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <system.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <rmt.h>
|
||||
#include "common.h"
|
||||
#include <quotearg.h>
|
||||
#include <save-cwd.h>
|
||||
#include <xgetcwd.h>
|
||||
#include <unlinkdir.h>
|
||||
#include <utimens.h>
|
||||
|
||||
@@ -412,7 +415,7 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
so, we do not have to backup block or character devices, nor remote
|
||||
entities. */
|
||||
bool
|
||||
maybe_backup_file (const char *file_name, int this_is_the_archive)
|
||||
maybe_backup_file (const char *file_name, bool this_is_the_archive)
|
||||
{
|
||||
struct stat file_stat;
|
||||
|
||||
@@ -542,8 +545,14 @@ chdir_arg (char const *dir)
|
||||
{
|
||||
if (wds == wd_alloc)
|
||||
{
|
||||
wd_alloc = 2 * (wd_alloc + 1);
|
||||
wd = xrealloc (wd, sizeof *wd * wd_alloc);
|
||||
if (wd_alloc == 0)
|
||||
{
|
||||
wd_alloc = 2;
|
||||
wd = xmalloc (sizeof *wd * wd_alloc);
|
||||
}
|
||||
else
|
||||
wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
|
||||
|
||||
if (! wds)
|
||||
{
|
||||
wd[wds].name = ".";
|
||||
@@ -568,13 +577,41 @@ chdir_arg (char const *dir)
|
||||
return wds++;
|
||||
}
|
||||
|
||||
/* Return maximum number of open files */
|
||||
int
|
||||
get_max_open_files ()
|
||||
{
|
||||
#if defined _SC_OPEN_MAX
|
||||
return sysconf (_SC_OPEN_MAX);
|
||||
#elif defined RLIMIT_NOFILE
|
||||
struct rlimit rlim;
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
|
||||
return rlim.rlim_max;
|
||||
#elif defined HAVE_GETDTABLESIZE
|
||||
return getdtablesize ();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Close all descriptors, except the first three */
|
||||
void
|
||||
closeopen ()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = get_max_open_files () - 1; i > 2; i--)
|
||||
close (i);
|
||||
}
|
||||
|
||||
/* Change to directory I. If I is 0, change to the initial working
|
||||
directory; otherwise, I must be a value returned by chdir_arg. */
|
||||
void
|
||||
chdir_do (int i)
|
||||
{
|
||||
static int previous;
|
||||
|
||||
static int saved_count;
|
||||
|
||||
if (previous != i)
|
||||
{
|
||||
struct wd *prev = &wd[previous];
|
||||
@@ -583,7 +620,15 @@ chdir_do (int i)
|
||||
if (! prev->saved)
|
||||
{
|
||||
prev->saved = 1;
|
||||
if (save_cwd (&prev->saved_cwd) != 0)
|
||||
saved_count++;
|
||||
/* Make sure we still have at least one descriptor available */
|
||||
if (saved_count >= get_max_open_files () - 4)
|
||||
{
|
||||
/* Force restore_cwd to use chdir_long */
|
||||
prev->saved_cwd.desc = -1;
|
||||
prev->saved_cwd.name = xgetcwd ();
|
||||
}
|
||||
else if (save_cwd (&prev->saved_cwd) != 0)
|
||||
FATAL_ERROR ((0, 0, _("Cannot save working directory")));
|
||||
}
|
||||
|
||||
|
||||
319
src/names.c
319
src/names.c
@@ -183,49 +183,90 @@ gname_to_gid (char const *gname, gid_t *gidp)
|
||||
|
||||
static struct name *namelist; /* first name in list, if any */
|
||||
static struct name **nametail = &namelist; /* end of name list */
|
||||
static const char **name_array; /* store an array of names */
|
||||
static int allocated_names; /* how big is the array? */
|
||||
static int names; /* how many entries does it have? */
|
||||
static int name_index; /* how many of the entries have we scanned? */
|
||||
|
||||
/* Initialize structures. */
|
||||
void
|
||||
init_names (void)
|
||||
/* File name arguments are processed in two stages: first a
|
||||
name_array (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,
|
||||
which is meant to help process large archives on machines with
|
||||
limited memory. With this option on, namelist contains at most one
|
||||
entry, which diminishes the memory consumption.
|
||||
|
||||
However, I very much doubt if we still need this -- Sergey */
|
||||
|
||||
/* A name_array 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 */
|
||||
|
||||
struct name_elt /* A name_array element. */
|
||||
{
|
||||
allocated_names = 10;
|
||||
name_array = xmalloc (sizeof (const char *) * allocated_names);
|
||||
names = 0;
|
||||
}
|
||||
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 */
|
||||
} v;
|
||||
};
|
||||
|
||||
/* Add NAME at end of name_array, reallocating it as necessary. */
|
||||
void
|
||||
name_add (const char *name)
|
||||
static struct name_elt *name_array; /* store an array of names */
|
||||
static size_t allocated_names; /* how big is the array? */
|
||||
static size_t names; /* how many entries does it have? */
|
||||
static size_t name_index; /* how many of the entries have we scanned? */
|
||||
|
||||
/* Check the size of name_array, reallocating it as necessary. */
|
||||
static void
|
||||
check_name_alloc ()
|
||||
{
|
||||
if (names == allocated_names)
|
||||
{
|
||||
allocated_names *= 2;
|
||||
name_array =
|
||||
xrealloc (name_array, sizeof (const char *) * allocated_names);
|
||||
if (allocated_names == 0)
|
||||
allocated_names = 10; /* Set initial allocation */
|
||||
name_array = x2nrealloc (name_array, &allocated_names,
|
||||
sizeof (name_array[0]));
|
||||
}
|
||||
name_array[names++] = name;
|
||||
}
|
||||
|
||||
/* Add to name_array the file NAME with fnmatch options MATCHING_FLAGS */
|
||||
void
|
||||
name_add_name (const char *name, int matching_flags)
|
||||
{
|
||||
static int prev_flags = 0; /* FIXME: Or EXCLUDE_ANCHORED? */
|
||||
struct name_elt *ep;
|
||||
|
||||
check_name_alloc ();
|
||||
ep = &name_array[names++];
|
||||
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[names++];
|
||||
}
|
||||
ep->type = NELT_NAME;
|
||||
ep->v.name = name;
|
||||
}
|
||||
|
||||
/* Add to name_array a chdir request for the directory NAME */
|
||||
void
|
||||
name_add_dir (const char *name)
|
||||
{
|
||||
struct name_elt *ep;
|
||||
check_name_alloc ();
|
||||
ep = &name_array[names++];
|
||||
ep->type = NELT_CHDIR;
|
||||
ep->v.name = name;
|
||||
}
|
||||
|
||||
|
||||
/* Names from external name file. */
|
||||
|
||||
static char *name_buffer; /* buffer to hold the current file name */
|
||||
static size_t name_buffer_length; /* allocated length of name_buffer */
|
||||
|
||||
/* FIXME: I should better check more closely. It seems at first glance that
|
||||
is_pattern is only used when reading a file, and ignored for all
|
||||
command line arguments. */
|
||||
|
||||
static inline int
|
||||
is_pattern (const char *string)
|
||||
{
|
||||
return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
|
||||
}
|
||||
|
||||
/* Set up to gather file names for tar. They can either come from a
|
||||
file or were saved from decoding arguments. */
|
||||
void
|
||||
@@ -242,27 +283,40 @@ name_term (void)
|
||||
free (name_array);
|
||||
}
|
||||
|
||||
/* Get the next name from ARGV or the file of names. Result is in
|
||||
static int matching_flags; /* exclude_fnmatch options */
|
||||
|
||||
/* Get the next NELT_NAME element from name_array. Result is in
|
||||
static storage and can't be relied upon across two calls.
|
||||
|
||||
If CHANGE_DIRS is true, treat a filename of the form "-C" as
|
||||
meaning that the next filename is the name of a directory to change
|
||||
to. If filename_terminator is NUL, CHANGE_DIRS is effectively
|
||||
always false. */
|
||||
char *
|
||||
name_next (int change_dirs)
|
||||
If CHANGE_DIRS is true, treat any entries of type NELT_CHDIR as
|
||||
the request to change to the given directory. If filename_terminator
|
||||
is NUL, CHANGE_DIRS is effectively always false.
|
||||
|
||||
Entries of type NELT_FMASK cause updates of the matching_flags
|
||||
value. */
|
||||
struct name_elt *
|
||||
name_next_elt (int change_dirs)
|
||||
{
|
||||
static struct name_elt entry;
|
||||
const char *source;
|
||||
char *cursor;
|
||||
int chdir_flag = 0;
|
||||
|
||||
if (filename_terminator == '\0')
|
||||
change_dirs = 0;
|
||||
|
||||
while (name_index != names)
|
||||
{
|
||||
struct name_elt *ep;
|
||||
size_t source_len;
|
||||
source = name_array[name_index++];
|
||||
|
||||
ep = &name_array[name_index++];
|
||||
if (ep->type == NELT_FMASK)
|
||||
{
|
||||
matching_flags = ep->v.matching_flags;
|
||||
continue;
|
||||
}
|
||||
|
||||
source = ep->v.name;
|
||||
source_len = strlen (source);
|
||||
if (name_buffer_length < source_len)
|
||||
{
|
||||
@@ -285,25 +339,31 @@ name_next (int change_dirs)
|
||||
while (cursor > name_buffer && ISSLASH (*cursor))
|
||||
*cursor-- = '\0';
|
||||
|
||||
if (chdir_flag)
|
||||
if (change_dirs && ep->type == NELT_CHDIR)
|
||||
{
|
||||
if (chdir (name_buffer) < 0)
|
||||
chdir_fatal (name_buffer);
|
||||
chdir_flag = 0;
|
||||
}
|
||||
else if (change_dirs && strcmp (name_buffer, "-C") == 0)
|
||||
chdir_flag = 1;
|
||||
else
|
||||
{
|
||||
if (unquote_option)
|
||||
unquote_string (name_buffer);
|
||||
if (incremental_option)
|
||||
register_individual_file (name_buffer);
|
||||
return name_buffer;
|
||||
entry.type = ep->type;
|
||||
entry.v.name = name_buffer;
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
name_next (int change_dirs)
|
||||
{
|
||||
struct name_elt *nelt = name_next_elt (change_dirs);
|
||||
return nelt ? nelt->v.name : NULL;
|
||||
}
|
||||
|
||||
/* Gather names in a list for scanning. Could hash them later if we
|
||||
@@ -323,7 +383,7 @@ name_gather (void)
|
||||
static struct name *buffer;
|
||||
static size_t allocated_size;
|
||||
|
||||
char const *name;
|
||||
struct name_elt *ep;
|
||||
|
||||
if (same_order_option)
|
||||
{
|
||||
@@ -336,19 +396,15 @@ name_gather (void)
|
||||
/* FIXME: This memset is overkill, and ugly... */
|
||||
memset (buffer, 0, allocated_size);
|
||||
}
|
||||
|
||||
while ((ep = name_next_elt (0)) && ep->type == NELT_CHDIR)
|
||||
change_dir = chdir_arg (xstrdup (ep->v.name));
|
||||
|
||||
while ((name = name_next (0)) && strcmp (name, "-C") == 0)
|
||||
{
|
||||
char const *dir = name_next (0);
|
||||
if (! dir)
|
||||
FATAL_ERROR ((0, 0, _("Missing file name after -C")));
|
||||
change_dir = chdir_arg (xstrdup (dir));
|
||||
}
|
||||
|
||||
if (name)
|
||||
if (ep)
|
||||
{
|
||||
size_t needed_size;
|
||||
buffer->length = strlen (name);
|
||||
|
||||
buffer->length = strlen (ep->v.name);
|
||||
needed_size = offsetof (struct name, name) + buffer->length + 1;
|
||||
if (allocated_size < needed_size)
|
||||
{
|
||||
@@ -363,10 +419,11 @@ name_gather (void)
|
||||
buffer = xrealloc (buffer, allocated_size);
|
||||
}
|
||||
buffer->change_dir = change_dir;
|
||||
strcpy (buffer->name, name);
|
||||
strcpy (buffer->name, ep->v.name);
|
||||
buffer->next = 0;
|
||||
buffer->found_count = 0;
|
||||
|
||||
buffer->matching_flags = matching_flags;
|
||||
|
||||
namelist = buffer;
|
||||
nametail = &namelist->next;
|
||||
}
|
||||
@@ -381,15 +438,11 @@ name_gather (void)
|
||||
for (;;)
|
||||
{
|
||||
int change_dir0 = change_dir;
|
||||
while ((name = name_next (0)) && strcmp (name, "-C") == 0)
|
||||
{
|
||||
char const *dir = name_next (0);
|
||||
if (! dir)
|
||||
FATAL_ERROR ((0, 0, _("Missing file name after -C")));
|
||||
change_dir = chdir_arg (xstrdup (dir));
|
||||
}
|
||||
if (name)
|
||||
addname (name, change_dir);
|
||||
while ((ep = name_next_elt (0)) && ep->type == NELT_CHDIR)
|
||||
change_dir = chdir_arg (xstrdup (ep->v.name));
|
||||
|
||||
if (ep)
|
||||
addname (ep->v.name, change_dir);
|
||||
else
|
||||
{
|
||||
if (change_dir != change_dir0)
|
||||
@@ -408,35 +461,16 @@ addname (char const *string, int change_dir)
|
||||
struct name *name = xmalloc (offsetof (struct name, name) + length + 1);
|
||||
|
||||
if (string)
|
||||
{
|
||||
name->fake = 0;
|
||||
strcpy (name->name, string);
|
||||
}
|
||||
strcpy (name->name, string);
|
||||
else
|
||||
{
|
||||
name->fake = 1;
|
||||
name->name[0] = 0;
|
||||
|
||||
/* FIXME: This initialization (and the byte of memory that it
|
||||
initializes) is probably not needed, but we are currently in
|
||||
bug-fix mode so we'll leave it in for now. */
|
||||
name->name[0] = 0;
|
||||
}
|
||||
|
||||
name->next = 0;
|
||||
name->next = NULL;
|
||||
name->length = length;
|
||||
name->found_count = 0;
|
||||
name->regexp = 0; /* assume not a regular expression */
|
||||
name->firstch = 1; /* assume first char is literal */
|
||||
name->matching_flags = matching_flags;
|
||||
name->change_dir = change_dir;
|
||||
name->dir_contents = 0;
|
||||
name->explicit = 1;
|
||||
|
||||
if (string && is_pattern (string))
|
||||
{
|
||||
name->regexp = 1;
|
||||
if (string[0] == '*' || string[0] == '[' || string[0] == '?')
|
||||
name->firstch = 0;
|
||||
}
|
||||
name->dir_contents = NULL;
|
||||
|
||||
*nametail = name;
|
||||
nametail = &name->next;
|
||||
@@ -446,34 +480,23 @@ addname (char const *string, int change_dir)
|
||||
/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
|
||||
list. */
|
||||
static struct name *
|
||||
namelist_match (char const *file_name, size_t length, bool exact)
|
||||
namelist_match (char const *file_name, size_t length)
|
||||
{
|
||||
struct name *p;
|
||||
|
||||
for (p = namelist; p; p = p->next)
|
||||
{
|
||||
/* If first chars don't match, quick skip. */
|
||||
|
||||
if (p->firstch && p->name[0] != file_name[0])
|
||||
continue;
|
||||
|
||||
if (p->regexp
|
||||
? fnmatch (p->name, file_name, recursion_option) == 0
|
||||
: exact ? (p->length == length
|
||||
&& memcmp (file_name, p->name, length) == 0)
|
||||
: (p->length <= length
|
||||
&& (file_name[p->length] == '\0'
|
||||
|| (ISSLASH (file_name[p->length]) && recursion_option))
|
||||
&& memcmp (file_name, p->name, p->length) == 0))
|
||||
if (p->name[0]
|
||||
&& exclude_fnmatch (p->name, file_name, p->matching_flags))
|
||||
return p;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return true if and only if name FILE_NAME (from an archive) matches any
|
||||
name from the namelist. */
|
||||
int
|
||||
bool
|
||||
name_match (const char *file_name)
|
||||
{
|
||||
size_t length = strlen (file_name);
|
||||
@@ -483,17 +506,17 @@ name_match (const char *file_name)
|
||||
struct name *cursor = namelist;
|
||||
|
||||
if (!cursor)
|
||||
return 1;
|
||||
|
||||
if (cursor->fake)
|
||||
return true;
|
||||
|
||||
if (cursor->name[0] == 0)
|
||||
{
|
||||
chdir_do (cursor->change_dir);
|
||||
namelist = 0;
|
||||
nametail = &namelist;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor = namelist_match (file_name, length, false);
|
||||
cursor = namelist_match (file_name, length);
|
||||
if (cursor)
|
||||
{
|
||||
if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
|
||||
@@ -520,10 +543,10 @@ name_match (const char *file_name)
|
||||
{
|
||||
name_gather (); /* read one more */
|
||||
if (namelist->found_count)
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,14 +572,39 @@ all_names_found (struct tar_stat_info *p)
|
||||
len = strlen (p->file_name);
|
||||
for (cursor = namelist; cursor; cursor = cursor->next)
|
||||
{
|
||||
if (cursor->regexp
|
||||
|| (!WASFOUND(cursor) && !cursor->fake)
|
||||
if (cursor->matching_flags /* FIXME: check this */
|
||||
|| (!WASFOUND (cursor) && cursor->name[0])
|
||||
|| (len >= cursor->length && ISSLASH (p->file_name[cursor->length])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_pattern (const char *string)
|
||||
{
|
||||
return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
|
||||
}
|
||||
|
||||
static void
|
||||
regex_usage_warning (const char *name)
|
||||
{
|
||||
static int warned_once = 0;
|
||||
|
||||
if (warn_regex_usage && is_pattern (name))
|
||||
{
|
||||
warned_once = 1;
|
||||
WARN ((0, 0,
|
||||
/* TRANSLATORS: The following three msgids form a single sentence.
|
||||
*/
|
||||
_("Pattern matching characters used in file names. Please,")));
|
||||
WARN ((0, 0,
|
||||
_("use --wildcards to enable pattern matching, or --no-wildcards to")));
|
||||
WARN ((0, 0,
|
||||
_("suppress this warning.")));
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the names of things in the namelist that were not matched. */
|
||||
void
|
||||
names_notfound (void)
|
||||
@@ -564,14 +612,15 @@ names_notfound (void)
|
||||
struct name const *cursor;
|
||||
|
||||
for (cursor = namelist; cursor; cursor = cursor->next)
|
||||
if (!WASFOUND(cursor) && !cursor->fake)
|
||||
if (!WASFOUND (cursor) && cursor->name[0])
|
||||
{
|
||||
regex_usage_warning (cursor->name);
|
||||
if (cursor->found_count == 0)
|
||||
ERROR ((0, 0, _("%s: Not found in archive"),
|
||||
quotearg_colon (cursor->name)));
|
||||
else
|
||||
ERROR ((0, 0, _("%s: Required occurrence not found in archive"),
|
||||
quotearg_colon (cursor->name)));
|
||||
quotearg_colon (cursor->name)));
|
||||
}
|
||||
|
||||
/* Don't bother freeing the name list; we're about to exit. */
|
||||
@@ -580,11 +629,14 @@ names_notfound (void)
|
||||
|
||||
if (same_order_option)
|
||||
{
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
while ((name = name_next (1)) != NULL)
|
||||
ERROR ((0, 0, _("%s: Not found in archive"),
|
||||
quotearg_colon (name)));
|
||||
{
|
||||
regex_usage_warning (name);
|
||||
ERROR ((0, 0, _("%s: Not found in archive"),
|
||||
quotearg_colon (name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,7 +780,6 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
|
||||
}
|
||||
strcpy (namebuf + name_length, string + 1);
|
||||
np = addname (namebuf, change_dir);
|
||||
np->explicit = 0;
|
||||
add_hierarchy_to_namelist (np, device);
|
||||
}
|
||||
}
|
||||
@@ -762,10 +813,12 @@ collect_and_sort_names (void)
|
||||
next_name = name->next;
|
||||
if (name->found_count || name->dir_contents)
|
||||
continue;
|
||||
if (name->regexp) /* FIXME: just skip regexps for now */
|
||||
if (name->matching_flags & EXCLUDE_WILDCARDS)
|
||||
/* NOTE: EXCLUDE_ANCHORED is not relevant here */
|
||||
/* FIXME: just skip regexps for now */
|
||||
continue;
|
||||
chdir_do (name->change_dir);
|
||||
if (name->fake)
|
||||
if (name->name[0] == 0)
|
||||
continue;
|
||||
|
||||
if (deref_stat (dereference_option, name->name, &statbuf) != 0)
|
||||
@@ -787,24 +840,29 @@ collect_and_sort_names (void)
|
||||
|
||||
for (name = namelist; name; name = name->next)
|
||||
name->found_count = 0;
|
||||
|
||||
if (listed_incremental_option)
|
||||
{
|
||||
for (name = namelist; name && name->name[0] == 0; name++)
|
||||
;
|
||||
if (name)
|
||||
name->dir_contents = append_incremental_renames (name->dir_contents);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is like name_match, except that
|
||||
1. It returns a pointer to the name it matched, and doesn't set FOUND
|
||||
in structure. The caller will have to do that if it wants to.
|
||||
2. If the namelist is empty, it returns null, unlike name_match, which
|
||||
returns TRUE.
|
||||
3. The second argument (EXACT) controls matching algorithm. If it
|
||||
is TRUE, the exact matching is used. However, regular expressions are
|
||||
always matched as such, no matter what the value of EXACT is. */
|
||||
returns TRUE. */
|
||||
struct name *
|
||||
name_scan (const char *file_name, bool exact)
|
||||
name_scan (const char *file_name)
|
||||
{
|
||||
size_t length = strlen (file_name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct name *cursor = namelist_match (file_name, length, exact);
|
||||
struct name *cursor = namelist_match (file_name, length);
|
||||
if (cursor)
|
||||
return cursor;
|
||||
|
||||
@@ -834,7 +892,8 @@ name_from_list (void)
|
||||
{
|
||||
if (!gnu_list_name)
|
||||
gnu_list_name = namelist;
|
||||
while (gnu_list_name && (gnu_list_name->found_count || gnu_list_name->fake))
|
||||
while (gnu_list_name
|
||||
&& (gnu_list_name->found_count || gnu_list_name->name[0] == 0))
|
||||
gnu_list_name = gnu_list_name->next;
|
||||
if (gnu_list_name)
|
||||
{
|
||||
@@ -856,7 +915,7 @@ blank_name_list (void)
|
||||
}
|
||||
|
||||
/* Yield a newly allocated file name consisting of FILE_NAME concatenated to
|
||||
NAME, with an intervening slash if FILE_NAME does not already end in one. */
|
||||
NAME, with an intervening slash if FILE_NAME does not already end in one. */
|
||||
char *
|
||||
new_name (const char *file_name, const char *name)
|
||||
{
|
||||
|
||||
311
src/sparse.c
311
src/sparse.c
@@ -1,6 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2004, 2005, 2006 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
|
||||
@@ -409,15 +409,6 @@ sparse_dump_file (int fd, struct tar_stat_info *st)
|
||||
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
|
||||
}
|
||||
|
||||
/* Returns true if the file represented by stat is a sparse one */
|
||||
bool
|
||||
sparse_file_p (struct tar_stat_info *st)
|
||||
{
|
||||
return (ST_NBLOCKS (st->stat)
|
||||
< (st->stat.st_size / ST_NBLOCKSIZE
|
||||
+ (st->stat.st_size % ST_NBLOCKSIZE != 0)));
|
||||
}
|
||||
|
||||
bool
|
||||
sparse_member_p (struct tar_stat_info *st)
|
||||
{
|
||||
@@ -740,11 +731,9 @@ oldgnu_dump_header (struct tar_sparse_file *file)
|
||||
oldgnu_store_sparse_info (file, &i,
|
||||
blk->sparse_header.sp,
|
||||
SPARSES_IN_SPARSE_HEADER);
|
||||
set_next_block_after (blk);
|
||||
if (i < file->stat_info->sparse_map_avail)
|
||||
blk->sparse_header.isextended = 1;
|
||||
else
|
||||
break;
|
||||
set_next_block_after (blk);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -843,16 +832,15 @@ static struct tar_sparse_optab const star_optab = {
|
||||
};
|
||||
|
||||
|
||||
/* GNU PAX sparse file format. The sparse file map is stored in
|
||||
x header:
|
||||
/* GNU PAX sparse file format. There are several versions:
|
||||
|
||||
* 0.0
|
||||
|
||||
The initial version of sparse format used by tar 1.14-1.15.1.
|
||||
The sparse file map is stored in x header:
|
||||
|
||||
GNU.sparse.size Real size of the stored file
|
||||
GNU.sparse.numblocks Number of blocks in the sparse map
|
||||
GNU.sparse.map Map of non-null data chunks. A string consisting
|
||||
of comma-separated values "offset,size[,offset,size]..."
|
||||
|
||||
Tar versions 1.14-1.15.1 instead of the latter used:
|
||||
|
||||
repeat numblocks time
|
||||
GNU.sparse.offset Offset of the next data block
|
||||
GNU.sparse.numbytes Size of the next data block
|
||||
@@ -860,44 +848,89 @@ static struct tar_sparse_optab const star_optab = {
|
||||
|
||||
This has been reported as conflicting with the POSIX specs. The reason is
|
||||
that offsets and sizes of non-zero data blocks were stored in multiple
|
||||
instances of GNU.sparse.offset/GNU.sparse.numbytes variables. However,
|
||||
instances of GNU.sparse.offset/GNU.sparse.numbytes variables, whereas
|
||||
POSIX requires the latest occurrence of the variable to override all
|
||||
previous occurrences.
|
||||
|
||||
To avoid this incompatibility new keyword GNU.sparse.map was introduced
|
||||
in tar 1.15.2. Some people might still need the 1.14 way of handling
|
||||
sparse files for the compatibility reasons: it can be achieved by
|
||||
specifying `--pax-option delete=GNU.sparse.map' in the command line.
|
||||
|
||||
To avoid this incompatibility two following versions were introduced.
|
||||
|
||||
See FIXME-1.14-1.15.1-1.20, below.
|
||||
* 0.1
|
||||
|
||||
Used by tar 1.15.2 -- 1.15.91 (alpha releases).
|
||||
|
||||
The sparse file map is stored in
|
||||
x header:
|
||||
|
||||
GNU.sparse.size Real size of the stored file
|
||||
GNU.sparse.numblocks Number of blocks in the sparse map
|
||||
GNU.sparse.map Map of non-null data chunks. A string consisting
|
||||
of comma-separated values "offset,size[,offset,size]..."
|
||||
|
||||
The resulting GNU.sparse.map string can be *very* long. While POSIX does not
|
||||
impose any limit on the length of a x header variable, this can confuse some
|
||||
tars.
|
||||
|
||||
* 1.0
|
||||
|
||||
Starting from this version, the exact sparse format version is specified
|
||||
explicitely in the header using the following variables:
|
||||
|
||||
GNU.sparse.major Major version
|
||||
GNU.sparse.minor Minor version
|
||||
|
||||
X header keeps the following variables:
|
||||
|
||||
GNU.sparse.name Real file name of the sparse file
|
||||
GNU.sparse.realsize Real size of the stored file (corresponds to the old
|
||||
GNU.sparse.size variable)
|
||||
|
||||
The name field of the ustar header is constructed using the pattern
|
||||
"%d/GNUSparseFile.%p/%f".
|
||||
|
||||
The sparse map itself is stored in the file data block, preceding the actual
|
||||
file data. It consists of a series of octal numbers of arbitrary length,
|
||||
delimited by newlines. The map is padded with nulls to the nearest block
|
||||
boundary.
|
||||
|
||||
The first number gives the number of entries in the map. Following are map
|
||||
entries, each one consisting of two numbers giving the offset and size of
|
||||
the data block it describes.
|
||||
|
||||
The format is designed in such a way that non-posix aware tars and tars not
|
||||
supporting GNU.sparse.* keywords will extract each sparse file in its
|
||||
condensed form with the file map attached and will place it into a separate
|
||||
directory. Then, using a simple program it would be possible to expand the
|
||||
file to its original form even without GNU tar.
|
||||
|
||||
Bu default, v.1.0 archives are created. To use other formats,
|
||||
--sparse-version option is provided. Additionally, v.0.0 can be obtained
|
||||
by deleting GNU.sparse.map from 0.1 format: --sparse-version 0.1
|
||||
--pax-option delete=GNU.sparse.map
|
||||
*/
|
||||
|
||||
static bool
|
||||
pax_sparse_member_p (struct tar_sparse_file *file)
|
||||
{
|
||||
return file->stat_info->sparse_map_avail > 0;
|
||||
return file->stat_info->sparse_map_avail > 0
|
||||
|| file->stat_info->sparse_major > 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_dump_header (struct tar_sparse_file *file)
|
||||
pax_dump_header_0 (struct tar_sparse_file *file)
|
||||
{
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
union block *blk;
|
||||
size_t i;
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
struct sp_array *map = file->stat_info->sparse_map;
|
||||
|
||||
char *save_file_name = NULL;
|
||||
|
||||
/* Store the real file size */
|
||||
xheader_store ("GNU.sparse.size", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
|
||||
|
||||
/* FIXME-1.14-1.15.1-1.20: See the comment above.
|
||||
Starting with 1.17 this should display a warning about POSIX-incompatible
|
||||
keywords being generated. In 1.20, the true branch of the if block below
|
||||
will be removed and GNU.sparse.map will be marked in xhdr_tab as
|
||||
protected. */
|
||||
|
||||
if (xheader_keyword_deleted_p ("GNU.sparse.map"))
|
||||
if (xheader_keyword_deleted_p ("GNU.sparse.map")
|
||||
|| tar_sparse_minor == 0)
|
||||
{
|
||||
for (i = 0; i < file->stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
@@ -907,6 +940,11 @@ pax_dump_header (struct tar_sparse_file *file)
|
||||
}
|
||||
else
|
||||
{
|
||||
xheader_store ("GNU.sparse.name", file->stat_info, NULL);
|
||||
save_file_name = file->stat_info->file_name;
|
||||
file->stat_info->file_name = xheader_format_name (file->stat_info,
|
||||
"%d/GNUSparseFile.%p/%f", 0);
|
||||
|
||||
xheader_string_begin ();
|
||||
for (i = 0; i < file->stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
@@ -916,12 +954,205 @@ pax_dump_header (struct tar_sparse_file *file)
|
||||
xheader_string_add (",");
|
||||
xheader_string_add (umaxtostr (map[i].numbytes, nbuf));
|
||||
}
|
||||
xheader_string_end ("GNU.sparse.map");
|
||||
if (!xheader_string_end ("GNU.sparse.map"))
|
||||
{
|
||||
free (file->stat_info->file_name);
|
||||
file->stat_info->file_name = save_file_name;
|
||||
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);
|
||||
finish_header (file->stat_info, blk, block_ordinal);
|
||||
if (save_file_name)
|
||||
{
|
||||
free (file->stat_info->file_name);
|
||||
file->stat_info->file_name = save_file_name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_dump_header_1 (struct tar_sparse_file *file)
|
||||
{
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
union block *blk;
|
||||
char *p, *q;
|
||||
size_t i;
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
off_t size = 0;
|
||||
struct sp_array *map = file->stat_info->sparse_map;
|
||||
char *save_file_name = file->stat_info->file_name;
|
||||
|
||||
#define COPY_STRING(b,dst,src) do \
|
||||
{ \
|
||||
char *endp = b->buffer + BLOCKSIZE; \
|
||||
char *srcp = src; \
|
||||
while (*srcp) \
|
||||
{ \
|
||||
if (dst == endp) \
|
||||
{ \
|
||||
set_next_block_after (b); \
|
||||
b = find_next_block (); \
|
||||
dst = b->buffer; \
|
||||
endp = b->buffer + BLOCKSIZE; \
|
||||
} \
|
||||
*dst++ = *srcp++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Compute stored file size */
|
||||
p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
|
||||
size += strlen (p) + 1;
|
||||
for (i = 0; i < file->stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
p = umaxtostr (map[i].offset, nbuf);
|
||||
size += strlen (p) + 1;
|
||||
p = umaxtostr (map[i].numbytes, nbuf);
|
||||
size += strlen (p) + 1;
|
||||
}
|
||||
size = (size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
file->stat_info->archive_file_size += size * BLOCKSIZE;
|
||||
|
||||
/* Store sparse file identification */
|
||||
xheader_store ("GNU.sparse.major", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.minor", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.name", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.realsize", file->stat_info, NULL);
|
||||
|
||||
file->stat_info->file_name = xheader_format_name (file->stat_info,
|
||||
"%d/GNUSparseFile.%p/%f", 0);
|
||||
|
||||
blk = start_header (file->stat_info);
|
||||
/* Store the effective (shrunken) file size */
|
||||
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
|
||||
finish_header (file->stat_info, blk, block_ordinal);
|
||||
free (file->stat_info->file_name);
|
||||
file->stat_info->file_name = save_file_name;
|
||||
|
||||
blk = find_next_block ();
|
||||
q = blk->buffer;
|
||||
p = umaxtostr (file->stat_info->sparse_map_avail, nbuf);
|
||||
COPY_STRING (blk, q, p);
|
||||
COPY_STRING (blk, q, "\n");
|
||||
for (i = 0; i < file->stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
p = umaxtostr (map[i].offset, nbuf);
|
||||
COPY_STRING (blk, q, p);
|
||||
COPY_STRING (blk, q, "\n");
|
||||
p = umaxtostr (map[i].numbytes, nbuf);
|
||||
COPY_STRING (blk, q, p);
|
||||
COPY_STRING (blk, q, "\n");
|
||||
}
|
||||
memset (q, 0, BLOCKSIZE - (q - blk->buffer));
|
||||
set_next_block_after (blk);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_dump_header (struct tar_sparse_file *file)
|
||||
{
|
||||
file->stat_info->sparse_major = tar_sparse_major;
|
||||
file->stat_info->sparse_minor = tar_sparse_minor;
|
||||
|
||||
return (file->stat_info->sparse_major == 0) ?
|
||||
pax_dump_header_0 (file) : pax_dump_header_1 (file);
|
||||
}
|
||||
|
||||
static bool
|
||||
decode_num (uintmax_t *num, char const *arg, uintmax_t maxval)
|
||||
{
|
||||
uintmax_t u;
|
||||
char *arg_lim;
|
||||
|
||||
if (!ISDIGIT (*arg))
|
||||
return false;
|
||||
|
||||
u = strtoumax (arg, &arg_lim, 10);
|
||||
|
||||
if (! (u <= maxval && errno != ERANGE) || *arg_lim)
|
||||
return false;
|
||||
|
||||
*num = u;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_decode_header (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->stat_info->sparse_major > 0)
|
||||
{
|
||||
uintmax_t u;
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
union block *blk;
|
||||
char *p;
|
||||
size_t i;
|
||||
|
||||
#define COPY_BUF(b,buf,src) do \
|
||||
{ \
|
||||
char *endp = b->buffer + BLOCKSIZE; \
|
||||
char *dst = buf; \
|
||||
do \
|
||||
{ \
|
||||
if (dst == buf + UINTMAX_STRSIZE_BOUND -1) \
|
||||
{ \
|
||||
ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"), \
|
||||
file->stat_info->orig_file_name)); \
|
||||
return false; \
|
||||
} \
|
||||
if (src == endp) \
|
||||
{ \
|
||||
set_next_block_after (b); \
|
||||
b = find_next_block (); \
|
||||
src = b->buffer; \
|
||||
endp = b->buffer + BLOCKSIZE; \
|
||||
} \
|
||||
*dst = *src++; \
|
||||
} \
|
||||
while (*dst++ != '\n'); \
|
||||
dst[-1] = 0; \
|
||||
} while (0)
|
||||
|
||||
set_next_block_after (current_header);
|
||||
blk = find_next_block ();
|
||||
p = blk->buffer;
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
file->stat_info->sparse_map_size = u;
|
||||
file->stat_info->sparse_map = xcalloc (file->stat_info->sparse_map_size,
|
||||
sizeof (*file->stat_info->sparse_map));
|
||||
file->stat_info->sparse_map_avail = 0;
|
||||
for (i = 0; i < file->stat_info->sparse_map_size; i++)
|
||||
{
|
||||
struct sp_array sp;
|
||||
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
sp.offset = u;
|
||||
COPY_BUF (blk,nbuf,p);
|
||||
if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
|
||||
{
|
||||
ERROR ((0, 0, _("%s: malformed sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
sp.numbytes = u;
|
||||
sparse_add_map (file->stat_info, &sp);
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -930,8 +1161,8 @@ static struct tar_sparse_optab const pax_optab = {
|
||||
NULL, /* No done function */
|
||||
pax_sparse_member_p,
|
||||
pax_dump_header,
|
||||
NULL, /* No decode_header function */
|
||||
NULL, /* No fixup_header function */
|
||||
NULL,
|
||||
pax_decode_header,
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
|
||||
569
src/tar.c
569
src/tar.c
@@ -25,6 +25,7 @@
|
||||
#include <getline.h>
|
||||
#include <argp.h>
|
||||
#include <argp-namefrob.h>
|
||||
#include <argp-fmtstream.h>
|
||||
|
||||
#include <signal.h>
|
||||
#if ! defined SIGCHLD && defined SIGCLD
|
||||
@@ -217,12 +218,12 @@ subcommand_string (enum subcommand c)
|
||||
}
|
||||
|
||||
void
|
||||
tar_list_quoting_styles (FILE *fp, char *prefix)
|
||||
tar_list_quoting_styles (argp_fmtstream_t fs, char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; quoting_style_args[i]; i++)
|
||||
fprintf (fp, "%s%s\n", prefix, quoting_style_args[i]);
|
||||
argp_fmtstream_printf (fs, "%s%s\n", prefix, quoting_style_args[i]);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -249,7 +250,6 @@ enum
|
||||
ATIME_PRESERVE_OPTION,
|
||||
BACKUP_OPTION,
|
||||
CHECKPOINT_OPTION,
|
||||
CHECK_LINKS_OPTION,
|
||||
DELAY_DIRECTORY_RESTORE_OPTION,
|
||||
DELETE_OPTION,
|
||||
EXCLUDE_CACHES_OPTION,
|
||||
@@ -263,6 +263,7 @@ enum
|
||||
INDEX_FILE_OPTION,
|
||||
KEEP_NEWER_FILES_OPTION,
|
||||
MODE_OPTION,
|
||||
MTIME_OPTION,
|
||||
NEWER_MTIME_OPTION,
|
||||
NO_ANCHORED_OPTION,
|
||||
NO_DELAY_DIRECTORY_RESTORE_OPTION,
|
||||
@@ -281,6 +282,7 @@ enum
|
||||
OCCURRENCE_OPTION,
|
||||
OLD_ARCHIVE_OPTION,
|
||||
ONE_FILE_SYSTEM_OPTION,
|
||||
OVERWRITE_DIR_OPTION,
|
||||
OVERWRITE_OPTION,
|
||||
OWNER_OPTION,
|
||||
PAX_OPTION,
|
||||
@@ -298,12 +300,14 @@ enum
|
||||
SAME_OWNER_OPTION,
|
||||
SHOW_DEFAULTS_OPTION,
|
||||
SHOW_OMITTED_DIRS_OPTION,
|
||||
SHOW_STORED_NAMES_OPTION,
|
||||
SHOW_TRANSFORMED_NAMES_OPTION,
|
||||
SPARSE_VERSION_OPTION,
|
||||
STRIP_COMPONENTS_OPTION,
|
||||
SUFFIX_OPTION,
|
||||
TEST_LABEL_OPTION,
|
||||
TOTALS_OPTION,
|
||||
TO_COMMAND_OPTION,
|
||||
TRANSFORM_OPTION,
|
||||
UNQUOTE_OPTION,
|
||||
USAGE_OPTION,
|
||||
USE_COMPRESS_PROGRAM_OPTION,
|
||||
@@ -316,13 +320,16 @@ enum
|
||||
|
||||
const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
|
||||
const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
|
||||
static char doc[] = N_("GNU `tar' saves many files together into a single tape or disk archive, and can restore individual files from the archive.\n\
|
||||
static char const doc[] = N_("\
|
||||
GNU `tar' saves many files together into a single tape or disk archive, \
|
||||
and can restore individual files from the archive.\n\
|
||||
\n\
|
||||
Examples:\n\
|
||||
tar -cf archive.tar foo bar # Create archive.tar from files foo and bar.\n\
|
||||
tar -tvf archive.tar # List all files in archive.tar verbosely.\n\
|
||||
tar -xf archive.tar # Extract all files from archive.tar.\n\
|
||||
\vThe backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
|
||||
tar -xf archive.tar # Extract all files from archive.tar.\n")
|
||||
"\v"
|
||||
N_("The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
|
||||
The version control may be set with --backup or VERSION_CONTROL, values are:\n\n\
|
||||
none, off never make backups\n\
|
||||
t, numbered make numbered backups\n\
|
||||
@@ -379,6 +386,8 @@ static struct argp_option options[] = {
|
||||
|
||||
{"sparse", 'S', 0, 0,
|
||||
N_("handle sparse files efficiently"), GRID+1 },
|
||||
{"sparse-version", SPARSE_VERSION_OPTION, N_("MAJOR[.MINOR]"), 0,
|
||||
N_("set version of the sparse format to use (implies --sparse)"), GRID+1},
|
||||
{"incremental", 'G', 0, 0,
|
||||
N_("handle old GNU-format incremental backup"), GRID+1 },
|
||||
{"listed-incremental", 'g', N_("FILE"), 0,
|
||||
@@ -397,7 +406,7 @@ static struct argp_option options[] = {
|
||||
|
||||
#define GRID 30
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("Overwrite control:\n"), GRID+1 },
|
||||
N_("Overwrite control:"), GRID },
|
||||
|
||||
{"verify", 'W', 0, 0,
|
||||
N_("attempt to verify the archive after writing it"), GRID+1 },
|
||||
@@ -415,6 +424,9 @@ static struct argp_option options[] = {
|
||||
N_("empty hierarchies prior to extracting directory"), GRID+1 },
|
||||
{"no-overwrite-dir", NO_OVERWRITE_DIR_OPTION, 0, 0,
|
||||
N_("preserve metadata of existing directories"), GRID+1 },
|
||||
{"overwrite-dir", OVERWRITE_DIR_OPTION, 0, 0,
|
||||
N_("overwrite metadata of existing directories when extracting (default)"),
|
||||
GRID+1 },
|
||||
#undef GRID
|
||||
|
||||
#define GRID 40
|
||||
@@ -439,6 +451,8 @@ static struct argp_option options[] = {
|
||||
N_("force NAME as owner for added files"), GRID+1 },
|
||||
{"group", GROUP_OPTION, N_("NAME"), 0,
|
||||
N_("force NAME as group for added files"), GRID+1 },
|
||||
{"mtime", MTIME_OPTION, N_("DATE-OR-FILE"), 0,
|
||||
N_("set mtime for added files from DATE-OR-FILE"), GRID+1 },
|
||||
{"mode", MODE_OPTION, N_("CHANGES"), 0,
|
||||
N_("force (symbolic) mode CHANGES for added files"), GRID+1 },
|
||||
{"atime-preserve", ATIME_PRESERVE_OPTION,
|
||||
@@ -474,7 +488,7 @@ static struct argp_option options[] = {
|
||||
|
||||
#define GRID 60
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("Device selection and switching:\n"), GRID+1 },
|
||||
N_("Device selection and switching:"), GRID },
|
||||
|
||||
{"file", 'f', N_("ARCHIVE"), 0,
|
||||
N_("use archive file or device ARCHIVE"), GRID+1 },
|
||||
@@ -513,7 +527,7 @@ static struct argp_option options[] = {
|
||||
|
||||
#define GRID 70
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("Device blocking:"), GRID+1 },
|
||||
N_("Device blocking:"), GRID },
|
||||
|
||||
{"blocking-factor", 'b', N_("BLOCKS"), 0,
|
||||
N_("BLOCKS x 512 bytes per record"), GRID+1 },
|
||||
@@ -589,23 +603,10 @@ static struct argp_option options[] = {
|
||||
N_("exclude patterns listed in FILE"), GRID+1 },
|
||||
{"exclude-caches", EXCLUDE_CACHES_OPTION, 0, 0,
|
||||
N_("exclude directories containing a cache tag"), GRID+1 },
|
||||
{"ignore-case", IGNORE_CASE_OPTION, 0, 0,
|
||||
N_("exclusion ignores case"), GRID+1 },
|
||||
{"anchored", ANCHORED_OPTION, 0, 0,
|
||||
N_("exclude patterns match file name start"), GRID+1 },
|
||||
{"no-anchored", NO_ANCHORED_OPTION, 0, 0,
|
||||
N_("exclude patterns match after any `/' (default)"), GRID+1 },
|
||||
{"no-ignore-case", NO_IGNORE_CASE_OPTION, 0, 0,
|
||||
N_("exclusion is case sensitive (default)"), GRID+1 },
|
||||
{"no-wildcards", NO_WILDCARDS_OPTION, 0, 0,
|
||||
N_("exclude patterns are plain strings"), GRID+1 },
|
||||
{"no-wildcards-match-slash", NO_WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
|
||||
N_("exclude pattern wildcards do not match `/'"), GRID+1 },
|
||||
{"no-recursion", NO_RECURSION_OPTION, 0, 0,
|
||||
N_("avoid descending automatically in directories"), GRID+1 },
|
||||
{"one-file-system", ONE_FILE_SYSTEM_OPTION, 0, 0,
|
||||
N_("stay in local file system when creating archive"), GRID+1 },
|
||||
{NULL, 'l', 0, OPTION_HIDDEN, "", GRID+1 },
|
||||
{"recursion", RECURSION_OPTION, 0, 0,
|
||||
N_("recurse into directories (default)"), GRID+1 },
|
||||
{"absolute-names", 'P', 0, 0,
|
||||
@@ -614,22 +615,47 @@ static struct argp_option options[] = {
|
||||
N_("follow symlinks; archive and dump the files they point to"), GRID+1 },
|
||||
{"starting-file", 'K', N_("MEMBER-NAME"), 0,
|
||||
N_("begin at member MEMBER-NAME in the archive"), GRID+1 },
|
||||
{"strip-components", STRIP_COMPONENTS_OPTION, N_("NUMBER"), 0,
|
||||
N_("strip NUMBER leading components from file names"), GRID+1 },
|
||||
{"newer", 'N', N_("DATE-OR-FILE"), 0,
|
||||
N_("only store files newer than DATE-OR-FILE"), GRID+1 },
|
||||
{"after-date", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
|
||||
{"newer-mtime", NEWER_MTIME_OPTION, N_("DATE"), 0,
|
||||
N_("compare date and time when data changed only"), GRID+1 },
|
||||
{"after-date", 'N', N_("DATE"), 0,
|
||||
N_("same as -N"), GRID+1 },
|
||||
{"backup", BACKUP_OPTION, N_("CONTROL"), OPTION_ARG_OPTIONAL,
|
||||
N_("backup before removal, choose version CONTROL"), GRID+1 },
|
||||
{"suffix", SUFFIX_OPTION, N_("STRING"), 0,
|
||||
N_("backup before removal, override usual suffix ('~' unless overridden by environment variable SIMPLE_BACKUP_SUFFIX)"), GRID+1 },
|
||||
#undef GRID
|
||||
|
||||
#define GRID 92
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("File name transformations:"), GRID },
|
||||
{"strip-components", STRIP_COMPONENTS_OPTION, N_("NUMBER"), 0,
|
||||
N_("strip NUMBER leading components from file names on extraction"),
|
||||
GRID+1 },
|
||||
{"transform", TRANSFORM_OPTION, N_("EXPRESSION"), 0,
|
||||
N_("use sed replace EXPRESSION to transform file names"), GRID+1 },
|
||||
#undef GRID
|
||||
|
||||
#define GRID 95
|
||||
{NULL, 0, NULL, 0,
|
||||
N_("File name matching options (affect both exclude and include patterns):"),
|
||||
GRID },
|
||||
{"ignore-case", IGNORE_CASE_OPTION, 0, 0,
|
||||
N_("ignore case"), GRID+1 },
|
||||
{"anchored", ANCHORED_OPTION, 0, 0,
|
||||
N_("patterns match file name start"), GRID+1 },
|
||||
{"no-anchored", NO_ANCHORED_OPTION, 0, 0,
|
||||
N_("patterns match after any `/' (default for exclusion)"), GRID+1 },
|
||||
{"no-ignore-case", NO_IGNORE_CASE_OPTION, 0, 0,
|
||||
N_("case sensitive matching (default)"), GRID+1 },
|
||||
{"wildcards", WILDCARDS_OPTION, 0, 0,
|
||||
N_("exclude patterns use wildcards (default)"), GRID+1 },
|
||||
N_("use wildcards (default for exclusion)"), GRID+1 },
|
||||
{"no-wildcards", NO_WILDCARDS_OPTION, 0, 0,
|
||||
N_("verbatim string matching"), GRID+1 },
|
||||
{"no-wildcards-match-slash", NO_WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
|
||||
N_("wildcards do not match `/'"), GRID+1 },
|
||||
{"wildcards-match-slash", WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
|
||||
N_("exclude pattern wildcards match `/' (default)"), GRID+1 },
|
||||
N_("wildcards match `/' (default for exclusion)"), GRID+1 },
|
||||
#undef GRID
|
||||
|
||||
#define GRID 100
|
||||
@@ -638,12 +664,16 @@ static struct argp_option options[] = {
|
||||
|
||||
{"verbose", 'v', 0, 0,
|
||||
N_("verbosely list files processed"), GRID+1 },
|
||||
{"checkpoint", CHECKPOINT_OPTION, 0, 0,
|
||||
N_("display progress messages every 10th record"), GRID+1 },
|
||||
{"check-links", CHECK_LINKS_OPTION, 0, 0,
|
||||
{"checkpoint", CHECKPOINT_OPTION, N_("[.]NUMBER"), OPTION_ARG_OPTIONAL,
|
||||
N_("display progress messages every NUMBERth record (default 10)"),
|
||||
GRID+1 },
|
||||
{"check-links", 'l', 0, 0,
|
||||
N_("print a message if not all links are dumped"), GRID+1 },
|
||||
{"totals", TOTALS_OPTION, 0, 0,
|
||||
N_("print total bytes written while creating archive"), GRID+1 },
|
||||
{"totals", TOTALS_OPTION, N_("SIGNAL"), OPTION_ARG_OPTIONAL,
|
||||
N_("print total bytes after processing the archive; "
|
||||
"with an argument - print total bytes when this SIGNAL is delivered; "
|
||||
"Allowed signals are: SIGHUP, SIGQUIT, SIGINT, SIGUSR1 and SIGUSR2; "
|
||||
"the names without SIG prefix are also accepted"), GRID+1 },
|
||||
{"utc", UTC_OPTION, 0, 0,
|
||||
N_("print file modification dates in UTC"), GRID+1 },
|
||||
{"index-file", INDEX_FILE_OPTION, N_("FILE"), 0,
|
||||
@@ -657,9 +687,10 @@ static struct argp_option options[] = {
|
||||
N_("show tar defaults"), GRID+1 },
|
||||
{"show-omitted-dirs", SHOW_OMITTED_DIRS_OPTION, 0, 0,
|
||||
N_("when listing or extracting, list each directory that does not match search criteria"), GRID+1 },
|
||||
{"show-stored-names", SHOW_STORED_NAMES_OPTION, 0, 0,
|
||||
N_("when creating archive in verbose mode, list member names as stored in the archive"),
|
||||
{"show-transformed-names", SHOW_TRANSFORMED_NAMES_OPTION, 0, 0,
|
||||
N_("show file or archive names after transformation"),
|
||||
GRID+1 },
|
||||
{"show-stored-names", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
|
||||
{"quoting-style", QUOTING_STYLE_OPTION, N_("STYLE"), 0,
|
||||
N_("set name quoting style; see below for valid STYLE values"), GRID+1 },
|
||||
{"quote-chars", QUOTE_CHARS_OPTION, N_("STRING"), 0,
|
||||
@@ -699,37 +730,85 @@ static char const *const atime_preserve_args[] =
|
||||
{
|
||||
"replace", "system", NULL
|
||||
};
|
||||
|
||||
static enum atime_preserve const atime_preserve_types[] =
|
||||
{
|
||||
replace_atime_preserve, system_atime_preserve
|
||||
};
|
||||
|
||||
/* Make sure atime_preserve_types has as much entries as atime_preserve_args
|
||||
(minus 1 for NULL guard) */
|
||||
ARGMATCH_VERIFY (atime_preserve_args, atime_preserve_types);
|
||||
|
||||
/* Wildcard matching settings */
|
||||
enum wildcards
|
||||
{
|
||||
default_wildcards, /* For exclusion == enable_wildcards,
|
||||
for inclusion == disable_wildcards */
|
||||
disable_wildcards,
|
||||
enable_wildcards
|
||||
};
|
||||
|
||||
struct tar_args {
|
||||
char const *textual_date_option;
|
||||
int exclude_options;
|
||||
bool o_option;
|
||||
int pax_option;
|
||||
char const *backup_suffix_string;
|
||||
char const *version_control_string;
|
||||
int input_files;
|
||||
struct tar_args /* Variables used during option parsing */
|
||||
{
|
||||
struct textual_date *textual_date; /* Keeps the arguments to --newer-mtime
|
||||
and/or --date option if they are
|
||||
textual dates */
|
||||
enum wildcards wildcards; /* Wildcard settings (--wildcards/
|
||||
--no-wildcards) */
|
||||
int matching_flags; /* exclude_fnmatch options */
|
||||
int include_anchored; /* Pattern anchoring options used for
|
||||
file inclusion */
|
||||
bool o_option; /* True if -o option was given */
|
||||
bool pax_option; /* True if --pax-option was given */
|
||||
char const *backup_suffix_string; /* --suffix option argument */
|
||||
char const *version_control_string; /* --backup option argument */
|
||||
bool input_files; /* True if some input files where given */
|
||||
};
|
||||
|
||||
static void
|
||||
show_default_settings (FILE *stream)
|
||||
{
|
||||
fprintf (stream,
|
||||
"--format=%s -f%s -b%d --quoting-style=%s --rmt-command=%s",
|
||||
archive_format_string (DEFAULT_ARCHIVE_FORMAT),
|
||||
DEFAULT_ARCHIVE, DEFAULT_BLOCKING,
|
||||
quoting_style_args[DEFAULT_QUOTING_STYLE],
|
||||
DEFAULT_RMT_COMMAND);
|
||||
#define MAKE_EXCL_OPTIONS(args) \
|
||||
((((args)->wildcards != disable_wildcards) ? EXCLUDE_WILDCARDS : 0) \
|
||||
| (args)->matching_flags \
|
||||
| recursion_option)
|
||||
|
||||
#define MAKE_INCL_OPTIONS(args) \
|
||||
((((args)->wildcards == enable_wildcards) ? EXCLUDE_WILDCARDS : 0) \
|
||||
| (args)->include_anchored \
|
||||
| (args)->matching_flags \
|
||||
| recursion_option)
|
||||
|
||||
#ifdef REMOTE_SHELL
|
||||
fprintf (stream, " --rsh-command=%s", REMOTE_SHELL);
|
||||
#endif
|
||||
fprintf (stream, "\n");
|
||||
# define DECL_SHOW_DEFAULT_SETTINGS(stream, printer) \
|
||||
{ \
|
||||
printer (stream, \
|
||||
"--format=%s -f%s -b%d --quoting-style=%s --rmt-command=%s", \
|
||||
archive_format_string (DEFAULT_ARCHIVE_FORMAT), \
|
||||
DEFAULT_ARCHIVE, DEFAULT_BLOCKING, \
|
||||
quoting_style_args[DEFAULT_QUOTING_STYLE], \
|
||||
DEFAULT_RMT_COMMAND); \
|
||||
printer (stream, " --rsh-command=%s", REMOTE_SHELL); \
|
||||
printer (stream, "\n"); \
|
||||
}
|
||||
#else
|
||||
# define DECL_SHOW_DEFAULT_SETTINGS(stream, printer) \
|
||||
{ \
|
||||
printer (stream, \
|
||||
"--format=%s -f%s -b%d --quoting-style=%s --rmt-command=%s", \
|
||||
archive_format_string (DEFAULT_ARCHIVE_FORMAT), \
|
||||
DEFAULT_ARCHIVE, DEFAULT_BLOCKING, \
|
||||
quoting_style_args[DEFAULT_QUOTING_STYLE], \
|
||||
DEFAULT_RMT_COMMAND); \
|
||||
printer (stream, "\n"); \
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
show_default_settings (FILE *fp)
|
||||
DECL_SHOW_DEFAULT_SETTINGS(fp, fprintf)
|
||||
|
||||
static void
|
||||
show_default_settings_fs (argp_fmtstream_t fs)
|
||||
DECL_SHOW_DEFAULT_SETTINGS(fs, argp_fmtstream_printf)
|
||||
|
||||
static void
|
||||
set_subcommand_option (enum subcommand subcommand)
|
||||
@@ -751,7 +830,123 @@ set_use_compress_program_option (const char *string)
|
||||
|
||||
use_compress_program_option = string;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
sigstat (int signo)
|
||||
{
|
||||
compute_duration ();
|
||||
print_total_stats ();
|
||||
#ifndef HAVE_SIGACTION
|
||||
signal (signo, sigstat);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
stat_on_signal (int signo)
|
||||
{
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction act;
|
||||
act.sa_handler = sigstat;
|
||||
sigemptyset (&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction (signo, &act, NULL);
|
||||
#else
|
||||
signal (signo, sigstat);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
set_stat_signal (const char *name)
|
||||
{
|
||||
static struct sigtab
|
||||
{
|
||||
char *name;
|
||||
int signo;
|
||||
} sigtab[] = {
|
||||
{ "SIGUSR1", SIGUSR1 },
|
||||
{ "USR1", SIGUSR1 },
|
||||
{ "SIGUSR2", SIGUSR2 },
|
||||
{ "USR2", SIGUSR2 },
|
||||
{ "SIGHUP", SIGHUP },
|
||||
{ "HUP", SIGHUP },
|
||||
{ "SIGINT", SIGINT },
|
||||
{ "INT", SIGINT },
|
||||
{ "SIGQUIT", SIGQUIT },
|
||||
{ "QUIT", SIGQUIT }
|
||||
};
|
||||
struct sigtab *p;
|
||||
|
||||
for (p = sigtab; p < sigtab + sizeof (sigtab) / sizeof (sigtab[0]); p++)
|
||||
if (strcmp (p->name, name) == 0)
|
||||
{
|
||||
stat_on_signal (p->signo);
|
||||
return;
|
||||
}
|
||||
FATAL_ERROR ((0, 0, _("Unknown signal name: %s"), name));
|
||||
}
|
||||
|
||||
|
||||
struct textual_date
|
||||
{
|
||||
struct textual_date *next;
|
||||
struct timespec *ts;
|
||||
const char *option;
|
||||
const char *date;
|
||||
};
|
||||
|
||||
static void
|
||||
get_date_or_file (struct tar_args *args, const char *option,
|
||||
const char *str, struct timespec *ts)
|
||||
{
|
||||
if (FILE_SYSTEM_PREFIX_LEN (str) != 0
|
||||
|| ISSLASH (*str)
|
||||
|| *str == '.')
|
||||
{
|
||||
struct stat st;
|
||||
if (deref_stat (dereference_option, str, &st) != 0)
|
||||
{
|
||||
stat_error (str);
|
||||
USAGE_ERROR ((0, 0, _("Date sample file not found")));
|
||||
}
|
||||
*ts = get_stat_mtime (&st);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! get_date (ts, str, NULL))
|
||||
{
|
||||
WARN ((0, 0, _("Substituting %s for unknown date format %s"),
|
||||
tartime (*ts, false), quote (str)));
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct textual_date *p = xmalloc (sizeof (*p));
|
||||
p->ts = ts;
|
||||
p->option = option;
|
||||
p->date = str;
|
||||
p->next = args->textual_date;
|
||||
args->textual_date = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
report_textual_dates (struct tar_args *args)
|
||||
{
|
||||
struct textual_date *p;
|
||||
for (p = args->textual_date; p; )
|
||||
{
|
||||
struct textual_date *next = p->next;
|
||||
char const *treated_as = tartime (*p->ts, true);
|
||||
if (strcmp (p->date, treated_as) != 0)
|
||||
WARN ((0, 0, _("Option %s: Treating date `%s' as %s"),
|
||||
p->option, p->date, treated_as));
|
||||
free (p);
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static volatile int _argp_hang;
|
||||
|
||||
enum read_file_list_state /* Result of reading file name from the list file */
|
||||
@@ -920,6 +1115,28 @@ update_argv (const char *filename, struct argp_state *state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
tar_help (struct argp_state *state)
|
||||
{
|
||||
argp_fmtstream_t fs;
|
||||
state->flags |= ARGP_NO_EXIT;
|
||||
argp_state_help (state, state->out_stream,
|
||||
ARGP_HELP_STD_HELP & ~ARGP_HELP_BUG_ADDR);
|
||||
/* FIXME: use struct uparams.rmargin (from argp-help.c) instead of 79 */
|
||||
fs = argp_make_fmtstream (state->out_stream, 0, 79, 0);
|
||||
|
||||
argp_fmtstream_printf (fs, "\n%s\n\n",
|
||||
_("Valid arguments for --quoting-style options are:"));
|
||||
tar_list_quoting_styles (fs, " ");
|
||||
|
||||
argp_fmtstream_puts (fs, _("\n*This* tar defaults to:\n"));
|
||||
show_default_settings_fs (fs);
|
||||
argp_fmtstream_putc (fs, '\n');
|
||||
argp_fmtstream_printf (fs, _("Report bugs to %s.\n"),
|
||||
argp_program_bug_address);
|
||||
argp_fmtstream_free (fs);
|
||||
}
|
||||
|
||||
static error_t
|
||||
parse_opt (int key, char *arg, struct argp_state *state)
|
||||
@@ -930,8 +1147,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
case ARGP_KEY_ARG:
|
||||
/* File name or non-parsed option, because of ARGP_IN_ORDER */
|
||||
name_add (arg);
|
||||
args->input_files++;
|
||||
name_add_name (arg, MAKE_INCL_OPTIONS (args));
|
||||
args->input_files = true;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
@@ -966,8 +1183,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
name_add ("-C");
|
||||
name_add (arg);
|
||||
name_add_dir (arg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
@@ -976,12 +1192,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
|
||||
case 'f':
|
||||
if (archive_names == allocated_archive_names)
|
||||
{
|
||||
allocated_archive_names *= 2;
|
||||
archive_name_array =
|
||||
xrealloc (archive_name_array,
|
||||
sizeof (const char *) * allocated_archive_names);
|
||||
}
|
||||
archive_name_array = x2nrealloc (archive_name_array,
|
||||
&allocated_archive_names,
|
||||
sizeof (archive_name_array[0]));
|
||||
|
||||
archive_name_array[archive_names++] = arg;
|
||||
break;
|
||||
|
||||
@@ -1039,23 +1253,16 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
addname (arg, 0);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
/* Historically equivalent to --one-file-system. This usage is
|
||||
incompatible with UNIX98 and POSIX specs and therefore is
|
||||
deprecated. The semantics of -l option will be changed in
|
||||
future versions. See TODO.
|
||||
*/
|
||||
WARN ((0, 0,
|
||||
_("Semantics of -l option will change in the future releases.")));
|
||||
WARN ((0, 0,
|
||||
_("Please use --one-file-system option instead.")));
|
||||
/* FALL THROUGH */
|
||||
case ONE_FILE_SYSTEM_OPTION:
|
||||
/* When dumping directories, don't dump files/subdirectories
|
||||
that are on other filesystems. */
|
||||
one_file_system_option = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
check_links_option = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
{
|
||||
uintmax_t u;
|
||||
@@ -1078,6 +1285,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
multi_volume_option = true;
|
||||
break;
|
||||
|
||||
case MTIME_OPTION:
|
||||
get_date_or_file (args, "--mtime", arg, &mtime_option);
|
||||
set_mtime_option = true;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
seekable_archive = true;
|
||||
break;
|
||||
@@ -1089,31 +1301,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
case NEWER_MTIME_OPTION:
|
||||
if (NEWER_OPTION_INITIALIZED (newer_mtime_option))
|
||||
USAGE_ERROR ((0, 0, _("More than one threshold date")));
|
||||
|
||||
if (FILE_SYSTEM_PREFIX_LEN (arg) != 0
|
||||
|| ISSLASH (*arg)
|
||||
|| *arg == '.')
|
||||
{
|
||||
struct stat st;
|
||||
if (deref_stat (dereference_option, arg, &st) != 0)
|
||||
{
|
||||
stat_error (arg);
|
||||
USAGE_ERROR ((0, 0, _("Date sample file not found")));
|
||||
}
|
||||
newer_mtime_option = get_stat_mtime (&st);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! get_date (&newer_mtime_option, arg, NULL))
|
||||
{
|
||||
WARN ((0, 0, _("Substituting %s for unknown date format %s"),
|
||||
tartime (newer_mtime_option, false), quote (arg)));
|
||||
newer_mtime_option.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
args->textual_date_option = arg;
|
||||
}
|
||||
|
||||
get_date_or_file (args,
|
||||
key == NEWER_MTIME_OPTION ? "--newer-mtime"
|
||||
: "--after-date", arg, &newer_mtime_option);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
@@ -1140,7 +1330,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
/* Print block numbers for debugging bad tar archives. */
|
||||
|
||||
/* It would surely make sense to exchange -B and -R, but it seems
|
||||
that -B has been used for a long while in Sun tar ans most
|
||||
that -B has been used for a long while in Sun tar and most
|
||||
BSD-derived systems. This is a consequence of the block/record
|
||||
terminology confusion. */
|
||||
|
||||
@@ -1148,7 +1338,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case 's':
|
||||
/* Names to extr are sorted. */
|
||||
/* Names to extract are sorted. */
|
||||
|
||||
same_order_option = true;
|
||||
break;
|
||||
@@ -1157,6 +1347,22 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
sparse_option = true;
|
||||
break;
|
||||
|
||||
case SPARSE_VERSION_OPTION:
|
||||
sparse_option = true;
|
||||
{
|
||||
char *p;
|
||||
tar_sparse_major = strtoul (arg, &p, 10);
|
||||
if (*p)
|
||||
{
|
||||
if (*p != '.')
|
||||
USAGE_ERROR ((0, 0, _("Invalid sparse version value")));
|
||||
tar_sparse_minor = strtoul (p + 1, &p, 10);
|
||||
if (*p)
|
||||
USAGE_ERROR ((0, 0, _("Invalid sparse version value")));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
set_subcommand_option (LIST_SUBCOMMAND);
|
||||
verbose_option++;
|
||||
@@ -1209,7 +1415,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
|
||||
case 'X':
|
||||
if (add_exclude_file (add_exclude, excluded, arg,
|
||||
args->exclude_options | recursion_option, '\n')
|
||||
MAKE_EXCL_OPTIONS (args), '\n')
|
||||
!= 0)
|
||||
{
|
||||
int e = errno;
|
||||
@@ -1226,7 +1432,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case ANCHORED_OPTION:
|
||||
args->exclude_options |= EXCLUDE_ANCHORED;
|
||||
args->matching_flags |= EXCLUDE_ANCHORED;
|
||||
break;
|
||||
|
||||
case ATIME_PRESERVE_OPTION:
|
||||
@@ -1242,7 +1448,22 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case CHECKPOINT_OPTION:
|
||||
checkpoint_option = true;
|
||||
if (arg)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (*arg == '.')
|
||||
{
|
||||
checkpoint_style = checkpoint_dot;
|
||||
arg++;
|
||||
}
|
||||
checkpoint_option = strtoul (arg, &p, 0);
|
||||
if (*p)
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("--checkpoint value is not an integer")));
|
||||
}
|
||||
else
|
||||
checkpoint_option = 10;
|
||||
break;
|
||||
|
||||
case BACKUP_OPTION:
|
||||
@@ -1264,7 +1485,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case EXCLUDE_OPTION:
|
||||
add_exclude (excluded, arg, args->exclude_options | recursion_option);
|
||||
add_exclude (excluded, arg, MAKE_EXCL_OPTIONS (args));
|
||||
break;
|
||||
|
||||
case EXCLUDE_CACHES_OPTION:
|
||||
@@ -1284,7 +1505,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case IGNORE_CASE_OPTION:
|
||||
args->exclude_options |= FNM_CASEFOLD;
|
||||
args->matching_flags |= FNM_CASEFOLD;
|
||||
break;
|
||||
|
||||
case IGNORE_COMMAND_ERROR_OPTION:
|
||||
@@ -1322,11 +1543,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case NO_ANCHORED_OPTION:
|
||||
args->exclude_options &= ~ EXCLUDE_ANCHORED;
|
||||
args->include_anchored = 0; /* Clear the default for comman line args */
|
||||
args->matching_flags &= ~ EXCLUDE_ANCHORED;
|
||||
break;
|
||||
|
||||
case NO_IGNORE_CASE_OPTION:
|
||||
args->exclude_options &= ~ FNM_CASEFOLD;
|
||||
args->matching_flags &= ~ FNM_CASEFOLD;
|
||||
break;
|
||||
|
||||
case NO_IGNORE_COMMAND_ERROR_OPTION:
|
||||
@@ -1343,11 +1565,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case NO_WILDCARDS_OPTION:
|
||||
args->exclude_options &= ~ EXCLUDE_WILDCARDS;
|
||||
args->wildcards = disable_wildcards;
|
||||
break;
|
||||
|
||||
case NO_WILDCARDS_MATCH_SLASH_OPTION:
|
||||
args->exclude_options |= FNM_FILE_NAME;
|
||||
args->matching_flags |= FNM_FILE_NAME;
|
||||
break;
|
||||
|
||||
case NULL_OPTION:
|
||||
@@ -1372,6 +1594,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
}
|
||||
break;
|
||||
|
||||
case OVERWRITE_DIR_OPTION:
|
||||
old_files_option = DEFAULT_OLD_FILES;
|
||||
break;
|
||||
|
||||
case OVERWRITE_OPTION:
|
||||
old_files_option = OVERWRITE_OLD_FILES;
|
||||
break;
|
||||
@@ -1400,7 +1626,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case PAX_OPTION:
|
||||
args->pax_option++;
|
||||
args->pax_option = true;
|
||||
xheader_set_option (arg);
|
||||
break;
|
||||
|
||||
@@ -1409,6 +1635,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case PRESERVE_OPTION:
|
||||
/* FIXME: What it is good for? */
|
||||
same_permissions_option = true;
|
||||
same_order_option = true;
|
||||
break;
|
||||
@@ -1468,8 +1695,8 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
show_omitted_dirs_option = true;
|
||||
break;
|
||||
|
||||
case SHOW_STORED_NAMES_OPTION:
|
||||
show_stored_names_option = true;
|
||||
case SHOW_TRANSFORMED_NAMES_OPTION:
|
||||
show_transformed_names_option = true;
|
||||
break;
|
||||
|
||||
case SUFFIX_OPTION:
|
||||
@@ -1484,7 +1711,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case TOTALS_OPTION:
|
||||
totals_option = true;
|
||||
if (arg)
|
||||
set_stat_signal (arg);
|
||||
else
|
||||
totals_option = true;
|
||||
break;
|
||||
|
||||
case TRANSFORM_OPTION:
|
||||
set_transform_expr (arg);
|
||||
break;
|
||||
|
||||
case USE_COMPRESS_PROGRAM_OPTION:
|
||||
@@ -1496,15 +1730,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case WILDCARDS_OPTION:
|
||||
args->exclude_options |= EXCLUDE_WILDCARDS;
|
||||
args->wildcards = enable_wildcards;
|
||||
break;
|
||||
|
||||
case WILDCARDS_MATCH_SLASH_OPTION:
|
||||
args->exclude_options &= ~ FNM_FILE_NAME;
|
||||
break;
|
||||
|
||||
case CHECK_LINKS_OPTION:
|
||||
check_links_option = 1;
|
||||
args->matching_flags &= ~ FNM_FILE_NAME;
|
||||
break;
|
||||
|
||||
case NO_RECURSION_OPTION:
|
||||
@@ -1585,12 +1815,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
#endif /* not DENSITY_LETTER */
|
||||
|
||||
if (archive_names == allocated_archive_names)
|
||||
{
|
||||
allocated_archive_names *= 2;
|
||||
archive_name_array =
|
||||
xrealloc (archive_name_array,
|
||||
sizeof (const char *) * allocated_archive_names);
|
||||
}
|
||||
archive_name_array = x2nrealloc (archive_name_array,
|
||||
&allocated_archive_names,
|
||||
sizeof (archive_name_array[0]));
|
||||
archive_name_array[archive_names++] = xstrdup (buf);
|
||||
}
|
||||
break;
|
||||
@@ -1603,18 +1830,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
#endif /* not DEVICE_PREFIX */
|
||||
|
||||
case '?':
|
||||
state->flags |= ARGP_NO_EXIT;
|
||||
argp_state_help (state, state->out_stream,
|
||||
ARGP_HELP_STD_HELP & ~ARGP_HELP_BUG_ADDR);
|
||||
fprintf (state->out_stream, "\n%s\n\n",
|
||||
_("Valid arguments for --quoting-style options are:"));
|
||||
tar_list_quoting_styles (state->out_stream, " ");
|
||||
|
||||
fprintf (state->out_stream, _("\n*This* tar defaults to:\n"));
|
||||
show_default_settings (state->out_stream);
|
||||
fprintf (state->out_stream, "\n");
|
||||
fprintf (state->out_stream, _("Report bugs to %s.\n"),
|
||||
argp_program_bug_address);
|
||||
tar_help (state);
|
||||
close_stdout ();
|
||||
exit (0);
|
||||
|
||||
@@ -1682,13 +1898,15 @@ decode_options (int argc, char **argv)
|
||||
struct tar_args args;
|
||||
|
||||
/* Set some default option values. */
|
||||
args.textual_date_option = NULL;
|
||||
args.exclude_options = EXCLUDE_WILDCARDS;
|
||||
args.o_option = 0;
|
||||
args.pax_option = 0;
|
||||
args.textual_date = NULL;
|
||||
args.wildcards = default_wildcards;
|
||||
args.matching_flags = 0;
|
||||
args.include_anchored = EXCLUDE_ANCHORED;
|
||||
args.o_option = false;
|
||||
args.pax_option = false;
|
||||
args.backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
|
||||
args.version_control_string = 0;
|
||||
args.input_files = 0;
|
||||
args.input_files = false;
|
||||
|
||||
subcommand_option = UNKNOWN_SUBCOMMAND;
|
||||
archive_format = DEFAULT_FORMAT;
|
||||
@@ -1699,6 +1917,8 @@ decode_options (int argc, char **argv)
|
||||
newer_mtime_option.tv_nsec = -1;
|
||||
recursion_option = FNM_LEADING_DIR;
|
||||
unquote_option = true;
|
||||
tar_sparse_major = 1;
|
||||
tar_sparse_minor = 0;
|
||||
|
||||
owner_option = -1;
|
||||
group_option = -1;
|
||||
@@ -1795,10 +2015,14 @@ decode_options (int argc, char **argv)
|
||||
/* Handle operands after any "--" argument. */
|
||||
for (; index < argc; index++)
|
||||
{
|
||||
name_add (argv[index]);
|
||||
args.input_files++;
|
||||
name_add_name (argv[index], MAKE_INCL_OPTIONS (&args));
|
||||
args.input_files = true;
|
||||
}
|
||||
|
||||
/* Warn about implicit use of the wildcards in command line arguments.
|
||||
See TODO */
|
||||
warn_regex_usage = args.wildcards == default_wildcards;
|
||||
|
||||
/* Derive option values and check option consistency. */
|
||||
|
||||
if (archive_format == DEFAULT_FORMAT)
|
||||
@@ -1817,13 +2041,6 @@ decode_options (int argc, char **argv)
|
||||
| FORMAT_MASK (GNU_FORMAT)
|
||||
| FORMAT_MASK (POSIX_FORMAT));
|
||||
|
||||
if (multi_volume_option
|
||||
&& archive_format == POSIX_FORMAT
|
||||
&& subcommand_option == CREATE_SUBCOMMAND
|
||||
&& !tape_length_option)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("creating multi-volume archives in posix format requires using --tape-length (-L) option")));
|
||||
|
||||
if (occurrence_option)
|
||||
{
|
||||
if (!args.input_files)
|
||||
@@ -1936,7 +2153,7 @@ decode_options (int argc, char **argv)
|
||||
{
|
||||
/* --test-label is silent if the user has specified the label name to
|
||||
compare against. */
|
||||
if (args.input_files == 0)
|
||||
if (!args.input_files)
|
||||
verbose_option++;
|
||||
}
|
||||
else if (utc_option)
|
||||
@@ -1948,7 +2165,7 @@ decode_options (int argc, char **argv)
|
||||
switch (subcommand_option)
|
||||
{
|
||||
case CREATE_SUBCOMMAND:
|
||||
if (args.input_files == 0 && !files_from_option)
|
||||
if (!args.input_files && !files_from_option)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("Cowardly refusing to create an empty archive")));
|
||||
break;
|
||||
@@ -1977,6 +2194,16 @@ decode_options (int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize stdlis */
|
||||
if (index_file_name)
|
||||
{
|
||||
stdlis = fopen (index_file_name, "w");
|
||||
if (! stdlis)
|
||||
open_error (index_file_name);
|
||||
}
|
||||
else
|
||||
stdlis = to_stdout_option ? stderr : stdout;
|
||||
|
||||
archive_name_cursor = archive_name_array;
|
||||
|
||||
/* Prepare for generating backup names. */
|
||||
@@ -1993,13 +2220,8 @@ decode_options (int argc, char **argv)
|
||||
backup_option = false;
|
||||
}
|
||||
|
||||
if (verbose_option && args.textual_date_option)
|
||||
{
|
||||
char const *treated_as = tartime (newer_mtime_option, true);
|
||||
if (strcmp (args.textual_date_option, treated_as) != 0)
|
||||
WARN ((0, 0, _("Treating date `%s' as %s"),
|
||||
args.textual_date_option, treated_as));
|
||||
}
|
||||
if (verbose_option)
|
||||
report_textual_dates (&args);
|
||||
}
|
||||
|
||||
|
||||
@@ -2024,6 +2246,9 @@ main (int argc, char **argv)
|
||||
/* Make sure we have first three descriptors available */
|
||||
stdopen ();
|
||||
|
||||
/* Close all inherited open descriptors, except for the first three */
|
||||
closeopen ();
|
||||
|
||||
/* Pre-allocate a few structures. */
|
||||
|
||||
allocated_archive_names = 10;
|
||||
@@ -2038,8 +2263,6 @@ main (int argc, char **argv)
|
||||
signal (SIGCHLD, SIG_DFL);
|
||||
#endif
|
||||
|
||||
init_names ();
|
||||
|
||||
/* Decode options. */
|
||||
|
||||
decode_options (argc, argv);
|
||||
@@ -2068,8 +2291,6 @@ main (int argc, char **argv)
|
||||
|
||||
case CREATE_SUBCOMMAND:
|
||||
create_archive ();
|
||||
if (totals_option)
|
||||
print_total_written ();
|
||||
break;
|
||||
|
||||
case EXTRACT_SUBCOMMAND:
|
||||
@@ -2092,6 +2313,9 @@ main (int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (totals_option)
|
||||
print_total_stats ();
|
||||
|
||||
if (check_links_option)
|
||||
check_links ();
|
||||
|
||||
@@ -2103,13 +2327,14 @@ main (int argc, char **argv)
|
||||
free (archive_name_array);
|
||||
name_term ();
|
||||
|
||||
if (stdlis == stdout)
|
||||
close_stdout ();
|
||||
|
||||
if (exit_status == TAREXIT_FAILURE)
|
||||
error (0, 0, _("Error exit delayed from previous errors"));
|
||||
if (ferror (stderr) || fclose (stderr) != 0)
|
||||
|
||||
if (stdlis == stdout)
|
||||
close_stdout ();
|
||||
else if (ferror (stderr) || fclose (stderr) != 0)
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
|
||||
22
src/tar.h
22
src/tar.h
@@ -192,8 +192,7 @@ struct oldgnu_header
|
||||
/* Solaris extended header */
|
||||
#define SOLARIS_XHDTYPE 'X'
|
||||
|
||||
|
||||
/* Jörg Schilling star header */
|
||||
/* J@"org Schilling star header */
|
||||
|
||||
struct star_header
|
||||
{ /* byte offset */
|
||||
@@ -221,7 +220,8 @@ struct star_header
|
||||
#define SPARSES_IN_STAR_HEADER 4
|
||||
#define SPARSES_IN_STAR_EXT_HEADER 21
|
||||
|
||||
struct star_in_header {
|
||||
struct star_in_header
|
||||
{
|
||||
char fill[345]; /* 0 Everything that is before t_prefix */
|
||||
char prefix[1]; /* 345 t_name prefix */
|
||||
char fill2; /* 346 */
|
||||
@@ -236,11 +236,13 @@ struct star_in_header {
|
||||
char xmagic[4]; /* 508 "tar" */
|
||||
};
|
||||
|
||||
struct star_ext_header {
|
||||
struct star_ext_header
|
||||
{
|
||||
struct sparse sp[SPARSES_IN_STAR_EXT_HEADER];
|
||||
char isextended;
|
||||
};
|
||||
|
||||
/* END */
|
||||
|
||||
|
||||
/* tar Header Block, overall structure. */
|
||||
@@ -263,10 +265,10 @@ enum archive_format
|
||||
|
||||
/* Information about a sparse file. */
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
};
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
};
|
||||
|
||||
struct tar_stat_info
|
||||
{
|
||||
@@ -293,6 +295,8 @@ struct tar_stat_info
|
||||
bool is_sparse; /* Is the file sparse */
|
||||
|
||||
/* For sparse files: */
|
||||
unsigned sparse_major;
|
||||
unsigned sparse_minor;
|
||||
size_t sparse_map_avail; /* Index to the first unused element in
|
||||
sparse_map array. Zero if the file is
|
||||
not sparse */
|
||||
@@ -317,4 +321,4 @@ union block
|
||||
struct star_ext_header star_ext_header;
|
||||
};
|
||||
|
||||
/* End of Format description. */
|
||||
|
||||
|
||||
527
src/transform.c
Normal file
527
src/transform.c
Normal file
@@ -0,0 +1,527 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2006 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 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <system.h>
|
||||
#include <regex.h>
|
||||
#include "common.h"
|
||||
|
||||
static enum transform_type
|
||||
{
|
||||
transform_none,
|
||||
transform_first,
|
||||
transform_global
|
||||
}
|
||||
transform_type = transform_none;
|
||||
static unsigned match_number = 0;
|
||||
static regex_t regex;
|
||||
static struct obstack stk;
|
||||
|
||||
enum replace_segm_type
|
||||
{
|
||||
segm_literal, /* Literal segment */
|
||||
segm_backref, /* Back-reference segment */
|
||||
segm_case_ctl /* Case control segment (GNU extension) */
|
||||
};
|
||||
|
||||
enum case_ctl_type
|
||||
{
|
||||
ctl_stop, /* Stop case conversion */
|
||||
ctl_upcase_next,/* Turn the next character to uppercase */
|
||||
ctl_locase_next,/* Turn the next character to lowercase */
|
||||
ctl_upcase, /* Turn the replacement to uppercase until ctl_stop */
|
||||
ctl_locase /* Turn the replacement to lowercase until ctl_stop */
|
||||
};
|
||||
|
||||
struct replace_segm
|
||||
{
|
||||
struct replace_segm *next;
|
||||
enum replace_segm_type type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
char *ptr;
|
||||
size_t size;
|
||||
} literal; /* type == segm_literal */
|
||||
size_t ref; /* type == segm_backref */
|
||||
enum case_ctl_type ctl; /* type == segm_case_ctl */
|
||||
} v;
|
||||
};
|
||||
|
||||
/* Compiled replacement expression */
|
||||
static struct replace_segm *repl_head, *repl_tail;
|
||||
static size_t segm_count; /* Number of elements in the above list */
|
||||
|
||||
static struct replace_segm *
|
||||
add_segment (void)
|
||||
{
|
||||
struct replace_segm *segm = xmalloc (sizeof *segm);
|
||||
segm->next = NULL;
|
||||
if (repl_tail)
|
||||
repl_tail->next = segm;
|
||||
else
|
||||
repl_head = segm;
|
||||
repl_tail = segm;
|
||||
segm_count++;
|
||||
return segm;
|
||||
}
|
||||
|
||||
static void
|
||||
add_literal_segment (char *str, char *end)
|
||||
{
|
||||
size_t len = end - str;
|
||||
if (len)
|
||||
{
|
||||
struct replace_segm *segm = add_segment ();
|
||||
segm->type = segm_literal;
|
||||
segm->v.literal.ptr = xmalloc (len + 1);
|
||||
memcpy (segm->v.literal.ptr, str, len);
|
||||
segm->v.literal.ptr[len] = 0;
|
||||
segm->v.literal.size = len;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_char_segment (int chr)
|
||||
{
|
||||
struct replace_segm *segm = add_segment ();
|
||||
segm->type = segm_literal;
|
||||
segm->v.literal.ptr = xmalloc (2);
|
||||
segm->v.literal.ptr[0] = chr;
|
||||
segm->v.literal.ptr[1] = 0;
|
||||
segm->v.literal.size = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
add_backref_segment (size_t ref)
|
||||
{
|
||||
struct replace_segm *segm = add_segment ();
|
||||
segm->type = segm_backref;
|
||||
segm->v.ref = ref;
|
||||
}
|
||||
|
||||
static void
|
||||
add_case_ctl_segment (enum case_ctl_type ctl)
|
||||
{
|
||||
struct replace_segm *segm = add_segment ();
|
||||
segm->type = segm_case_ctl;
|
||||
segm->v.ctl = ctl;
|
||||
}
|
||||
|
||||
void
|
||||
set_transform_expr (const char *expr)
|
||||
{
|
||||
int delim;
|
||||
int i, j, rc;
|
||||
char *str, *beg, *cur;
|
||||
const char *p;
|
||||
int cflags = 0;
|
||||
|
||||
if (transform_type == transform_none)
|
||||
obstack_init (&stk);
|
||||
else
|
||||
{
|
||||
/* Redefinition of the transform expression */
|
||||
regfree (®ex);
|
||||
}
|
||||
|
||||
if (expr[0] != 's')
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
|
||||
delim = expr[1];
|
||||
|
||||
/* Scan regular expression */
|
||||
for (i = 2; expr[i] && expr[i] != delim; i++)
|
||||
if (expr[i] == '\\' && expr[i+1])
|
||||
i++;
|
||||
|
||||
if (expr[i] != delim)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
|
||||
/* Scan replacement expression */
|
||||
for (j = i + 1; expr[j] && expr[j] != delim; j++)
|
||||
if (expr[j] == '\\' && expr[j+1])
|
||||
j++;
|
||||
|
||||
if (expr[j] != delim)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
|
||||
/* Check flags */
|
||||
transform_type = transform_first;
|
||||
for (p = expr + j + 1; *p; p++)
|
||||
switch (*p)
|
||||
{
|
||||
case 'g':
|
||||
transform_type = transform_global;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
cflags |= REG_ICASE;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
cflags |= REG_EXTENDED;
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
match_number = strtoul (p, (char**) &p, 0);
|
||||
p--;
|
||||
break;
|
||||
|
||||
default:
|
||||
USAGE_ERROR ((0, 0, _("Unknown flag in transform expression")));
|
||||
}
|
||||
|
||||
/* Extract and compile regex */
|
||||
str = xmalloc (i - 1);
|
||||
memcpy (str, expr + 2, i - 2);
|
||||
str[i - 2] = 0;
|
||||
|
||||
rc = regcomp (®ex, str, cflags);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
char errbuf[512];
|
||||
regerror (rc, ®ex, errbuf, sizeof (errbuf));
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
|
||||
}
|
||||
|
||||
if (str[0] == '^' || str[strlen (str) - 1] == '$')
|
||||
transform_type = transform_first;
|
||||
|
||||
free (str);
|
||||
|
||||
/* Extract and compile replacement expr */
|
||||
i++;
|
||||
str = xmalloc (j - i + 1);
|
||||
memcpy (str, expr + i, j - i);
|
||||
str[j - i] = 0;
|
||||
|
||||
for (cur = beg = str; *cur;)
|
||||
{
|
||||
if (*cur == '\\')
|
||||
{
|
||||
size_t n;
|
||||
|
||||
add_literal_segment (beg, cur);
|
||||
switch (*++cur)
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
n = strtoul (cur, &cur, 10);
|
||||
if (n > regex.re_nsub)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
|
||||
add_backref_segment (n);
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
add_char_segment ('\\');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
add_char_segment ('\a');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
add_char_segment ('\b');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
add_char_segment ('\f');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
add_char_segment ('\n');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
add_char_segment ('\r');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
add_char_segment ('\t');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
add_char_segment ('\v');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
add_char_segment ('&');
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
/* Turn the replacement to lowercase until a `\U' or `\E'
|
||||
is found, */
|
||||
add_case_ctl_segment (ctl_locase);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
/* Turn the next character to lowercase, */
|
||||
add_case_ctl_segment (ctl_locase_next);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
/* Turn the replacement to uppercase until a `\L' or `\E'
|
||||
is found, */
|
||||
add_case_ctl_segment (ctl_upcase);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
/* Turn the next character to uppercase, */
|
||||
add_case_ctl_segment (ctl_upcase_next);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
/* Stop case conversion started by `\L' or `\U'. */
|
||||
add_case_ctl_segment (ctl_stop);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Try to be nice */
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = '\\';
|
||||
buf[1] = *cur;
|
||||
add_literal_segment (buf, buf + 2);
|
||||
}
|
||||
cur++;
|
||||
break;
|
||||
}
|
||||
beg = cur;
|
||||
}
|
||||
else if (*cur == '&')
|
||||
{
|
||||
add_literal_segment (beg, cur);
|
||||
add_backref_segment (0);
|
||||
beg = ++cur;
|
||||
}
|
||||
else
|
||||
cur++;
|
||||
}
|
||||
add_literal_segment (beg, cur);
|
||||
|
||||
}
|
||||
|
||||
/* Run case conversion specified by CASE_CTL on array PTR of SIZE
|
||||
characters. Returns pointer to statically allocated storage. */
|
||||
static char *
|
||||
run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
|
||||
{
|
||||
static char *case_ctl_buffer;
|
||||
static size_t case_ctl_bufsize;
|
||||
char *p;
|
||||
|
||||
if (case_ctl_bufsize < size)
|
||||
{
|
||||
case_ctl_bufsize = size;
|
||||
case_ctl_buffer = xrealloc (case_ctl_buffer, case_ctl_bufsize);
|
||||
}
|
||||
memcpy (case_ctl_buffer, ptr, size);
|
||||
switch (case_ctl)
|
||||
{
|
||||
case ctl_upcase_next:
|
||||
case_ctl_buffer[0] = toupper (case_ctl_buffer[0]);
|
||||
break;
|
||||
|
||||
case ctl_locase_next:
|
||||
case_ctl_buffer[0] = tolower (case_ctl_buffer[0]);
|
||||
break;
|
||||
|
||||
case ctl_upcase:
|
||||
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
|
||||
*p = toupper (*p);
|
||||
break;
|
||||
|
||||
case ctl_locase:
|
||||
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
|
||||
*p = tolower (*p);
|
||||
break;
|
||||
|
||||
case ctl_stop:
|
||||
break;
|
||||
}
|
||||
return case_ctl_buffer;
|
||||
}
|
||||
|
||||
bool
|
||||
_transform_name_to_obstack (char *input)
|
||||
{
|
||||
regmatch_t *rmp;
|
||||
int rc;
|
||||
size_t nmatches = 0;
|
||||
enum case_ctl_type case_ctl = ctl_stop, /* Current case conversion op */
|
||||
save_ctl = ctl_stop; /* Saved case_ctl for \u and \l */
|
||||
|
||||
/* Reset case conversion after a single-char operation */
|
||||
#define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \
|
||||
|| case_ctl == ctl_locase_next) \
|
||||
{ \
|
||||
case_ctl = save_ctl; \
|
||||
save_ctl = ctl_stop; \
|
||||
}
|
||||
|
||||
if (transform_type == transform_none)
|
||||
return false;
|
||||
|
||||
rmp = xmalloc ((regex.re_nsub + 1) * sizeof (*rmp));
|
||||
|
||||
while (*input)
|
||||
{
|
||||
size_t disp;
|
||||
char *ptr;
|
||||
|
||||
rc = regexec (®ex, input, regex.re_nsub + 1, rmp, 0);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
struct replace_segm *segm;
|
||||
|
||||
disp = rmp[0].rm_eo;
|
||||
|
||||
if (rmp[0].rm_so)
|
||||
obstack_grow (&stk, input, rmp[0].rm_so);
|
||||
|
||||
nmatches++;
|
||||
if (match_number && nmatches < match_number)
|
||||
{
|
||||
obstack_grow (&stk, input, disp);
|
||||
input += disp;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (segm = repl_head; segm; segm = segm->next)
|
||||
{
|
||||
switch (segm->type)
|
||||
{
|
||||
case segm_literal: /* Literal segment */
|
||||
if (case_ctl == ctl_stop)
|
||||
ptr = segm->v.literal.ptr;
|
||||
else
|
||||
{
|
||||
ptr = run_case_conv (case_ctl,
|
||||
segm->v.literal.ptr,
|
||||
segm->v.literal.size);
|
||||
CASE_CTL_RESET();
|
||||
}
|
||||
obstack_grow (&stk, ptr, segm->v.literal.size);
|
||||
break;
|
||||
|
||||
case segm_backref: /* Back-reference segment */
|
||||
if (rmp[segm->v.ref].rm_so != -1
|
||||
&& rmp[segm->v.ref].rm_eo != -1)
|
||||
{
|
||||
size_t size = rmp[segm->v.ref].rm_eo
|
||||
- rmp[segm->v.ref].rm_so;
|
||||
ptr = input + rmp[segm->v.ref].rm_so;
|
||||
if (case_ctl != ctl_stop)
|
||||
{
|
||||
ptr = run_case_conv (case_ctl, ptr, size);
|
||||
CASE_CTL_RESET();
|
||||
}
|
||||
|
||||
obstack_grow (&stk, ptr, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case segm_case_ctl:
|
||||
switch (segm->v.ctl)
|
||||
{
|
||||
case ctl_upcase_next:
|
||||
case ctl_locase_next:
|
||||
switch (save_ctl)
|
||||
{
|
||||
case ctl_stop:
|
||||
case ctl_upcase:
|
||||
case ctl_locase:
|
||||
save_ctl = case_ctl;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
|
||||
case ctl_upcase:
|
||||
case ctl_locase:
|
||||
case ctl_stop:
|
||||
case_ctl = segm->v.ctl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
disp = strlen (input);
|
||||
obstack_grow (&stk, input, disp);
|
||||
}
|
||||
|
||||
input += disp;
|
||||
|
||||
if (transform_type == transform_first)
|
||||
{
|
||||
obstack_grow (&stk, input, strlen (input));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
obstack_1grow (&stk, 0);
|
||||
free (rmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
transform_name_fp (char **pinput, char *(*fun)(char *))
|
||||
{
|
||||
char *str;
|
||||
bool ret = _transform_name_to_obstack (*pinput);
|
||||
if (ret)
|
||||
{
|
||||
str = obstack_finish (&stk);
|
||||
assign_string (pinput, fun ? fun (str) : str);
|
||||
obstack_free (&stk, str);
|
||||
}
|
||||
else if (fun)
|
||||
{
|
||||
str = *pinput;
|
||||
*pinput = NULL;
|
||||
assign_string (pinput, fun (str));
|
||||
free (str);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
transform_name (char **pinput)
|
||||
{
|
||||
return transform_name_fp (pinput, NULL);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ update_archive (void)
|
||||
archive_format = current_format;
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
&& (name = name_scan (current_stat_info.file_name, false)) != NULL)
|
||||
&& (name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
|
||||
256
src/xheader.c
256
src/xheader.c
@@ -157,7 +157,7 @@ xheader_list_destroy (struct keyword_list **root)
|
||||
static void
|
||||
xheader_set_single_keyword (char *kw)
|
||||
{
|
||||
USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet imlemented"), kw));
|
||||
USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet implemented"), kw));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -430,7 +430,7 @@ struct xhdr_tab
|
||||
char const *keyword;
|
||||
void (*coder) (struct tar_stat_info const *, char const *,
|
||||
struct xheader *, void const *data);
|
||||
void (*decoder) (struct tar_stat_info *, char const *, size_t);
|
||||
void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
|
||||
bool protect;
|
||||
};
|
||||
|
||||
@@ -484,7 +484,8 @@ decode_record (char **ptr,
|
||||
{
|
||||
char *start = *ptr;
|
||||
char *p = start;
|
||||
unsigned long int len;
|
||||
uintmax_t u;
|
||||
size_t len;
|
||||
char *len_lim;
|
||||
char const *keyword;
|
||||
char *nextp;
|
||||
@@ -501,8 +502,13 @@ decode_record (char **ptr,
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
len = strtoul (p, &len_lim, 10);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (len_max < len)
|
||||
{
|
||||
int len_len = len_lim - p;
|
||||
@@ -551,7 +557,7 @@ run_override_list (struct keyword_list *kp, struct tar_stat_info *st)
|
||||
{
|
||||
struct xhdr_tab const *t = locate_handler (kp->pattern);
|
||||
if (t)
|
||||
t->decoder (st, kp->value, strlen (kp->value));
|
||||
t->decoder (st, t->keyword, kp->value, strlen (kp->value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +573,7 @@ decx (void *data, char const *keyword, char const *value, size_t size)
|
||||
|
||||
t = locate_handler (keyword);
|
||||
if (t)
|
||||
t->decoder (st, value, size);
|
||||
t->decoder (st, keyword, value, size);
|
||||
else
|
||||
ERROR((0, 0, _("Ignoring unknown extended header keyword `%s'"),
|
||||
keyword));
|
||||
@@ -746,18 +752,19 @@ xheader_string_add (char const *s)
|
||||
x_obstack_grow (&extended_header, s, strlen (s));
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
xheader_string_end (char const *keyword)
|
||||
{
|
||||
size_t len;
|
||||
size_t p;
|
||||
size_t n = 0;
|
||||
uintmax_t len;
|
||||
uintmax_t p;
|
||||
uintmax_t n = 0;
|
||||
size_t size;
|
||||
char nbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char const *np;
|
||||
char *cp;
|
||||
|
||||
if (extended_header.buffer)
|
||||
return;
|
||||
return false;
|
||||
extended_header_init ();
|
||||
|
||||
len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */
|
||||
@@ -771,6 +778,15 @@ xheader_string_end (char const *keyword)
|
||||
while (n != p);
|
||||
|
||||
p = strlen (keyword) + n + 2;
|
||||
size = p;
|
||||
if (size != p)
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Generated keyword/value pair is too long (keyword=%s, length=%s)"),
|
||||
keyword, nbuf));
|
||||
obstack_free (extended_header.stk, obstack_finish (extended_header.stk));
|
||||
return false;
|
||||
}
|
||||
x_obstack_blank (&extended_header, p);
|
||||
x_obstack_1grow (&extended_header, '\n');
|
||||
cp = obstack_next_free (extended_header.stk) - string_length - p - 1;
|
||||
@@ -779,6 +795,7 @@ xheader_string_end (char const *keyword)
|
||||
*cp++ = ' ';
|
||||
cp = stpcpy (cp, keyword);
|
||||
*cp++ = '=';
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -836,8 +853,15 @@ code_time (struct timespec t, char const *keyword, struct xheader *xhdr)
|
||||
xheader_print (xhdr, keyword, code_timespec (t, buf));
|
||||
}
|
||||
|
||||
static bool
|
||||
decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
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;
|
||||
@@ -853,21 +877,21 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
{
|
||||
intmax_t i = strtoimax (arg, &arg_lim, 10);
|
||||
if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
|
||||
goto out_of_range;
|
||||
return decode_time_range;
|
||||
s = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
uintmax_t i = strtoumax (arg, &arg_lim, 10);
|
||||
if (TYPE_MAXIMUM (time_t) < i)
|
||||
goto out_of_range;
|
||||
return decode_time_range;
|
||||
s = i;
|
||||
}
|
||||
|
||||
p = arg_lim;
|
||||
|
||||
if (errno == ERANGE)
|
||||
goto out_of_range;
|
||||
return decode_time_range;
|
||||
|
||||
if (*p == '.')
|
||||
{
|
||||
@@ -895,7 +919,7 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
if (ns != 0)
|
||||
{
|
||||
if (s == TYPE_MINIMUM (time_t))
|
||||
goto out_of_range;
|
||||
return decode_time_range;
|
||||
s--;
|
||||
ns = BILLION - ns;
|
||||
}
|
||||
@@ -906,20 +930,34 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
{
|
||||
ts->tv_sec = s;
|
||||
ts->tv_nsec = ns;
|
||||
return true;
|
||||
return decode_time_success;
|
||||
}
|
||||
}
|
||||
|
||||
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
|
||||
keyword, arg));
|
||||
return false;
|
||||
|
||||
out_of_range:
|
||||
out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
|
||||
TYPE_MAXIMUM (time_t));
|
||||
return false;
|
||||
return decode_time_bad_header;
|
||||
}
|
||||
|
||||
static bool
|
||||
decode_time (struct timespec *ts, char const *arg, char const *keyword)
|
||||
{
|
||||
switch (_decode_time (ts, arg, keyword))
|
||||
{
|
||||
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));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
|
||||
{
|
||||
@@ -962,6 +1000,7 @@ dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
|
||||
|
||||
static void
|
||||
dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)),
|
||||
char const *keyword __attribute__ ((unused)),
|
||||
char const *arg __attribute__ ((unused)),
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
@@ -975,11 +1014,13 @@ atime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
atime_decoder (struct tar_stat_info *st, char const *arg,
|
||||
atime_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, "atime"))
|
||||
if (decode_time (&ts, arg, keyword))
|
||||
st->atime = ts;
|
||||
}
|
||||
|
||||
@@ -991,11 +1032,13 @@ gid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
gid_decoder (struct tar_stat_info *st, char const *arg,
|
||||
gid_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), "gid"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), keyword))
|
||||
st->stat.st_gid = u;
|
||||
}
|
||||
|
||||
@@ -1007,7 +1050,9 @@ gname_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
gname_decoder (struct tar_stat_info *st, char const *arg,
|
||||
gname_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&st->gname, arg);
|
||||
@@ -1021,7 +1066,9 @@ linkpath_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
linkpath_decoder (struct tar_stat_info *st, char const *arg,
|
||||
linkpath_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&st->link_name, arg);
|
||||
@@ -1035,11 +1082,13 @@ ctime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
ctime_decoder (struct tar_stat_info *st, char const *arg,
|
||||
ctime_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, "ctime"))
|
||||
if (decode_time (&ts, arg, keyword))
|
||||
st->ctime = ts;
|
||||
}
|
||||
|
||||
@@ -1051,11 +1100,13 @@ mtime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
mtime_decoder (struct tar_stat_info *st, char const *arg,
|
||||
mtime_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, "mtime"))
|
||||
if (decode_time (&ts, arg, keyword))
|
||||
st->mtime = ts;
|
||||
}
|
||||
|
||||
@@ -1067,7 +1118,9 @@ path_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
path_decoder (struct tar_stat_info *st, char const *arg,
|
||||
path_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&st->orig_file_name, arg);
|
||||
@@ -1083,11 +1136,13 @@ size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
size_decoder (struct tar_stat_info *st, char const *arg,
|
||||
size_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "size"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
st->stat.st_size = u;
|
||||
}
|
||||
|
||||
@@ -1099,11 +1154,13 @@ uid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
uid_decoder (struct tar_stat_info *st, char const *arg,
|
||||
uid_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), "uid"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), keyword))
|
||||
st->stat.st_uid = u;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1172,9 @@ uname_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
uname_decoder (struct tar_stat_info *st, char const *arg,
|
||||
uname_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&st->uname, arg);
|
||||
@@ -1129,11 +1188,13 @@ sparse_size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_size_decoder (struct tar_stat_info *st, char const *arg,
|
||||
sparse_size_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.size"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
st->stat.st_size = u;
|
||||
}
|
||||
|
||||
@@ -1146,11 +1207,13 @@ sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg,
|
||||
sparse_numblocks_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numblocks"))
|
||||
if (decode_num (&u, arg, SIZE_MAX, keyword))
|
||||
{
|
||||
st->sparse_map_size = u;
|
||||
st->sparse_map = xcalloc (u, sizeof st->sparse_map[0]);
|
||||
@@ -1167,11 +1230,13 @@ sparse_offset_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_offset_decoder (struct tar_stat_info *st, char const *arg,
|
||||
sparse_offset_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.offset"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
|
||||
{
|
||||
if (st->sparse_map_avail < st->sparse_map_size)
|
||||
st->sparse_map[st->sparse_map_avail].offset = u;
|
||||
@@ -1190,26 +1255,29 @@ sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg,
|
||||
sparse_numbytes_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numbytes"))
|
||||
if (decode_num (&u, arg, SIZE_MAX, keyword))
|
||||
{
|
||||
if (st->sparse_map_avail < st->sparse_map_size)
|
||||
st->sparse_map[st->sparse_map_avail++].numbytes = u;
|
||||
else
|
||||
ERROR ((0, 0, _("Malformed extended header: excess %s=%s"),
|
||||
"GNU.sparse.numbytes", arg));
|
||||
keyword, arg));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_map_decoder (struct tar_stat_info *st, char const *arg,
|
||||
sparse_map_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
int offset = 1;
|
||||
static char *keyword = "GNU.sparse.map";
|
||||
|
||||
st->sparse_map_avail = 0;
|
||||
while (1)
|
||||
@@ -1283,7 +1351,9 @@ dumpdir_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
dumpdir_decoder (struct tar_stat_info *st, char const *arg,
|
||||
dumpdir_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size)
|
||||
{
|
||||
st->dumpdir = xmalloc (size);
|
||||
@@ -1298,7 +1368,10 @@ volume_label_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_label_decoder (struct tar_stat_info *st, char const *arg, size_t size)
|
||||
volume_label_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&volume_label, arg);
|
||||
}
|
||||
@@ -1312,10 +1385,12 @@ volume_size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size)
|
||||
volume_size_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg, size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.size"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
|
||||
continued_file_size = u;
|
||||
}
|
||||
|
||||
@@ -1329,21 +1404,60 @@ volume_offset_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
}
|
||||
|
||||
static void
|
||||
volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size)
|
||||
volume_offset_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg, size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.offset"))
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword))
|
||||
continued_file_offset = u;
|
||||
}
|
||||
|
||||
static void
|
||||
volume_filename_decoder (struct tar_stat_info *st, char const *arg,
|
||||
size_t size)
|
||||
volume_filename_decoder (struct tar_stat_info *st,
|
||||
char const *keyword __attribute__((unused)),
|
||||
char const *arg,
|
||||
size_t size __attribute__((unused)))
|
||||
{
|
||||
decode_string (&continued_file_name, arg);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
code_num (st->sparse_major, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_major_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
|
||||
st->sparse_major = u;
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_minor_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
code_num (st->sparse_minor, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_minor_decoder (struct tar_stat_info *st,
|
||||
char const *keyword,
|
||||
char const *arg,
|
||||
size_t size)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
|
||||
st->sparse_minor = u;
|
||||
}
|
||||
|
||||
struct xhdr_tab const xhdr_tab[] = {
|
||||
{ "atime", atime_coder, atime_decoder, false },
|
||||
{ "comment", dummy_coder, dummy_decoder, false },
|
||||
@@ -1359,10 +1473,20 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
{ "uname", uname_coder, uname_decoder, false },
|
||||
|
||||
/* Sparse file handling */
|
||||
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
|
||||
{ "GNU.sparse.name", path_coder, path_decoder,
|
||||
true },
|
||||
{ "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
|
||||
true },
|
||||
{ "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
|
||||
true },
|
||||
{ "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
|
||||
true },
|
||||
{ "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
|
||||
true },
|
||||
/* tar 1.14 - 1.15.1 keywords. Multiplse instances of these appeared in 'x'
|
||||
|
||||
/* tar 1.14 - 1.15.90 keywords. */
|
||||
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
|
||||
/* 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." */
|
||||
@@ -1370,7 +1494,7 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
true },
|
||||
{ "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
|
||||
true },
|
||||
/* tar >=1.16 keyword, introduced to remove the above-mentioned conflict. */
|
||||
/* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
|
||||
{ "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
|
||||
sparse_map_decoder, false },
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
argcv.h
|
||||
argcv.c
|
||||
*.bz2
|
||||
*.gz
|
||||
*.tar
|
||||
*.gtar
|
||||
.deps
|
||||
genfile
|
||||
Makefile
|
||||
Makefile.in
|
||||
argcv.c
|
||||
argcv.h
|
||||
atconfig
|
||||
atlocal
|
||||
testsuite
|
||||
genfile
|
||||
genfile.c
|
||||
package.m4
|
||||
testsuite
|
||||
testsuite.dir
|
||||
testsuite.log
|
||||
package.m4
|
||||
|
||||
@@ -49,6 +49,8 @@ TESTSUITE_AT = \
|
||||
testsuite.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
append02.at\
|
||||
chtype.at\
|
||||
comprec.at\
|
||||
delete01.at\
|
||||
delete02.at\
|
||||
@@ -62,9 +64,13 @@ TESTSUITE_AT = \
|
||||
extrac05.at\
|
||||
extrac06.at\
|
||||
gzip.at\
|
||||
grow.at\
|
||||
incremental.at\
|
||||
incr01.at\
|
||||
incr02.at\
|
||||
incr03.at\
|
||||
incr04.at\
|
||||
indexfile.at\
|
||||
ignfail.at\
|
||||
link01.at\
|
||||
listed01.at\
|
||||
@@ -78,11 +84,15 @@ TESTSUITE_AT = \
|
||||
multiv02.at\
|
||||
multiv03.at\
|
||||
multiv04.at\
|
||||
multiv05.at\
|
||||
old.at\
|
||||
options.at\
|
||||
options02.at\
|
||||
pipe.at\
|
||||
recurse.at\
|
||||
rename01.at\
|
||||
rename02.at\
|
||||
rename03.at\
|
||||
same-order01.at\
|
||||
same-order02.at\
|
||||
shortrec.at\
|
||||
@@ -91,9 +101,14 @@ TESTSUITE_AT = \
|
||||
sparse03.at\
|
||||
sparsemv.at\
|
||||
sparsemvp.at\
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
truncate.at\
|
||||
update.at\
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
version.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
@@ -118,6 +133,9 @@ clean-local:
|
||||
check-local: atconfig atlocal $(TESTSUITE)
|
||||
$(SHELL) $(TESTSUITE)
|
||||
|
||||
check-full:
|
||||
FULL_TEST=1 $(MAKE) check
|
||||
|
||||
#check_SCRIPTS = tar
|
||||
|
||||
# Run the test suite on the *installed* tree.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,7 +19,7 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([append])
|
||||
AT_KEYWORDS([append])
|
||||
AT_KEYWORDS([append append00])
|
||||
|
||||
AT_TAR_CHECK([touch file1
|
||||
touch file2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2005, 2006 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -26,8 +26,8 @@
|
||||
# <7231C15EAC2F164CA6DC326D97493C8B36C25D@exchange35.fed.cclrc.ac.uk>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2005-02/msg00032.html
|
||||
|
||||
AT_SETUP([append01])
|
||||
AT_KEYWORDS([appending files with long names])
|
||||
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])
|
||||
|
||||
|
||||
72
tests/append02.at
Normal file
72
tests/append02.at
Normal file
@@ -0,0 +1,72 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Using tar 1.15.x the following equivalent command sets:
|
||||
#
|
||||
# 1. tar cf archive file1 file2
|
||||
# and
|
||||
# 2. tar cfT archive /dev/null
|
||||
# tar rf archive file1
|
||||
# tar rt archive file2
|
||||
#
|
||||
# produced different archives (GNU format is assumed). Namely, in the
|
||||
# second case the mode field of all members, except the first, was truncated
|
||||
# to lower 3 octets (& 0777).
|
||||
#
|
||||
# References:
|
||||
# <200607210526.AA03440@tamuki.linet.gr.jp>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2006-07/msg00029.html
|
||||
|
||||
# The test case below verifies that the equivalent create and append commands
|
||||
# produce binary equivalent archives for all formats.
|
||||
|
||||
AT_SETUP([append vs. create])
|
||||
AT_KEYWORDS([append append02 append-gnu])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --file file1
|
||||
genfile --file file2
|
||||
|
||||
# For PAX archives, we need to make sure extended header names are
|
||||
# reproducible.
|
||||
if test $[]TEST_TAR_FORMAT = posix; then
|
||||
TAR_OPTIONS="$TAR_OPTIONS --pax-option=exthdr.name=%d/PaxHeaders/%f"
|
||||
fi
|
||||
|
||||
echo Creating archive.1
|
||||
tar cf archive.1 file1 file2
|
||||
|
||||
echo Creating archive.2
|
||||
tar cfT archive.2 /dev/null
|
||||
tar rf archive.2 file1
|
||||
tar rf archive.2 file2
|
||||
|
||||
echo Comparing archives
|
||||
cmp archive.1 archive.2
|
||||
],
|
||||
[0],
|
||||
[Creating archive.1
|
||||
Creating archive.2
|
||||
Comparing archives
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of append02.at
|
||||
@@ -4,3 +4,30 @@
|
||||
|
||||
PATH=@abs_builddir@:@abs_top_builddir@/src:@abs_top_srcdir@/build-aux:$top_srcdir:$srcdir:$PATH
|
||||
|
||||
XFAILFILE=$abs_builddir/.badversion
|
||||
|
||||
trap "test -r $XFAILFILE && cat $XFAILFILE; exit $?" 1 2 13 15
|
||||
|
||||
TEST_DATA_URL=ftp://download.gnu.org.ua/pub/tests/tar
|
||||
if test -z "$TEST_DATA_DIR"; then
|
||||
TEST_DATA_DIR=$abs_builddir
|
||||
fi
|
||||
|
||||
STAR_DATA_URL=http://download.berlios.de/pub/star/testscripts
|
||||
if test -z "$STAR_TESTSCRIPTS"; then
|
||||
STAR_TESTSCRIPTS=$TEST_DATA_DIR
|
||||
fi
|
||||
|
||||
# tarball_prereq file sum dir url
|
||||
tarball_prereq() {
|
||||
if test -d "$3"; then
|
||||
if test -r $3/$1; then
|
||||
:
|
||||
elif test -n "$FULL_TEST"; then
|
||||
wget -q --directory-prefix=$3 $4/$1
|
||||
fi
|
||||
fi
|
||||
echo "$2 $3/$1" | md5sum --status --check -
|
||||
}
|
||||
|
||||
|
||||
|
||||
73
tests/chtype.at
Normal file
73
tests/chtype.at
Normal file
@@ -0,0 +1,73 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description: Incremental restore malfunctions if an archive member
|
||||
# changes type before restoration, e.g. from directory to file or vice
|
||||
# versa.
|
||||
# Reported by: Wolfram Kleff <bugreport@wkleff.intergenia.de>
|
||||
# References: <200605101232.25031.bugreport@wkleff.intergenia.de>
|
||||
|
||||
AT_SETUP([changed file types in incrementals])
|
||||
AT_KEYWORDS([incremental chtype])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
AT_TAR_MKHIER([directory/b/c],[x])
|
||||
mkdir directory/a
|
||||
genfile --file directory/a/a
|
||||
|
||||
echo First backup
|
||||
tar --create --file=archive.1 --listed-incremental=db.1 directory
|
||||
|
||||
sleep 2
|
||||
|
||||
# Remove directory b and create a file with this name.
|
||||
# Previous versions were not able to restore over this file.
|
||||
rm -r directory/b
|
||||
genfile --file directory/b
|
||||
genfile --file directory/a/b
|
||||
|
||||
echo Second backup
|
||||
tar --create --file=archive.2 --listed-incremental=db.2 directory
|
||||
|
||||
# Delete a
|
||||
rm -r directory
|
||||
|
||||
echo Restore archive.1
|
||||
tar -xf archive.1 --listed-incremental=/dev/null
|
||||
echo Restore archive.2
|
||||
tar -xf archive.2 --listed-incremental=/dev/null
|
||||
find directory | sort
|
||||
],
|
||||
[0],
|
||||
[First backup
|
||||
Second backup
|
||||
Restore archive.1
|
||||
Restore archive.2
|
||||
directory
|
||||
directory/a
|
||||
directory/a/a
|
||||
directory/a/b
|
||||
directory/b
|
||||
],[],[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of chtype.at
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
# There was a diagnostic when directory already exists.
|
||||
|
||||
AT_SETUP([extract01])
|
||||
AT_SETUP([extract over an existing directory])
|
||||
AT_KEYWORDS([extract extract01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -24,6 +24,7 @@ AT_SETUP([extract + fnmatch])
|
||||
AT_KEYWORDS([extract extract04])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
touch file1
|
||||
mkdir directory
|
||||
mkdir directory/subdirectory
|
||||
@@ -35,7 +36,7 @@ tar -cf archive ./file1 directory
|
||||
tar -tf archive \
|
||||
--exclude='./*1' \
|
||||
--exclude='d*/*1' \
|
||||
--exclude='d*/s*/*2' | sort 2>/dev/null
|
||||
--exclude='d*/s*/*2' | sort
|
||||
],
|
||||
[0],
|
||||
[directory/
|
||||
|
||||
40
tests/grow.at
Normal file
40
tests/grow.at
Normal file
@@ -0,0 +1,40 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Tar should exit with error code 1 (file differs) if any files have
|
||||
# changed during archiving.
|
||||
|
||||
AT_SETUP([grow])
|
||||
AT_KEYWORDS([grow filechange])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --file foo --length 50000k
|
||||
genfile --file baz
|
||||
genfile --run 'tar -vcf bar foo baz' --checkpoint 10 --length 1024 \
|
||||
--append foo
|
||||
],
|
||||
[1],
|
||||
[foo
|
||||
baz
|
||||
],
|
||||
[tar: foo: file changed as we read it
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -24,42 +24,40 @@ AT_SETUP([ignfail])
|
||||
AT_KEYWORDS([ignfail])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
if test -w / ; then
|
||||
# The test is meaningless for super-user.
|
||||
AT_SKIP_TEST
|
||||
else
|
||||
touch file
|
||||
mkdir directory
|
||||
touch directory/file
|
||||
# The test is meaningless for super-user.
|
||||
AT_UNPRIVILEGED_PREREQ
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 file
|
||||
tar cf archive file
|
||||
status=$?
|
||||
chmod 600 file
|
||||
test $status = 2 || exit 1
|
||||
touch file
|
||||
mkdir directory
|
||||
touch directory/file
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 file
|
||||
tar cf archive --ignore-failed-read file || exit 1
|
||||
status=$?
|
||||
chmod 600 file
|
||||
test $status = 0 || exit 1
|
||||
echo 1>&2 -----
|
||||
chmod 000 file
|
||||
tar cf archive file
|
||||
status=$?
|
||||
chmod 600 file
|
||||
test $status = 2 || exit 1
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 directory
|
||||
tar cf archive directory
|
||||
status=$?
|
||||
chmod 700 directory
|
||||
test $status = 2 || exit 1
|
||||
echo 1>&2 -----
|
||||
chmod 000 file
|
||||
tar cf archive --ignore-failed-read file || exit 1
|
||||
status=$?
|
||||
chmod 600 file
|
||||
test $status = 0 || exit 1
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 directory
|
||||
tar cf archive --ignore-failed-read directory || exit 1
|
||||
status=$?
|
||||
chmod 700 directory
|
||||
test $status = 0
|
||||
fi
|
||||
echo 1>&2 -----
|
||||
chmod 000 directory
|
||||
tar cf archive directory
|
||||
status=$?
|
||||
chmod 700 directory
|
||||
test $status = 2 || exit 1
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 directory
|
||||
tar cf archive --ignore-failed-read directory || exit 1
|
||||
status=$?
|
||||
chmod 700 directory
|
||||
test $status = 0
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
|
||||
78
tests/incr03.at
Normal file
78
tests/incr03.at
Normal file
@@ -0,0 +1,78 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description:
|
||||
# Previous versions checked only mtime/ctime of directories during
|
||||
# incremental backups. As a result, it sufficed to rename a single file
|
||||
# to get full dump of the directory where it resided. Since v.1.15.91
|
||||
# tar checks directory contents as well, so in this case only the renamed
|
||||
# file is dumped.
|
||||
|
||||
AT_SETUP([renamed files in incrementals])
|
||||
AT_KEYWORDS([incremental incr03 rename])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir directory
|
||||
genfile --file=directory/x
|
||||
genfile --file=directory/y
|
||||
|
||||
tar -cf archive.1 -g db directory
|
||||
|
||||
mv directory/x directory/z
|
||||
tar -cf archive.2 -g db directory
|
||||
|
||||
mv directory orig
|
||||
|
||||
echo Listing of archive.1
|
||||
tar -tf archive.1 | sort
|
||||
echo Listing of archive.2
|
||||
tar -tf archive.2 | sort
|
||||
|
||||
echo Directory after first restore
|
||||
tar -xf archive.1 -g db
|
||||
find directory | sort
|
||||
|
||||
echo Directory after second restore
|
||||
tar -xf archive.2 -g db
|
||||
find directory | sort
|
||||
],
|
||||
[0],
|
||||
[Listing of archive.1
|
||||
directory/
|
||||
directory/x
|
||||
directory/y
|
||||
Listing of archive.2
|
||||
directory/
|
||||
directory/z
|
||||
Directory after first restore
|
||||
directory
|
||||
directory/x
|
||||
directory/y
|
||||
Directory after second restore
|
||||
directory
|
||||
directory/y
|
||||
directory/z
|
||||
],[],[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of incr03.at
|
||||
|
||||
63
tests/incr04.at
Normal file
63
tests/incr04.at
Normal file
@@ -0,0 +1,63 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description: Rewritten incremental backup support (2006-05-08)
|
||||
# missed initialization of all struct directory members in make_directory,
|
||||
# which lead to random core dumps.
|
||||
# Reported by Sergey Myasnikov <tigra@sw.ru>. This testcase uses original
|
||||
# script provided by him.
|
||||
# References: <1148669592.5127.81.camel@tigra.sw.ru>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2006-05/msg00038.html
|
||||
|
||||
AT_SETUP([proper icontents initialization])
|
||||
AT_KEYWORDS([incremental incr04 icontents])
|
||||
|
||||
m4_define([NAME_PREFIX],[a/b/one_31_chars_long_file_name_])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_TAR_MKHIER(a/b)
|
||||
awk 'BEGIN {
|
||||
for (i=1;i<=142;i++)
|
||||
printf("NAME_PREFIX[%03d]\n", i);
|
||||
}' < /dev/null | genfile --files-from -
|
||||
|
||||
echo "Initial dump"
|
||||
tar cvf a0.tar -g a.sna a
|
||||
mv a/b a/c
|
||||
echo "Incremental dump"
|
||||
tar cvf a1.tar -g a.sna a
|
||||
],
|
||||
[0],
|
||||
[Initial dump
|
||||
a/
|
||||
a/b/
|
||||
m4_for(I,1,142,1,[NAME_PREFIX[]m4_if(m4_len(I),1,00,m4_len(I),2,0)I
|
||||
])dnl
|
||||
Incremental dump
|
||||
a/
|
||||
a/c/
|
||||
],
|
||||
[tar: a/b: Directory is new
|
||||
tar: a/c: Directory has been renamed from `a/b'
|
||||
],[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of incr04.at
|
||||
47
tests/indexfile.at
Normal file
47
tests/indexfile.at
Normal file
@@ -0,0 +1,47 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# tar --index-file=FILE --file=- sent the archive to FILE, and
|
||||
# the listing to stderr.
|
||||
# Reported by Marcin Gryszkalis <mg@fork.pl>
|
||||
# References: <200607061943.06645.mg@fork.pl>
|
||||
|
||||
AT_SETUP([tar --index-file=FILE --file=-])
|
||||
AT_KEYWORDS([stdout indexfile])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
mkdir directory
|
||||
genfile --file=directory/a --length=1035
|
||||
|
||||
echo "Creating the archive"
|
||||
tar -c -v -f - --index-file=idx directory > archive
|
||||
|
||||
echo "Testing the archive"
|
||||
tar -tf archive
|
||||
],
|
||||
[0],
|
||||
[Creating the archive
|
||||
Testing the archive
|
||||
directory/
|
||||
directory/a
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -29,8 +29,9 @@ AT_SETUP([working --listed])
|
||||
AT_KEYWORDS([listed incremental listed02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
AT_SORT_PREREQ
|
||||
echo Create directories
|
||||
|
||||
mkdir tart
|
||||
sleep 1
|
||||
mkdir tart/c0
|
||||
@@ -50,7 +51,7 @@ tar -c -v --listed-incremental=tart.incr1 -f archive.1 tart 2> err || exit 1
|
||||
|
||||
# The above prints two lines to stderr announcing the new directories c0 and c1.
|
||||
# Ensure that they appear in this script's stderr in sorted order.
|
||||
sort err 1>&2 2>/dev/null; rm -f err
|
||||
sort err 1>&2; rm -f err
|
||||
|
||||
sleep 1
|
||||
echo Modifying filesystem
|
||||
@@ -110,8 +111,6 @@ tart/
|
||||
tart/c0/
|
||||
tart/c2/
|
||||
tart/b2
|
||||
tart/c2/ca1
|
||||
tart/c2/ca2
|
||||
tart/c2/ca3
|
||||
Extracting main archive
|
||||
tart/
|
||||
@@ -126,13 +125,10 @@ tart/c1/ca2
|
||||
Extracting incremental archive
|
||||
tar: Deleting `tart/a1'
|
||||
tar: Deleting `tart/b1'
|
||||
tar: Deleting `tart/c1'
|
||||
tart/
|
||||
tart/b2
|
||||
tart/c0/
|
||||
tart/c2/
|
||||
tart/c2/ca1
|
||||
tart/c2/ca2
|
||||
tart/c2/ca3
|
||||
Final files:
|
||||
tart
|
||||
@@ -147,7 +143,7 @@ tart/c2/ca3
|
||||
],
|
||||
[tar: tart/c0: Directory is new
|
||||
tar: tart/c1: Directory is new
|
||||
tar: tart/c2: Directory is new
|
||||
tar: tart/c2: Directory has been renamed from `tart/c1'
|
||||
],
|
||||
[],[],[gnu, oldgnu])
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
AT_SETUP([long file names divisible by block size])
|
||||
AT_KEYWORDS([longname long512])
|
||||
|
||||
dnl Create a directory structure with maximum diractory name length 512-16
|
||||
dnl Create a directory structure with maximum directory name length 512-16
|
||||
m4_define([NAME],[0123456789abcde])
|
||||
m4_define([FULLNAME],NAME)
|
||||
m4_for([N],0,29,,[m4_define([FULLNAME],FULLNAME/NAME)])
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
# 3. Test the created multi-volume archive.
|
||||
|
||||
AT_SETUP([split directory members in a MV archive])
|
||||
AT_KEYWORDS([multivolume multiv multiv04])
|
||||
AT_KEYWORDS([multivolume multiv incremental multiv04])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
mkdir directory
|
||||
awk 'BEGIN { for (i = 0; i < 1024; i++) printf("genfile -f directory/%014x\n", i); }' </dev/null | sh
|
||||
awk 'BEGIN { for (i = 0; i < 1024; i++) printf("directory/%014x\n", i); }' </dev/null | genfile --files-from -
|
||||
|
||||
exec <&-
|
||||
|
||||
|
||||
67
tests/multiv05.at
Normal file
67
tests/multiv05.at
Normal file
@@ -0,0 +1,67 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Up to version 1.15.91 tar was unable to recognize all volumes
|
||||
# given after an aout-of-sync volume.
|
||||
# Reported by: Joerg Weilbier <gnu@weilbier.net>
|
||||
# References: <200610011952.29880.gnu@weilbier.net>
|
||||
|
||||
AT_SETUP([Restoring after an out of sync folume])
|
||||
AT_KEYWORDS([multivolume multiv multiv05 sync])
|
||||
m4_define([FILELIST],[jeden,dwa,trzy,cztery,piec,szesc])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
exec <&-
|
||||
|
||||
m4_foreach([f],
|
||||
[FILELIST],
|
||||
[genfile --length 250k --file f
|
||||
])
|
||||
|
||||
echo Creating archive
|
||||
tar -c -M -L 502 -f a.tar -f b.tar -f c.tar m4_foreach([f],[FILELIST],f )
|
||||
echo separator
|
||||
mkdir bak
|
||||
mv m4_foreach([f],[FILELIST],f )bak
|
||||
tar -vxM -f a.tar -f c.tar -f b.tar -f c.tar
|
||||
m4_foreach([f],
|
||||
[FILELIST],
|
||||
[echo Diffing f
|
||||
cmp bak/f f || exit 1
|
||||
])],
|
||||
[0],
|
||||
[Creating archive
|
||||
separator]
|
||||
m4_foreach([file],
|
||||
[FILELIST],
|
||||
[file
|
||||
])dnl
|
||||
m4_foreach([file],
|
||||
[FILELIST],
|
||||
[Diffing file
|
||||
])dnl
|
||||
,
|
||||
[tar: `trzy' is not continued on this volume
|
||||
],[],[], [gnu])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -21,7 +21,7 @@
|
||||
# Ensure that TAR_OPTIONS works in conjunction with old-style options.
|
||||
|
||||
unset TAR_OPTIONS
|
||||
AT_SETUP([options])
|
||||
AT_SETUP([mixing options])
|
||||
AT_KEYWORDS([options options00])
|
||||
|
||||
AT_CHECK([
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -23,7 +23,7 @@
|
||||
# References: <200501051042.46223.vapier@gentoo.org>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2005-01/msg00011.html
|
||||
|
||||
AT_SETUP([options02])
|
||||
AT_SETUP([interspersed options])
|
||||
AT_KEYWORDS([options options02])
|
||||
|
||||
AT_CHECK([
|
||||
|
||||
@@ -31,12 +31,14 @@ AT_SETUP([decompressing from stdin])
|
||||
AT_KEYWORDS([pipe])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
mkdir directory
|
||||
genfile --length 10240 --pattern zeros --file directory/file1
|
||||
genfile --length 13 --file directory/file2
|
||||
tar cf archive directory|sort 2>/dev/null
|
||||
tar cf archive directory|sort
|
||||
mv directory orig
|
||||
cat archive | tar xfv - | sort 2>/dev/null
|
||||
cat archive | tar xfv - | sort
|
||||
echo "separator"
|
||||
cmp orig/file1 directory/file1
|
||||
echo "separator"
|
||||
|
||||
89
tests/rename01.at
Normal file
89
tests/rename01.at
Normal file
@@ -0,0 +1,89 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description: Test basic handling of renamed directory in the incremental
|
||||
# archives.
|
||||
|
||||
AT_SETUP([renamed dirs in incrementals])
|
||||
AT_KEYWORDS([incremental rename rename01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
mkdir foo
|
||||
genfile --file foo/file1
|
||||
genfile --file foo/file2
|
||||
mkdir foo/bar
|
||||
genfile --file foo/bar/file
|
||||
|
||||
echo "Creating base archive"
|
||||
tar -g incr -cf arch.1 -v foo
|
||||
|
||||
mv foo/bar foo/baz
|
||||
|
||||
echo "Creating incremental archive"
|
||||
tar -g incr -cf arch.2 -v foo
|
||||
|
||||
mv foo old
|
||||
|
||||
tar xfg arch.1 /dev/null
|
||||
|
||||
echo "Begin directory listing 1"
|
||||
find foo | sort
|
||||
echo "End directory listing 1"
|
||||
|
||||
tar xfg arch.2 /dev/null
|
||||
echo Begin directory listing 2
|
||||
find foo | sort
|
||||
echo End directory listing 2
|
||||
],
|
||||
[0],
|
||||
[Creating base archive
|
||||
foo/
|
||||
foo/bar/
|
||||
foo/file1
|
||||
foo/file2
|
||||
foo/bar/file
|
||||
Creating incremental archive
|
||||
foo/
|
||||
foo/baz/
|
||||
Begin directory listing 1
|
||||
foo
|
||||
foo/bar
|
||||
foo/bar/file
|
||||
foo/file1
|
||||
foo/file2
|
||||
End directory listing 1
|
||||
Begin directory listing 2
|
||||
foo
|
||||
foo/baz
|
||||
foo/baz/file
|
||||
foo/file1
|
||||
foo/file2
|
||||
End directory listing 2
|
||||
],
|
||||
[tar: foo/bar: Directory is new
|
||||
tar: foo/baz: Directory has been renamed from `foo/bar'
|
||||
],
|
||||
[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of rename01.at
|
||||
102
tests/rename02.at
Normal file
102
tests/rename02.at
Normal file
@@ -0,0 +1,102 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description: Incremental archives should be able to handle directories
|
||||
# moved between directory hierarchies.
|
||||
|
||||
AT_SETUP([move between hierarchies])
|
||||
AT_KEYWORDS([incremental rename rename02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir foo
|
||||
genfile --file foo/file1
|
||||
genfile --file foo/file2
|
||||
mkdir foo/bar
|
||||
genfile --file foo/bar/file.r
|
||||
mkdir foo/bar/baz
|
||||
genfile --file foo/bar/baz/file.z
|
||||
|
||||
echo "Creating base archive"
|
||||
tar -g incr -cf arch.1 -v foo
|
||||
|
||||
mv foo/bar/baz foo
|
||||
|
||||
echo "Creating incremental archive"
|
||||
tar -g incr -cf arch.2 -v foo
|
||||
|
||||
mv foo old
|
||||
|
||||
tar xfg arch.1 /dev/null 2>tmperr
|
||||
sort tmperr >&2
|
||||
|
||||
echo "Begin directory listing 1"
|
||||
find foo | sort
|
||||
echo "End directory listing 1"
|
||||
|
||||
tar xfgv arch.2 /dev/null
|
||||
echo Begin directory listing 2
|
||||
find foo | sort
|
||||
echo End directory listing 2
|
||||
],
|
||||
[0],
|
||||
[Creating base archive
|
||||
foo/
|
||||
foo/bar/
|
||||
foo/bar/baz/
|
||||
foo/file1
|
||||
foo/file2
|
||||
foo/bar/file.r
|
||||
foo/bar/baz/file.z
|
||||
Creating incremental archive
|
||||
foo/
|
||||
foo/bar/
|
||||
foo/baz/
|
||||
Begin directory listing 1
|
||||
foo
|
||||
foo/bar
|
||||
foo/bar/baz
|
||||
foo/bar/baz/file.z
|
||||
foo/bar/file.r
|
||||
foo/file1
|
||||
foo/file2
|
||||
End directory listing 1
|
||||
foo/
|
||||
foo/bar/
|
||||
foo/baz/
|
||||
Begin directory listing 2
|
||||
foo
|
||||
foo/bar
|
||||
foo/bar/file.r
|
||||
foo/baz
|
||||
foo/baz/file.z
|
||||
foo/file1
|
||||
foo/file2
|
||||
End directory listing 2
|
||||
],
|
||||
[tar: foo/bar: Directory is new
|
||||
tar: foo/bar/baz: Directory is new
|
||||
tar: foo/baz: Directory has been renamed from `foo/bar/baz'
|
||||
],
|
||||
[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of rename02.at
|
||||
126
tests/rename03.at
Normal file
126
tests/rename03.at
Normal file
@@ -0,0 +1,126 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description: Handling of cyclic renames in incremental archives.
|
||||
|
||||
AT_SETUP([cyclic renames])
|
||||
AT_KEYWORDS([incremental rename rename03 cyclic-rename])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
mkdir foo
|
||||
genfile --file foo/file1
|
||||
genfile --file foo/file2
|
||||
|
||||
mkdir foo/a
|
||||
genfile --file foo/a/filea
|
||||
|
||||
mkdir foo/b
|
||||
genfile --file foo/b/fileb
|
||||
|
||||
mkdir foo/c
|
||||
genfile --file foo/c/filec
|
||||
|
||||
echo "First dump"
|
||||
echo "First dump">&2
|
||||
tar -g incr -cf arch.1 -v foo 2>tmperr
|
||||
sort tmperr >&2
|
||||
|
||||
# Shuffle directories:
|
||||
(cd foo
|
||||
mv a $$
|
||||
mv c a
|
||||
mv b c
|
||||
mv $$ b)
|
||||
|
||||
echo "Second dump"
|
||||
echo "Second dump" >&2
|
||||
tar -g incr -cf arch.2 -v foo 2>tmperr
|
||||
sort tmperr >&2
|
||||
|
||||
tar xfg arch.1 /dev/null
|
||||
|
||||
echo "Begin directory listing 1"
|
||||
find foo | sort
|
||||
echo "End directory listing 1"
|
||||
|
||||
tar xfgv arch.2 /dev/null
|
||||
echo Begin directory listing 2
|
||||
find foo | sort
|
||||
echo End directory listing 2
|
||||
],
|
||||
[0],
|
||||
[First dump
|
||||
foo/
|
||||
foo/a/
|
||||
foo/b/
|
||||
foo/c/
|
||||
foo/file1
|
||||
foo/file2
|
||||
foo/a/filea
|
||||
foo/b/fileb
|
||||
foo/c/filec
|
||||
Second dump
|
||||
foo/
|
||||
foo/a/
|
||||
foo/b/
|
||||
foo/c/
|
||||
Begin directory listing 1
|
||||
foo
|
||||
foo/a
|
||||
foo/a/filea
|
||||
foo/b
|
||||
foo/b/fileb
|
||||
foo/c
|
||||
foo/c/filec
|
||||
foo/file1
|
||||
foo/file2
|
||||
End directory listing 1
|
||||
foo/
|
||||
foo/a/
|
||||
foo/b/
|
||||
foo/c/
|
||||
Begin directory listing 2
|
||||
foo
|
||||
foo/a
|
||||
foo/a/filec
|
||||
foo/b
|
||||
foo/b/filea
|
||||
foo/c
|
||||
foo/c/fileb
|
||||
foo/file1
|
||||
foo/file2
|
||||
End directory listing 2
|
||||
],
|
||||
[First dump
|
||||
tar: foo/a: Directory is new
|
||||
tar: foo/b: Directory is new
|
||||
tar: foo/c: Directory is new
|
||||
Second dump
|
||||
tar: foo/a: Directory has been renamed from `foo/c'
|
||||
tar: foo/b: Directory has been renamed from `foo/a'
|
||||
tar: foo/c: Directory has been renamed from `foo/b'
|
||||
],
|
||||
[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of rename03.at
|
||||
@@ -23,10 +23,12 @@
|
||||
# References: <20040507122613.GB12457@pike.phil.uni-passau.de>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-05/msg00008.html
|
||||
|
||||
AT_SETUP([same-order01])
|
||||
AT_SETUP([working -C with --same-order])
|
||||
AT_KEYWORDS([same-order same-order01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
genfile -l 1024 -f file1
|
||||
genfile -l 1024 -f file2
|
||||
tar cf archive file1 file2
|
||||
@@ -34,7 +36,7 @@ tar cf archive file1 file2
|
||||
mkdir directory
|
||||
tar -xf archive --same-order -C directory || exit 1
|
||||
|
||||
ls directory|sort 2>/dev/null
|
||||
ls directory|sort
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# (see same-order01.sh). However, multiple -C options worked OK.
|
||||
# Test if we did not break the correct behavior.
|
||||
|
||||
AT_SETUP([same-order02])
|
||||
AT_SETUP([multiple -C options])
|
||||
AT_KEYWORDS([same-order same-order02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
@@ -28,7 +28,7 @@ AT_KEYWORDS([shortrec.at])
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
(cd directory && touch a b c d e f g h i j k l m n o p q r)
|
||||
tar -c -b 1 directory | tar -t >/dev/null
|
||||
tar -c -b 1 directory | tar -t -f - >/dev/null
|
||||
tar -c -b 1 -f archive directory
|
||||
tar -t -f archive >/dev/null
|
||||
tar -t -f - < archive >/dev/null
|
||||
|
||||
@@ -18,28 +18,27 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([sparse files in PAX MV archives])
|
||||
AT_KEYWORDS([sparse multiv sparsemvp])
|
||||
|
||||
# Check if sparse files are correctly split between PAX multi-volume
|
||||
# archives.
|
||||
# See comment in sparsemv.at for the description.
|
||||
|
||||
dnl TAR_MVP_TEST version map1 map2
|
||||
m4_define([TAR_MVP_TEST],[
|
||||
AT_TAR_CHECK([
|
||||
exec <&-
|
||||
genfile --sparse --file sparsefile 0 ABCDEFGHIJK 1M ABCDEFGHI || AT_SKIP_TEST
|
||||
genfile --sparse --file sparsefile $2 || AT_SKIP_TEST
|
||||
echo "Pass 1: Split between data blocks"
|
||||
echo "Create archive"
|
||||
tar --sparse -c --record-size=512 -M -L6 -f arc.1 -f arc.2 -f arc.3 sparsefile
|
||||
tar --sparse --sparse-version=$1 -c --record-size=512 -M -L6 -f arc.1 -f arc.2 -f arc.3 sparsefile
|
||||
echo "Test archive"
|
||||
tar -t -M -f arc.1 -f arc.2 -f arc.3
|
||||
echo "Compare archive"
|
||||
tar -d -M -f arc.1 -f arc.2 -f arc.3
|
||||
|
||||
echo "Pass 2: Split within a data block"
|
||||
genfile --sparse --file sparsefile 0 ABCDEFGHIJ 1M ABCDEFGHI || AT_SKIP_TEST
|
||||
genfile --sparse --file sparsefile $3 || AT_SKIP_TEST
|
||||
echo "Create archive"
|
||||
tar --sparse -c --record-size=512 -M -L6 -f arc.1 -f arc.2 -f arc.3 sparsefile
|
||||
tar --sparse --sparse-version=$1 -c --record-size=512 -M -L6 -f arc.1 -f arc.2 -f arc.3 sparsefile
|
||||
echo "Test archive"
|
||||
tar -t -M -f arc.1 -f arc.2 -f arc.3
|
||||
echo "Compare archive"
|
||||
@@ -57,6 +56,5 @@ Test archive
|
||||
sparsefile
|
||||
Compare archive
|
||||
],
|
||||
[],[],[],[pax])
|
||||
[],[],[],[pax])])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
26
tests/spmvp00.at
Normal file
26
tests/spmvp00.at
Normal file
@@ -0,0 +1,26 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([sparse files in PAX MV archives, v.0.0])
|
||||
AT_KEYWORDS([sparse multiv sparsemvp sparsemvp00])
|
||||
|
||||
TAR_MVP_TEST(0.0, [0 ABCDEFGHI 1M ABCDEFGHI], [0 ABCDEFGH 1M ABCDEFGHI])
|
||||
|
||||
AT_CLEANUP
|
||||
26
tests/spmvp01.at
Normal file
26
tests/spmvp01.at
Normal file
@@ -0,0 +1,26 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([sparse files in PAX MV archives, v.0.1])
|
||||
AT_KEYWORDS([sparse multiv sparsemvp sparsemvp01])
|
||||
|
||||
TAR_MVP_TEST(0.1, [0 ABCDEFGHIJK 1M ABCDEFGHI], [0 ABCDEFGHIJ 1M ABCDEFGHI])
|
||||
|
||||
AT_CLEANUP
|
||||
26
tests/spmvp10.at
Normal file
26
tests/spmvp10.at
Normal file
@@ -0,0 +1,26 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([sparse files in PAX MV archives, v.1.0])
|
||||
AT_KEYWORDS([sparse multiv sparsemvp sparsemvp10])
|
||||
|
||||
TAR_MVP_TEST(1.0, [0 ABCDEFGH 1M ABCDEFGHI], [0 ABCDEFG 1M ABCDEFGHI])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,5 +1,5 @@
|
||||
This directory contains scripts for testing GNU tar using
|
||||
star "test archives". The archives themselves may be obtained
|
||||
star "test archives". The archives themselves can be obtained
|
||||
from http://download.berlios.de/pub/star/testscripts.
|
||||
|
||||
The tests are ignored unless environment variable STAR_TESTSCRIPTS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,12 +19,12 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([gtarfail])
|
||||
AT_KEYWORDS([gtarfail])
|
||||
AT_KEYWORDS([star gtarfail])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
AT_STAR_PREREQ([gtarfail.tar])
|
||||
AT_STAR_PREREQ([gtarfail.tar],[bf7612e401aaa679edbb07ae1183811b])
|
||||
|
||||
tar --utc -tvf $STAR_TESTSCRIPTS/gtarfail.tar
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,12 +19,12 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([gtarfail2])
|
||||
AT_KEYWORDS([gtarfail2])
|
||||
AT_KEYWORDS([star gtarfail2])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
AT_STAR_PREREQ([gtarfail2.tar])
|
||||
AT_STAR_PREREQ([gtarfail2.tar],[6b607d1faec14b82f69525d9c5b66e53])
|
||||
tar --utc -tvf $STAR_TESTSCRIPTS/gtarfail2.tar
|
||||
],
|
||||
[0],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,13 +19,13 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([multi-fail])
|
||||
AT_KEYWORDS([multivolume multiv multi-fail])
|
||||
AT_KEYWORDS([star multivolume multiv multi-fail])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
AT_STAR_PREREQ([gnu-multi-fail-volume1.gtar])
|
||||
AT_STAR_PREREQ([gnu-multi-fail-volume2.gtar])
|
||||
AT_STAR_PREREQ([gnu-multi-fail-volume1.gtar],[7c28663dd98b0bd91ceb4be7af55254e])
|
||||
AT_STAR_PREREQ([gnu-multi-fail-volume2.gtar],[b5d41c4c3ec440687d4a44957b5079a8])
|
||||
|
||||
tar --utc -tvM -f $STAR_TESTSCRIPTS/gnu-multi-fail-volume1.gtar \
|
||||
-f $STAR_TESTSCRIPTS/gnu-multi-fail-volume2.gtar <&-
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,13 +19,13 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([pax-big-10g])
|
||||
AT_KEYWORDS([pax-big-10g])
|
||||
AT_KEYWORDS([star pax-big-10g])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
AT_GZIP_PREREQ([bzip2])
|
||||
AT_STAR_PREREQ([pax-big-10g.tar.bz2])
|
||||
AT_STAR_PREREQ([pax-big-10g.tar.bz2],[ca15c23acc8d8bb1f27e60113a5f8bff])
|
||||
|
||||
tar --utc -tvjf $STAR_TESTSCRIPTS/pax-big-10g.tar.bz2
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,13 +19,13 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([ustar-big-2g])
|
||||
AT_KEYWORDS([ustar-big-2g])
|
||||
AT_KEYWORDS([star ustar-big-2g])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
AT_GZIP_PREREQ([bzip2])
|
||||
AT_STAR_PREREQ([ustar-big-2g.tar.bz2])
|
||||
AT_STAR_PREREQ([ustar-big-2g.tar.bz2],[b63979733629c8fcdf40b60065422767])
|
||||
|
||||
tar --utc -tvjf $STAR_TESTSCRIPTS/ustar-big-2g.tar.bz2
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -19,13 +19,13 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([ustar-big-8g])
|
||||
AT_KEYWORDS([ustar-big-8g])
|
||||
AT_KEYWORDS([star ustar-big-8g])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
AT_GZIP_PREREQ([bzip2])
|
||||
AT_STAR_PREREQ([ustar-big-8g.tar.bz2])
|
||||
AT_STAR_PREREQ([ustar-big-8g.tar.bz2],[60ff503fa4b8288bef7ada89e9c91b0f])
|
||||
|
||||
tar --utc -tvjf $STAR_TESTSCRIPTS/ustar-big-8g.tar.bz2
|
||||
],
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
m4_version_prereq([2.52g])
|
||||
|
||||
m4_define([AT_TAR_CHECK],[
|
||||
AT_XFAIL_IF(test -f $[]XFAILFILE)
|
||||
m4_foreach([FMT],
|
||||
[m4_if([$7],[],[v7,oldgnu,ustar,posix,gnu],[$7])],
|
||||
[AT_CHECK([
|
||||
@@ -47,18 +48,46 @@ done
|
||||
|
||||
m4_define([AT_SKIP_TEST],[exit 77])
|
||||
|
||||
dnl AT_TARBALL_PREREQ(tarball, md5sum) - Check if test tarball exists
|
||||
dnl in $TEST_DATA_DIR. If it does not, try to download it from
|
||||
dnl $TEST_DATA_URL. If download fails, or it the file's md5 sum does not
|
||||
dnl match second argument, skip the test.
|
||||
|
||||
m4_define([AT_TARBALL_PREREQ],[
|
||||
test -z "$[]TEST_DATA_DIR" && AT_SKIP_TEST
|
||||
tarball_prereq $1 $2 $[]TEST_DATA_DIR $[]TEST_DATA_URL || AT_SKIP_TEST])
|
||||
|
||||
dnl AT_TARBALL_PREREQ(tarball, md5sum) - Same for star testfiles
|
||||
m4_define([AT_STAR_PREREQ],[
|
||||
test -z "$STAR_TESTSCRIPTS" && AT_SKIP_TEST
|
||||
test -r "$STAR_TESTSCRIPTS/$1" || AT_SKIP_TEST
|
||||
tarball_prereq $1 $2 $[]STAR_TESTSCRIPTS $[]STAR_DATA_URL || AT_SKIP_TEST
|
||||
])
|
||||
|
||||
dnl AT_GZIP_PREREQ - Skip test unless gzip (or $1) is available
|
||||
m4_define([AT_GZIP_PREREQ],[
|
||||
cat /dev/null | m4_if([$1],[],gzip,[$1]) - > /dev/null 2>&1 || AT_SKIP_TEST
|
||||
])
|
||||
|
||||
dnl AT_SORT_PREREQ - Skip test if sort utility outputs unwanted data on stderr
|
||||
m4_define([AT_SORT_PREREQ],[
|
||||
test -z "`sort < /dev/null 2>&1`" || AT_SKIP_TEST
|
||||
])
|
||||
|
||||
dnl AT_UNPRIVILEGED_PREREQ - Skip test if running at root privileges
|
||||
m4_define([AT_UNPRIVILEGED_PREREQ],[
|
||||
echo "test" > $[]$
|
||||
chmod 0 $[]$
|
||||
cat $[]$ > /dev/null 2>&1
|
||||
result=$?
|
||||
rm -f $[]$
|
||||
test $result -eq 0 && AT_SKIP_TEST
|
||||
])
|
||||
|
||||
m4_define([AT_TAR_MKHIER],[
|
||||
mkinstalldirs $1 >/dev/null
|
||||
genfile --file $1/$2])
|
||||
install-sh -d $1 >/dev/null
|
||||
m4_if([$2],,,genfile --file [$1]/[$2])])
|
||||
|
||||
m4_include([sparsemvp.at])
|
||||
|
||||
AT_INIT
|
||||
|
||||
@@ -71,8 +100,12 @@ m4_include([pipe.at])
|
||||
m4_include([options.at])
|
||||
m4_include([options02.at])
|
||||
|
||||
m4_include([indexfile.at])
|
||||
m4_include([verbose.at])
|
||||
|
||||
m4_include([append.at])
|
||||
m4_include([append01.at])
|
||||
m4_include([append02.at])
|
||||
|
||||
m4_include([delete01.at])
|
||||
m4_include([delete02.at])
|
||||
@@ -92,14 +125,19 @@ m4_include([gzip.at])
|
||||
m4_include([incremental.at])
|
||||
m4_include([incr01.at])
|
||||
m4_include([incr02.at])
|
||||
m4_include([listed01.at])
|
||||
m4_include([listed02.at])
|
||||
m4_include([incr03.at])
|
||||
m4_include([incr04.at])
|
||||
m4_include([rename01.at])
|
||||
m4_include([rename02.at])
|
||||
m4_include([rename03.at])
|
||||
m4_include([chtype.at])
|
||||
|
||||
m4_include([ignfail.at])
|
||||
|
||||
m4_include([link01.at])
|
||||
|
||||
m4_include([listed01.at])
|
||||
m4_include([listed02.at])
|
||||
|
||||
m4_include([longv7.at])
|
||||
m4_include([long01.at])
|
||||
m4_include([lustar01.at])
|
||||
@@ -110,6 +148,7 @@ m4_include([multiv01.at])
|
||||
m4_include([multiv02.at])
|
||||
m4_include([multiv03.at])
|
||||
m4_include([multiv04.at])
|
||||
m4_include([multiv05.at])
|
||||
|
||||
m4_include([old.at])
|
||||
|
||||
@@ -124,15 +163,19 @@ m4_include([sparse01.at])
|
||||
m4_include([sparse02.at])
|
||||
m4_include([sparse03.at])
|
||||
m4_include([sparsemv.at])
|
||||
m4_include([sparsemvp.at])
|
||||
m4_include([spmvp00.at])
|
||||
m4_include([spmvp01.at])
|
||||
m4_include([spmvp10.at])
|
||||
|
||||
m4_include([update.at])
|
||||
|
||||
m4_include([volume.at])
|
||||
m4_include([volsize.at])
|
||||
|
||||
m4_include([comprec.at])
|
||||
|
||||
m4_include([truncate.at])
|
||||
m4_include([grow.at])
|
||||
|
||||
m4_include([star/gtarfail.at])
|
||||
m4_include([star/gtarfail2.at])
|
||||
|
||||
@@ -24,14 +24,16 @@
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2005-05/msg00008.html
|
||||
#
|
||||
# The test case is based on the script by Frank Heckenbach <frank@g-n-u.de>
|
||||
# Additionally, the test verifies if tar exits with code 1 (file differs).
|
||||
|
||||
AT_SETUP([truncate])
|
||||
AT_KEYWORDS([truncated files])
|
||||
AT_KEYWORDS([truncate filechange])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --file foo --length 50000k
|
||||
genfile --file baz
|
||||
genfile --run 'tar -vcf bar foo baz' --checkpoint 10 --length 49995k --truncate foo
|
||||
echo Exit status: $?
|
||||
echo separator
|
||||
sleep 1
|
||||
dd if=/dev/zero of=foo bs=1k seek=49995 count=5 >/dev/null 2>&1
|
||||
@@ -39,13 +41,13 @@ tar dvf bar],
|
||||
[1],
|
||||
[foo
|
||||
baz
|
||||
Exit status: 1
|
||||
separator
|
||||
foo
|
||||
foo: Mod time differs
|
||||
baz
|
||||
],
|
||||
[tar: foo: File shrank by 5120 bytes; padding with zeros
|
||||
tar: Error exit delayed from previous errors
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2005, 2006 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
|
||||
@@ -28,6 +28,7 @@ AT_SETUP([update unchanged directories])
|
||||
AT_KEYWORDS([update])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir directory
|
||||
genfile --length 10240 --pattern zeros --file directory/file1
|
||||
genfile --length 10240 --pattern default --file directory/file2
|
||||
@@ -36,7 +37,7 @@ tar cf archive directory || exit 1
|
||||
echo separator
|
||||
tar uf archive directory || exit 1
|
||||
echo separator
|
||||
tar tf archive | sort 2>/dev/null || exit 1
|
||||
tar tf archive | sort || exit 1
|
||||
],
|
||||
[0],
|
||||
[separator
|
||||
|
||||
44
tests/verbose.at
Normal file
44
tests/verbose.at
Normal file
@@ -0,0 +1,44 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Version 1.15.92 sent verbose output to the archive when invoked
|
||||
# as tar cvf - foo.txt > foo.tar
|
||||
# Reported by Mike Frysinger <vapier@gentoo.org>
|
||||
# References: <200610131946.20530.vapier@gentoo.org>
|
||||
|
||||
AT_SETUP([tar cvf -])
|
||||
AT_KEYWORDS([stdout verbose])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --file file --length 10240
|
||||
echo Creating the archive
|
||||
tar cvf - file > archive
|
||||
echo Testing the archive
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[Creating the archive
|
||||
Testing the archive
|
||||
file
|
||||
],
|
||||
[file
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -21,6 +21,15 @@ AT_SETUP([tar version])
|
||||
AT_CHECK([tar --version | sed 1q],
|
||||
[0],
|
||||
[AT_PACKAGE_TARNAME (AT_PACKAGE_NAME) AT_PACKAGE_VERSION
|
||||
])
|
||||
],
|
||||
[],
|
||||
[cat >$[]XFAILFILE <<'_EOT'
|
||||
|
||||
==============================================================
|
||||
WARNING: Not using the proper version, *all* checks dubious...
|
||||
==============================================================
|
||||
_EOT
|
||||
],
|
||||
[rm -f $[]XFAILFILE])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
60
tests/volsize.at
Normal file
60
tests/volsize.at
Normal file
@@ -0,0 +1,60 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Description: The size field of a volume header was ignored when listing,
|
||||
# but taken into account when extracting. Thus it was possible to hide
|
||||
# some files within the archive, placing them after a volume header and
|
||||
# manually modifying its size field. Test tarball kindly provided by Tomas.
|
||||
# Reported by: Thomas <metaf4@users.askja.de>
|
||||
# References: <4462E13A.3080008@users.askja.de>,
|
||||
# <44639C4C.5050401@users.askja.de>
|
||||
|
||||
AT_SETUP([volume header size])
|
||||
AT_KEYWORDS([volume volsize])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
AT_TARBALL_PREREQ([abc.tar],[540f196ceddcad9e7bd2f2d7533d0474])
|
||||
|
||||
echo Short Listing
|
||||
tar tf $TEST_DATA_DIR/abc.tar
|
||||
echo Verbose Listing
|
||||
tar tfv $TEST_DATA_DIR/abc.tar
|
||||
echo Extracted directory
|
||||
tar xf $TEST_DATA_DIR/abc.tar
|
||||
find abc|sort
|
||||
],
|
||||
[0],
|
||||
[Short Listing
|
||||
abc/not-a-file.gif
|
||||
abc/CCC
|
||||
Verbose Listing
|
||||
V--------- 0/0 1536 2006-05-09 01:07 abc/not-a-file.gif--Volume Header--
|
||||
-rw-r--r-- tom/users 0 2006-04-22 22:52 abc/CCC
|
||||
Extracted directory
|
||||
abc
|
||||
abc/CCC
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
# End of volsize.at
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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
|
||||
@@ -21,7 +21,7 @@
|
||||
# Volume labels are checked on read by fnmatch.
|
||||
|
||||
AT_SETUP([volume])
|
||||
AT_KEYWORDS([volume])
|
||||
AT_KEYWORDS([volume volcheck])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
tar -cf archive -V label -T /dev/null || exit 1
|
||||
|
||||
Reference in New Issue
Block a user