263 Commits

Author SHA1 Message Date
Sergey Poznyakoff
f572ca0cfb Update 2006-10-21 16:48:08 +00:00
Sergey Poznyakoff
29236a68fa (distclean-local): New rule 2006-10-21 16:47:56 +00:00
Sergey Poznyakoff
a4b1564d4a Version 1.16 2006-10-21 16:47:42 +00:00
Sergey Poznyakoff
94d0385a57 Update 2006-10-17 08:14:06 +00:00
Sergey Poznyakoff
603c1d60a6 Fix help output formatting. Thanks Benno Schulenberg. 2006-10-17 08:13:43 +00:00
Sergey Poznyakoff
29e9004b69 Update 2006-10-16 07:51:40 +00:00
Sergey Poznyakoff
8da152d2b3 Update 2006-10-16 07:49:00 +00:00
Sergey Poznyakoff
00746182f3 (dist-hook): Create a cpio archive. 2006-10-16 07:48:51 +00:00
Sergey Poznyakoff
6c8815909d Update 2006-10-14 21:13:28 +00:00
Sergey Poznyakoff
fde336b21a (AT_KEYWORDS): Keyword `filechange'
Test tar exit status.
2006-10-14 21:12:42 +00:00
Sergey Poznyakoff
394b12d950 New test grow.at 2006-10-14 21:12:04 +00:00
Sergey Poznyakoff
372638ae7a Do not attempt to close stderr after call to close_stdout. 2006-10-14 21:11:43 +00:00
Sergey Poznyakoff
c455373e5b (dump_regular_file,dump_file0): Set exit_status to
TAREXIT_DIFFERS if the file being dumped was truncated or
otherwise changed.
2006-10-14 21:11:27 +00:00
Sergey Poznyakoff
f2541c66cd (Synopsis): Document tar exit codes. 2006-10-14 21:11:03 +00:00
Sergey Poznyakoff
7e6d54d0c0 Update 2006-10-14 10:48:14 +00:00
Sergey Poznyakoff
876e554157 (AT_KEYWORDS): Add stdout keyword 2006-10-14 10:46:24 +00:00
Sergey Poznyakoff
1118d24fd3 New test verbose.at 2006-10-14 10:46:13 +00:00
Sergey Poznyakoff
dc6f7ebf20 (_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.
2006-10-14 10:45:44 +00:00
Sergey Poznyakoff
1102eeef1f Update 2006-10-02 15:45:08 +00:00
Sergey Poznyakoff
e8a4c35a73 Add new testcase: multiv05.at: 2006-10-02 15:44:52 +00:00
Sergey Poznyakoff
e359fad641 (xheader_string_end): Fix diagnostic message. 2006-10-02 15:44:20 +00:00
Sergey Poznyakoff
f5504a3bae (new_volume): Initialize current_block 2006-10-02 15:44:09 +00:00
Sergey Poznyakoff
341be8f405 Add Joerg Weilbier 2006-10-02 15:43:59 +00:00
Sergey Poznyakoff
4f2a22f306 Update 2006-09-27 09:03:23 +00:00
Sergey Poznyakoff
a76ab340dd (doc0, doc1, initialize_argp_doc): Removed. Rely on the new argp method instead 2006-09-27 09:03:13 +00:00
Sergey Poznyakoff
3ad3ca8734 Minor fix 2006-09-27 09:03:02 +00:00
Sergey Poznyakoff
82b2829e10 Use ${package} instead of hardcoding package name 2006-09-27 09:02:45 +00:00
Sergey Poznyakoff
f852428d5f Update 2006-09-12 09:59:08 +00:00
Sergey Poznyakoff
86e91a5bfc Fix typo 2006-09-12 09:56:39 +00:00
Paul Eggert
ec5743a628 * tests/testsuite.at (AT_TAR_MKHIER): Use install-sh -d
rather than the no-longer-included mkinstalldirs.
2006-09-08 23:29:43 +00:00
Paul Eggert
bf7f4fdc1e Add at-func.c, configmake.h, fchmodat.c,
fcntl.h, fcntl_.h, inttypes_.h, lstat.c, lstat.h.
2006-09-08 23:27:45 +00:00
Sergey Poznyakoff
98b9522499 Update 2006-09-08 16:47:15 +00:00
Sergey Poznyakoff
6398dbe1a5 List texinfo among build prerequisites for the CVS version. 2006-09-08 16:47:01 +00:00
Sergey Poznyakoff
37724f5e20 (try_purge_directory): Initialize struct st. Fix condition for selecting candidates for removal. 2006-09-08 16:45:41 +00:00
Sergey Poznyakoff
c8c351684c (intl_files_to_remove): Do not remove m4/inttypes-h.m4 and m4/inttypes-pri.m4 2006-09-08 15:17:56 +00:00
Paul Eggert
01b6fb98bf * 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.
2006-08-11 21:39:36 +00:00
Paul Eggert
f1309bffbf * bootstrap (get_translations):
Don't exclude ky.po; it is working again.
2006-08-11 07:44:21 +00:00
Paul Eggert
c732eb584e * bootstrap: 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-09 18:30:16 +00:00
Paul Eggert
0680ad4d42 * 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.
2006-08-08 05:28:32 +00:00
Paul Eggert
1942370acd Fix typo: remove po/tar.html. 2006-08-07 22:58:12 +00:00
Paul Eggert
94de7c4c77 * 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.
2006-08-07 22:57:25 +00:00
Paul Eggert
05805868f2 (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.
2006-08-07 21:29:27 +00:00
Paul Eggert
57aa98047e gettext 0.15 rejects this. 2006-08-07 21:12:21 +00:00
Sergey Poznyakoff
7573967406 Update 2006-07-24 09:14:18 +00:00
Sergey Poznyakoff
ab8711413c Add append02.at 2006-07-24 09:14:00 +00:00
Sergey Poznyakoff
9fd9a0913d New test case 2006-07-24 09:13:44 +00:00
Sergey Poznyakoff
f4e4adea80 (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.
2006-07-24 09:13:21 +00:00
Sergey Poznyakoff
7110641821 (decode_options): Do not require -L with -M -Hpax.
It could be needed in future, but currently it is not.
2006-07-24 09:12:55 +00:00
Paul Eggert
fce454b5ca * bootstrap: Adjust to today's change to gnulib-tool by invoking
it with --assume-autoconf='latest-stable'.
2006-07-20 16:57:31 +00:00
Paul Eggert
8ad985ea6c 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-17 05:47:26 +00:00
Sergey Poznyakoff
37edfd9e8f Update 2006-07-09 11:26:46 +00:00
Sergey Poznyakoff
016f7c87a7 Update 2006-07-09 11:26:16 +00:00
Sergey Poznyakoff
52b8bea074 Add Ralf Wildenhues 2006-07-09 11:25:47 +00:00
Sergey Poznyakoff
5addfdcb03 Fix some typos 2006-07-09 11:25:18 +00:00
Sergey Poznyakoff
e707b47aba Fix entry ordering 2006-07-06 20:10:37 +00:00
Sergey Poznyakoff
76dc519f9f Update 2006-07-06 20:08:53 +00:00
Sergey Poznyakoff
2a00376816 (TESTSUITE_AT): Add indexfile.at 2006-07-06 20:08:20 +00:00
Sergey Poznyakoff
9766528b07 Include indexfile.at 2006-07-06 20:08:09 +00:00
Sergey Poznyakoff
f26a90783b New test case 2006-07-06 20:08:01 +00:00
Sergey Poznyakoff
36fe16aaf5 (decode_options): Initialize stdlis 2006-07-06 20:07:37 +00:00
Sergey Poznyakoff
89f1667fdb (_open_archive): Remove stdlis initialization 2006-07-06 20:05:30 +00:00
Sergey Poznyakoff
f2d65dda39 Update 2006-07-05 06:46:53 +00:00
Sergey Poznyakoff
8370746251 (FIXME): Do not use deprecated @quote-args.
Do not use @allow-recursion. In its current form the macro is not
recursive.
2006-07-05 06:46:32 +00:00
Sergey Poznyakoff
2614af6d3c (manual): Fix TEXINPUTS 2006-07-05 06:46:11 +00:00
Sergey Poznyakoff
614def3113 Update 2006-07-04 21:53:40 +00:00
Sergey Poznyakoff
b6365e9b03 Update 2006-07-04 21:52:53 +00:00
Sergey Poznyakoff
bf789e3642 Update --directory description 2006-07-04 21:52:34 +00:00
Sergey Poznyakoff
1421ee630d (main): Call closeopen 2006-07-04 21:52:14 +00:00
Sergey Poznyakoff
9869d0ae17 (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.
2006-07-04 21:52:05 +00:00
Sergey Poznyakoff
edc0b12c5e (closeopen): New function 2006-07-04 21:51:42 +00:00
Sergey Poznyakoff
808cafa454 (AC_CHECK_FUNCS): Check for getdtablesize 2006-07-04 21:51:33 +00:00
Sergey Poznyakoff
d1dedae402 (update_po): Fix single translation update 2006-07-03 16:46:14 +00:00
Sergey Poznyakoff
de754902da Update 2006-06-27 13:39:20 +00:00
Sergey Poznyakoff
bc7f4ad027 Update 2006-06-26 14:42:35 +00:00
Sergey Poznyakoff
55abc110f5 Add cross-references 2006-06-26 14:42:18 +00:00
Sergey Poznyakoff
4d753fced1 Minor fixes 2006-06-26 12:48:25 +00:00
Sergey Poznyakoff
85a4e0fdeb Do not depend on getopt.h 2006-06-26 11:18:54 +00:00
Sergey Poznyakoff
583415c2c1 Update 2006-06-26 08:09:18 +00:00
Sergey Poznyakoff
6488588c5f Update 2006-06-26 08:08:47 +00:00
Sergey Poznyakoff
ac40b1e6f6 Update 2006-06-25 12:46:43 +00:00
Sergey Poznyakoff
4bf5f6dca4 --sparse-version turns on --sparse 2006-06-25 12:46:12 +00:00
Sergey Poznyakoff
ecaff7cbba Use ST_IS_SPARSE instead of sparse_file_p (update paxutils first) 2006-06-25 12:45:57 +00:00
Sergey Poznyakoff
ea9e2d8d8e (sparse_file_p): Remove 2006-06-25 12:45:16 +00:00
Sergey Poznyakoff
39e5d9182c (Other Tars): New node describing how to extract
GNU-specific member formats using third-party tars.
2006-06-25 12:45:03 +00:00
Sergey Poznyakoff
c7aa519f09 (tar_TEXINFOS): Sorted 2006-06-25 12:44:15 +00:00
Sergey Poznyakoff
bf5ba3dbef 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.
2006-06-25 12:44:04 +00:00
Sergey Poznyakoff
ea368b6d1b Update 2006-06-24 16:50:11 +00:00
Sergey Poznyakoff
d0201294c0 (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-24 16:49:33 +00:00
Sergey Poznyakoff
c5b15c4ac1 (segm_count): Change type to size_t 2006-06-24 16:49:05 +00:00
Sergey Poznyakoff
4b3dd17c00 (pax_dump_header_0): Return false if
xheader_string_end fails (for 0.1 formats).
(pax_dump_header): Return meaningful value
2006-06-24 16:48:45 +00:00
Sergey Poznyakoff
d339cc38af Remove not used variables 2006-06-24 16:48:24 +00:00
Sergey Poznyakoff
796a69787e (extract_volhdr): Add missing return 2006-06-24 16:48:08 +00:00
Sergey Poznyakoff
4c54e234c1 (name_init): New prototype.
(xheader_string_end): Return bool.
2006-06-24 16:47:57 +00:00
Sergey Poznyakoff
c027e03924 (print_total_stats): Add default case 2006-06-24 16:47:29 +00:00
Sergey Poznyakoff
6d615f12d4 Update 2006-06-23 15:24:53 +00:00
Sergey Poznyakoff
8f970d2c1e Include sparsemvp.at, spmvp00.at, spmvp01.at, spmvp10.at 2006-06-23 15:24:43 +00:00
Sergey Poznyakoff
d04af8f714 Rewritten as an include file.
(TAR_MVP_TEST): New macro
2006-06-23 15:24:10 +00:00
Sergey Poznyakoff
e2ecb82711 Explicitely give `-f -' to the tar invocation 2006-06-23 15:23:47 +00:00
Sergey Poznyakoff
8e2e731733 Add spmvp00.at, spmpv01.at, spmpv10.at 2006-06-23 15:23:16 +00:00
Sergey Poznyakoff
19a63e523d Implement new keywords: GNU.sparse.name, GNU.sparse.major, GNU.sparse.minor, GNU.sparse.realsize 2006-06-23 15:22:50 +00:00
Sergey Poznyakoff
5679d3020e (struct tar_stat_info.sparse_major,sparse_minor): New members 2006-06-23 15:22:31 +00:00
Sergey Poznyakoff
1001c1b326 New option --sparse-version 2006-06-23 15:22:12 +00:00
Sergey Poznyakoff
090d1d36ae 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
2006-06-23 15:21:48 +00:00
Sergey Poznyakoff
2e1f904f2c (tar_sparse_major,tar_sparse_minor): New globals. 2006-06-23 15:20:06 +00:00
Sergey Poznyakoff
6a0b5421b9 Update master menu 2006-06-23 15:19:47 +00:00
Sergey Poznyakoff
9c764b14a9 (Sparse Formats): New node 2006-06-23 15:19:27 +00:00
Sergey Poznyakoff
ae67839879 (tar_TEXINFOS): Add sparse.texi 2006-06-23 15:19:08 +00:00
Sergey Poznyakoff
9588a106a7 New files 2006-06-23 15:18:18 +00:00
Sergey Poznyakoff
b3627f3f07 Update 2006-06-21 10:44:29 +00:00
Sergey Poznyakoff
ca7df3fe6b Raise version number to 1.15.92 2006-06-21 10:44:16 +00:00
Sergey Poznyakoff
ab19642053 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.
2006-06-21 10:40:39 +00:00
Sergey Poznyakoff
a71b154289 (start_header): Override mtime if requested 2006-06-21 10:40:10 +00:00
Sergey Poznyakoff
ceaef10443 (set_mtime_option,mtime_option): New globals 2006-06-21 10:39:58 +00:00
Sergey Poznyakoff
5da6733724 (Overriding File Metadata): New node
Document --mtime option.
2006-06-21 10:39:52 +00:00
Sergey Poznyakoff
8d6c177ecb update 2006-06-20 15:15:11 +00:00
Sergey Poznyakoff
1ecd6672e1 (GNU.sparse.name): New variable for storing sparse file name. 2006-06-20 15:14:59 +00:00
Sergey Poznyakoff
ca2f855c90 (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.
2006-06-20 15:14:47 +00:00
Sergey Poznyakoff
693134a4e7 (name_next_elt): Call register_individual_file
(namelist_match): Remove third argument
(name_match): Change return type to bool
(name_scan): Remove second argument
2006-06-20 15:14:19 +00:00
Sergey Poznyakoff
90cec95580 (maybe_backup_file): Second argument is bool 2006-06-20 15:14:00 +00:00
Sergey Poznyakoff
b6fcb4ba8f (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)
2006-06-20 15:13:49 +00:00
Sergey Poznyakoff
6d1e9ab67e Remove second argument from calls to name_scan 2006-06-20 15:13:30 +00:00
Sergey Poznyakoff
300210aa15 (struct name.explicit): Remove
Use variable names in all declarations
(name_scan): Remove second argument
2006-06-20 15:13:20 +00:00
Sergey Poznyakoff
532b2dd31f Fix typo in a comment 2006-06-16 07:19:34 +00:00
Sergey Poznyakoff
3358f5fcc3 Update 2006-06-13 19:34:20 +00:00
Sergey Poznyakoff
51e3f3f1ca Update 2006-06-13 14:59:43 +00:00
Sergey Poznyakoff
caf6b29f1e (Using Multiple Tapes,Multi-Volume Archives): Rewritten 2006-06-13 14:59:32 +00:00
Sergey Poznyakoff
12ae9f6912 Update 2006-06-13 13:35:46 +00:00
Sergey Poznyakoff
64041696c9 (xopindex,opsummary): New macros 2006-06-13 13:35:34 +00:00
Sergey Poznyakoff
8ee09b9939 Define op as codeindex. Use xopindex and opsummary 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.
2006-06-13 13:35:14 +00:00
Sergey Poznyakoff
72f60f9e5f (FIXME) [!PROOF_FOOTNOTED]: Enclose in a cartouche 2006-06-13 13:34:32 +00:00
Sergey Poznyakoff
378818cb3e (check-options): Expand macros before grepping in $(info_TEXINFOS) 2006-06-13 13:34:14 +00:00
Sergey Poznyakoff
c980a06329 Update 2006-06-12 22:51:32 +00:00
Sergey Poznyakoff
4c7a2b10b8 Implement --overwrite-dir option (long ago documented) 2006-06-12 22:50:29 +00:00
Sergey Poznyakoff
8f3ed604b9 Update 2006-06-12 22:50:17 +00:00
Sergey Poznyakoff
b886724818 (check-options): New goal 2006-06-12 22:49:37 +00:00
Sergey Poznyakoff
f143fa5d64 Update 2006-06-12 13:21:28 +00:00
Sergey Poznyakoff
1e3568d947 (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-12 13:20:10 +00:00
Sergey Poznyakoff
b229a86dd7 (check_time): Use volume_start_time when checking
for the timestamp plausability.
2006-06-12 13:19:43 +00:00
Sergey Poznyakoff
05b250d4a4 (records_skipped): Remove static qualifier, the
variable is used by print_total_stats in buffer.c
2006-06-12 13:19:16 +00:00
Sergey Poznyakoff
42d180b24e (volume_start_time,last_stat_time): New globals
(print_total_written): Replaced with:
(print_total_stats): New function
2006-06-12 13:18:59 +00:00
Sergey Poznyakoff
8c10111c66 (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.
2006-06-12 13:18:26 +00:00
Sergey Poznyakoff
15a55db341 Update 2006-06-12 13:17:54 +00:00
Sergey Poznyakoff
e721e74259 Document better the --totals option. 2006-06-12 13:17:42 +00:00
Sergey Poznyakoff
1bea3b4b25 Update 2006-06-11 20:07:20 +00:00
Sergey Poznyakoff
4ef056729e (xheader_set_single_keyword): Fix typo.
(decode_time): Avoid using gotos.
2006-06-11 20:06:46 +00:00
Sergey Poznyakoff
37986cdff9 Update 2006-06-11 15:05:52 +00:00
Sergey Poznyakoff
5fe07ac97d Update master menu 2006-06-11 15:05:22 +00:00
Sergey Poznyakoff
a35935e973 (master-menu): New goal 2006-06-11 15:04:39 +00:00
Sergey Poznyakoff
e832cab432 New file 2006-06-11 15:04:17 +00:00
Sergey Poznyakoff
578f46309f Update 2006-06-10 09:55:20 +00:00
Sergey Poznyakoff
4396675861 Remove leftover include 2006-06-10 09:54:02 +00:00
Sergey Poznyakoff
a3dd97d9be Update 2006-06-09 13:55:36 +00:00
Sergey Poznyakoff
13adf3f762 Update 2006-06-09 13:50:20 +00:00
Sergey Poznyakoff
f1b1e9a476 Fix indentation, introduce end-of-format marker for texify.sed 2006-06-09 13:50:04 +00:00
Sergey Poznyakoff
fc4502c17e Update 2006-06-09 13:49:51 +00:00
Sergey Poznyakoff
0abf3a5ac9 Fix typo 2006-06-09 13:49:39 +00:00
Sergey Poznyakoff
19b36aaf60 Auxiliary script to convert ../src/tar.h to header.texi 2006-06-09 13:48:28 +00:00
Sergey Poznyakoff
9b44f8efed *** empty log message *** 2006-06-09 13:46:53 +00:00
Sergey Poznyakoff
97bfe578ed New file 2006-06-09 13:46:34 +00:00
Sergey Poznyakoff
fb88325f56 (tar_TEXINFOS): Add intern.texi
(EXTRA_DIST): Remove convtexi.pl, add texify.sed
2006-06-09 13:46:11 +00:00
Sergey Poznyakoff
a1b2406646 Update 2006-06-08 22:36:30 +00:00
Sergey Poznyakoff
5e14ef32c0 Minor fixes. 2006-06-08 22:35:52 +00:00
Sergey Poznyakoff
f9bd340c1b --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
2006-06-08 22:35:39 +00:00
Sergey Poznyakoff
46defea70e (checkpoint_option): Change type to unsigned
(checkpoint_style): New variable.
2006-06-08 22:34:56 +00:00
Sergey Poznyakoff
5daab19c27 Implement more flexible checkpoint style 2006-06-08 22:34:38 +00:00
Sergey Poznyakoff
7214086d3d Update 2006-06-08 22:34:16 +00:00
Sergey Poznyakoff
93560dd669 Add Jason Armistead 2006-06-08 22:33:33 +00:00
Sergey Poznyakoff
c1f55f1c37 Update 2006-06-08 14:43:23 +00:00
Sergey Poznyakoff
2d2e1d411e (dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce
X control code.
(make_tmp_dir_name): Remove
2006-06-08 14:43:05 +00:00
Sergey Poznyakoff
5591fa407a Document dumpdir format 2006-06-08 14:42:20 +00:00
Sergey Poznyakoff
e2dbba2f07 (tar_TEXINFOS): Add dumpdir.texi 2006-06-08 14:42:07 +00:00
Sergey Poznyakoff
018de58373 New file 2006-06-08 14:41:56 +00:00
Sergey Poznyakoff
17111bef8f Add mkdtemp 2006-06-08 14:41:15 +00:00
Sergey Poznyakoff
3a9f2ea587 Update 2006-06-08 09:51:06 +00:00
Sergey Poznyakoff
02c7b862a3 (add_char_segment): Fix length assignement 2006-06-08 09:50:56 +00:00
Sergey Poznyakoff
9154c0c43b Update 2006-06-08 09:43:44 +00:00
Sergey Poznyakoff
5108a3dc41 Update 2006-06-08 09:34:03 +00:00
Sergey Poznyakoff
c52e5fc4e8 Update 2006-06-08 09:28:18 +00:00
Sergey Poznyakoff
0fc3177ed2 Update 2006-06-08 09:27:38 +00:00
Sergey Poznyakoff
6be1349236 (set_transform_expr,_transform_name_to_obstack): Implement NUMBER flag. 2006-06-08 09:27:25 +00:00
Sergey Poznyakoff
a2625311c8 Update 2006-06-07 14:57:57 +00:00
Sergey Poznyakoff
6e2760f7d7 Update 2006-06-07 14:57:29 +00:00
Sergey Poznyakoff
8b2f4ad670 (_transform_name_to_obstack,set_transform_expr): Implement case conversion operations (GNU extension). 2006-06-07 14:57:10 +00:00
Sergey Poznyakoff
d4c0836ec2 Update 2006-06-06 21:36:17 +00:00
Sergey Poznyakoff
40afe4d362 Update 2006-06-06 21:35:22 +00:00
Sergey Poznyakoff
435edb824e (transform_name_fp): Run fun even if _transform_name_to_obstack returns false. 2006-06-06 21:33:25 +00:00
Sergey Poznyakoff
9d2e8df195 Update 2006-06-06 21:30:26 +00:00
Sergey Poznyakoff
aa7476a68e Update 2006-06-03 20:53:17 +00:00
Sergey Poznyakoff
16c48ef8d0 Update 2006-06-02 15:07:00 +00:00
Sergey Poznyakoff
0da8aac59f Use genfile --files-from 2006-06-02 15:06:29 +00:00
Sergey Poznyakoff
bb6f707781 Fix typo in the comment 2006-06-02 15:06:19 +00:00
Sergey Poznyakoff
7cb01d37bb Add incr04.at 2006-06-02 15:06:10 +00:00
Sergey Poznyakoff
d79bbe0fd1 (set_transform_expr): New function 2006-06-02 15:05:52 +00:00
Sergey Poznyakoff
f984c43b82 Update 2006-06-02 15:05:36 +00:00
Sergey Poznyakoff
d75890c1b8 (options): Minor rewording 2006-06-02 10:54:05 +00:00
Sergey Poznyakoff
b3b4347821 Update 2006-06-02 10:42:25 +00:00
Sergey Poznyakoff
39080c7628 Update 2006-06-02 08:08:10 +00:00
Sergey Poznyakoff
c58063c17a New option --transform
New option --show-transformed-names generalizes
--show-stored-names. The latter is retained as an alias.
2006-06-02 08:06:46 +00:00
Sergey Poznyakoff
ae7bd36423 (print_header): Update displayable name selection. 2006-06-02 08:05:04 +00:00
Sergey Poznyakoff
973b611290 (extract_archive): safer_name_suffix and stripped_prefix_len are now called by decode_header 2006-06-02 08:04:37 +00:00
Sergey Poznyakoff
29fb7356df (dump_file0): Transform file name 2006-06-02 08:03:53 +00:00
Sergey Poznyakoff
bbee515590 (transform_name, transform_name_fp): New functions
(show_stored_names_option): Renamed to
show_transformed_names_option. All uses changed
2006-06-02 08:03:08 +00:00
Sergey Poznyakoff
c8aa01c80c New file 2006-06-02 08:02:24 +00:00
Sergey Poznyakoff
43ba23114f (tar_SOURCES): New module transform.c 2006-06-02 08:01:44 +00:00
Sergey Poznyakoff
7bfcbd6a27 Update 2006-06-02 08:01:33 +00:00
Sergey Poznyakoff
c5fd5f9e8d Update 2006-05-31 12:45:44 +00:00
Sergey Poznyakoff
a23a95b4a0 (make_directory): Fix initialization of struct directory. 2006-05-31 12:45:14 +00:00
Sergey Poznyakoff
19498c9172 Initialize AM_CPPFLAGS 2006-05-25 19:29:03 +00:00
Sergey Poznyakoff
edff149522 Update 2006-05-25 14:13:07 +00:00
Sergey Poznyakoff
f20e08dd45 (parse_opt): Add comment before --preserve case. 2006-05-25 14:12:51 +00:00
Sergey Poznyakoff
e6d15fc7af Updated 2006-05-25 14:12:35 +00:00
Sergey Poznyakoff
c96ba08e06 Update 2006-05-25 11:02:50 +00:00
Sergey Poznyakoff
6f89b1fce5 Document use of wildcards 2006-05-25 11:02:09 +00:00
Sergey Poznyakoff
93f8f6780a Update 2006-05-25 07:05:58 +00:00
Sergey Poznyakoff
75f37f4cef Make AT_SETUP more readable. 2006-05-25 07:05:41 +00:00
Sergey Poznyakoff
3947e63c25 (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.
2006-05-25 07:05:28 +00:00
Sergey Poznyakoff
8b471d55ff 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
2006-05-25 07:04:53 +00:00
Sergey Poznyakoff
c2c2df6c93 (dump_file,dump_file0): First argument is const char*. All callers updated. 2006-05-25 07:04:15 +00:00
Sergey Poznyakoff
cf857388c1 (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*.
2006-05-25 07:03:57 +00:00
Sergey Poznyakoff
9dfad74683 (AM_INIT_AUTOMAKE): Use tar-ustar option. Raise version requirement to 1.9 2006-05-25 07:03:30 +00:00
Sergey Poznyakoff
57267f7ed9 Update 2006-05-25 07:02:59 +00:00
Sergey Poznyakoff
476abe556b Update 2006-05-23 07:10:55 +00:00
Sergey Poznyakoff
fe72c79ad8 (change_tape_menu): Fix typo (uninitialized variable) introduced yesterday. 2006-05-23 07:10:34 +00:00
Sergey Poznyakoff
8fea578b22 Update 2006-05-22 10:02:32 +00:00
Sergey Poznyakoff
a46704b1bf (change_tape_menu): Break the loop after obtaining new archive name. Check for empty input line 2006-05-22 10:02:23 +00:00
Sergey Poznyakoff
6f8cbc5ca8 Use @var{file_name} instead of @var{file name} 2006-05-22 10:01:34 +00:00
Sergey Poznyakoff
c03131aba9 Update 2006-05-15 09:52:29 +00:00
Sergey Poznyakoff
c9195c75be (AT_TAR_CHECK): Declare expected failure if $XFAILFILE exists. 2006-05-15 09:52:16 +00:00
Sergey Poznyakoff
5632d195f5 Create $XFAILFILE on failure 2006-05-15 09:52:03 +00:00
Sergey Poznyakoff
ef90e05363 (XFAILFILE): New variable 2006-05-15 09:51:53 +00:00
Sergey Poznyakoff
939d63b92d Update 2006-05-13 14:03:46 +00:00
Sergey Poznyakoff
0ff13351f0 Update 2006-05-13 14:01:26 +00:00
Sergey Poznyakoff
c57418b462 New file 2006-05-13 14:01:13 +00:00
Sergey Poznyakoff
3c7dd57a17 Update 2006-05-13 13:58:59 +00:00
Sergey Poznyakoff
0b3fe146dd Update 2006-05-13 12:16:09 +00:00
Sergey Poznyakoff
90088ff00d Update 2006-05-13 12:02:58 +00:00
Sergey Poznyakoff
a183d6f7f5 Update 2006-05-13 12:00:06 +00:00
Sergey Poznyakoff
4883aab47d (AT_STAR_PREREQ): Provide md5 sum. 2006-05-13 11:59:51 +00:00
Sergey Poznyakoff
30873dbd97 Add keywords. 2006-05-13 11:59:36 +00:00
Sergey Poznyakoff
74849d8119 (AT_TARBALL_PREREQ): New defun
(AT_STAR_PREREQ): Rewrite using tarball_prereq
Include chtype.at and volsize.at
2006-05-13 11:59:08 +00:00
Sergey Poznyakoff
3962eb6a3e (TEST_DATA_URL,STAR_DATA_URL)
(STAR_TESTSCRIPTS): Provide default values.
(tarball_prereq): New function
2006-05-13 11:58:41 +00:00
Sergey Poznyakoff
c99076e925 (TESTSUITE_AT): Add chtype.at, volsize.at
(check-full): New target
2006-05-13 11:58:16 +00:00
Sergey Poznyakoff
6315d1700b (read_header_primitive): New function
(read_header): Front end for read_header_primitive
2006-05-13 11:57:52 +00:00
Sergey Poznyakoff
520104f5f8 (extract_volhdr): New function
(prepare_to_extract): Use extract_volhdr as extractor for volume
names.
2006-05-13 11:57:36 +00:00
Sergey Poznyakoff
34e5f66589 (read_header_primitive): New function 2006-05-13 11:57:20 +00:00
Sergey Poznyakoff
d2b3114a3b (read_header0): Use read_header_primitive to avoid clubbering current_tar_info. All callers updated. 2006-05-13 11:57:06 +00:00
Sergey Poznyakoff
2b27e8de1f Update 2006-05-13 11:56:51 +00:00
Sergey Poznyakoff
a85cfd69e3 (find_directory_meta): Bugfix 2006-05-13 08:38:12 +00:00
Sergey Poznyakoff
4b951034f3 Update 2006-05-08 12:48:27 +00:00
Sergey Poznyakoff
1524831224 Call AT_SORT_PREREQ. Remove fd 2 redirection after sort invocations 2006-05-08 12:46:41 +00:00
Sergey Poznyakoff
ee6f14194d Call AT_UNPRIVILEGED_PREREQ 2006-05-08 12:46:16 +00:00
Sergey Poznyakoff
ac7f4e853d (AT_SORT_PREREQ, AT_UNPRIVILEGED_PREREQ): New defines 2006-05-08 12:46:01 +00:00
Sergey Poznyakoff
47dd75e87b Update 2006-05-08 12:12:45 +00:00
Sergey Poznyakoff
6054b5e9d5 (AT_KEYWORDS): Add missing incremental kw 2006-05-08 12:12:09 +00:00
Sergey Poznyakoff
edd6df370d Update for the new behavior 2006-05-08 12:11:53 +00:00
Sergey Poznyakoff
fd89d5a3cd Add incr03.at,rename01.at,rename02.at,rename03.at 2006-05-08 12:11:43 +00:00
Sergey Poznyakoff
71f2e412ae New testcase 2006-05-08 12:11:26 +00:00
Sergey Poznyakoff
67877f7de2 (collect_and_sort_names): Update dir_contents of the first non-fake name entry when in listed incremental mode. 2006-05-08 12:10:36 +00:00
Sergey Poznyakoff
c9e7465642 (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.
2006-05-08 12:10:14 +00:00
Sergey Poznyakoff
a0b4431f26 (rename_directory): New function 2006-05-08 12:09:46 +00:00
Sergey Poznyakoff
192ac7136a (rename_directory,append_incremental_renames): New functions. 2006-05-08 12:09:35 +00:00
Sergey Poznyakoff
c2775aedf1 Raise version number to 1.15.91 2006-05-08 12:09:15 +00:00
Sergey Poznyakoff
f1fe157dfe Update 2006-05-08 12:09:07 +00:00
88 changed files with 9281 additions and 3150 deletions

643
ChangeLog
View File

@@ -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,

View File

@@ -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
View File

@@ -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
View File

@@ -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

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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'."

View File

@@ -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\

View File

@@ -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

View File

@@ -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'

View File

@@ -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
View 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
View 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
View 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

View File

@@ -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

View File

@@ -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
View 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{}.

File diff suppressed because it is too large Load Diff

26
doc/texify.sed Normal file
View 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,\*/,}&,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 =

View File

@@ -2,6 +2,7 @@ index.html
*.po
LINGUAS
Makefile.in.in
Makevars
Makevars.template
Rules-quot
boldquot.sed

View File

@@ -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
View 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;
}

View File

@@ -36,6 +36,7 @@ tar_SOURCES = \
sparse.c\
system.c\
tar.c\
transform.c\
update.c\
utf8.c

View File

@@ -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 ();
}

View File

@@ -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 *));

View File

@@ -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);

View File

@@ -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);

View File

@@ -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, &current_stat_info, &current_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 (&current_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 (&current_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)
{

File diff suppressed because it is too large Load Diff

View File

@@ -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 (&current_stat_info.orig_file_name, name);
assign_string (&current_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 (&current_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, &current_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;

View File

@@ -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")));
}

View File

@@ -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)
{

View File

@@ -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
View File

@@ -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;
}

View File

@@ -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
View 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 (&regex);
}
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 (&regex, str, cflags);
if (rc)
{
char errbuf[512];
regerror (rc, &regex, 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 (&regex, 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);
}

View File

@@ -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;

View File

@@ -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 },

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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([

View File

@@ -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
View 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

View File

@@ -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
View 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
View 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
View 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

View File

@@ -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])

View File

@@ -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)])

View File

@@ -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
View 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

View File

@@ -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([

View File

@@ -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([

View File

@@ -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
View 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
View 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
View 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

View File

@@ -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

View File

@@ -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([

View File

@@ -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

View File

@@ -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
View 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
View 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
View 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

View File

@@ -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

View File

@@ -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
],

View File

@@ -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],

View File

@@ -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 <&-

View File

@@ -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
],

View File

@@ -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
],

View File

@@ -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
],

View File

@@ -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])

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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