Compare commits
332 Commits
alpha_1_13
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb782b023f | ||
|
|
8d44c6b51e | ||
|
|
c575787495 | ||
|
|
71850c6ab3 | ||
|
|
fa87656256 | ||
|
|
7c3510b40d | ||
|
|
5f1e6a6a3b | ||
|
|
aa600ee769 | ||
|
|
bf2b8556e8 | ||
|
|
8263cc7bc0 | ||
|
|
6af2e16b9b | ||
|
|
664ec232d4 | ||
|
|
90b1e24487 | ||
|
|
94f7d4e7c1 | ||
|
|
6323ff0880 | ||
|
|
7b29b10847 | ||
|
|
e6a67c2eb5 | ||
|
|
2e7378e819 | ||
|
|
849ec50941 | ||
|
|
889b8a1046 | ||
|
|
2f034ae71b | ||
|
|
bf8852627a | ||
|
|
73b52b1b9b | ||
|
|
c69d2f6539 | ||
|
|
412fbeb90d | ||
|
|
322114744f | ||
|
|
b5db978830 | ||
|
|
4674867a23 | ||
|
|
d5f1626556 | ||
|
|
c8b0fd28c2 | ||
|
|
dcdbe18968 | ||
|
|
6c941e0826 | ||
|
|
ff989f4b84 | ||
|
|
b2a65edf5c | ||
|
|
d305c258bf | ||
|
|
8ff11f27c1 | ||
|
|
5dee0c1348 | ||
|
|
b55daca933 | ||
|
|
f218c29b13 | ||
|
|
1625cc5f67 | ||
|
|
c0f0d25271 | ||
|
|
2ab1422c04 | ||
|
|
53a80edafc | ||
|
|
75284507b3 | ||
|
|
9b712b0fc8 | ||
|
|
d47a177d3d | ||
|
|
2c7d98238b | ||
|
|
9e2233007c | ||
|
|
06742ec624 | ||
|
|
5b56886a72 | ||
|
|
5db60955f5 | ||
|
|
52030539f7 | ||
|
|
e370518b43 | ||
|
|
3cb52ac16a | ||
|
|
75bf036edc | ||
|
|
6cf99ce8ae | ||
|
|
ae3238495d | ||
|
|
33491a8d7c | ||
|
|
5fd2daf959 | ||
|
|
37ac08b3fe | ||
|
|
35cae74c4c | ||
|
|
a1c8c7bd47 | ||
|
|
71c05b230c | ||
|
|
cf2fa13bc5 | ||
|
|
7d6865480e | ||
|
|
cadabfc4c7 | ||
|
|
6b401f904a | ||
|
|
f3f06e8a71 | ||
|
|
8fed513af1 | ||
|
|
00478f4bd3 | ||
|
|
4ad940344a | ||
|
|
b5d9942a35 | ||
|
|
c0b641f055 | ||
|
|
7347b4f5d5 | ||
|
|
e3bd2a63a6 | ||
|
|
430b139592 | ||
|
|
06bb349ca9 | ||
|
|
2e419759d1 | ||
|
|
da3f3e0b3b | ||
|
|
a0404319e2 | ||
|
|
a2a6547e2d | ||
|
|
5e30076bfd | ||
|
|
7c7da5f79f | ||
|
|
d1f3689d96 | ||
|
|
ac830291f1 | ||
|
|
44283eb6ca | ||
|
|
4ad0f97e2c | ||
|
|
d14f101217 | ||
|
|
19335cdfb4 | ||
|
|
4e4e8c57fd | ||
|
|
df6161b9fe | ||
|
|
33da1b2f64 | ||
|
|
28efbf6944 | ||
|
|
678a4411ea | ||
|
|
001e5cf813 | ||
|
|
fc264a87a8 | ||
|
|
68bd7ac50a | ||
|
|
3f4f5a4bf4 | ||
|
|
e563240b95 | ||
|
|
6522c25b8d | ||
|
|
0ec47c16a9 | ||
|
|
b1f2c77860 | ||
|
|
607c1bf3b4 | ||
|
|
74b3e8ab49 | ||
|
|
8771e7c560 | ||
|
|
1992ef9496 | ||
|
|
73030de19f | ||
|
|
a5f5e75388 | ||
|
|
bd599facc8 | ||
|
|
7f27104062 | ||
|
|
e24d4efed0 | ||
|
|
a418ef678e | ||
|
|
83acd3c604 | ||
|
|
303132dcdc | ||
|
|
3848b93af6 | ||
|
|
93becc4f52 | ||
|
|
03092879ac | ||
|
|
38f39174f2 | ||
|
|
1c0a13aade | ||
|
|
2d041189aa | ||
|
|
f6c0aee290 | ||
|
|
54e4a0df65 | ||
|
|
34ff480be9 | ||
|
|
260acce7a3 | ||
|
|
5a8a98cffe | ||
|
|
320298c663 | ||
|
|
4f3e70b0f9 | ||
|
|
c50565d965 | ||
|
|
df2c78e32b | ||
|
|
56389381fc | ||
|
|
45a6a18d85 | ||
|
|
68ff77508c | ||
|
|
43ca8709c0 | ||
|
|
c4e054673b | ||
|
|
df6200e97e | ||
|
|
9ae5a981fc | ||
|
|
7287be445e | ||
|
|
cafa07d966 | ||
|
|
9038410bb7 | ||
|
|
f3da0c26b8 | ||
|
|
82eff37f6f | ||
|
|
6869d0f6b3 | ||
|
|
81460a0349 | ||
|
|
ae29dcca87 | ||
|
|
ac7c2b7116 | ||
|
|
08cba4e4e5 | ||
|
|
d81b5d6f1e | ||
|
|
55ec665a41 | ||
|
|
4ab8cff6b3 | ||
|
|
e4afe72b7a | ||
|
|
0a3a9744f7 | ||
|
|
ad548198f3 | ||
|
|
4f732c1595 | ||
|
|
f94cf6216b | ||
|
|
44391cb932 | ||
|
|
af15956c4d | ||
|
|
402b50d4d2 | ||
|
|
240a4ed90a | ||
|
|
6938706958 | ||
|
|
cd2c8d4fbb | ||
|
|
421043b6b1 | ||
|
|
24aa94e5cf | ||
|
|
8160c0dae9 | ||
|
|
53614b3dff | ||
|
|
23c2244ddf | ||
|
|
ebdf1bc7a6 | ||
|
|
ba08e339a6 | ||
|
|
951b0370df | ||
|
|
167f5ba2bc | ||
|
|
488430f739 | ||
|
|
80c29e6315 | ||
|
|
432b157a28 | ||
|
|
b121917368 | ||
|
|
fa8cb1895c | ||
|
|
64759986a9 | ||
|
|
d4d6c23008 | ||
|
|
325a45f0f1 | ||
|
|
f41e484f23 | ||
|
|
141d267691 | ||
|
|
3331593d8d | ||
|
|
3344bf9380 | ||
|
|
463d99453f | ||
|
|
d2d5d64cb4 | ||
|
|
32ebe16224 | ||
|
|
a447fd3714 | ||
|
|
792965270b | ||
|
|
916019e417 | ||
|
|
3ee93d341e | ||
|
|
dd4cef1699 | ||
|
|
8286de0946 | ||
|
|
a65779d558 | ||
|
|
e1a4fea80d | ||
|
|
5608be67f7 | ||
|
|
0a79415a97 | ||
|
|
f730b47314 | ||
|
|
48c24ac711 | ||
|
|
3e8f210904 | ||
|
|
ee56bd0d0b | ||
|
|
ecb338ad8e | ||
|
|
ce486a8fd7 | ||
|
|
abba83af27 | ||
|
|
823f96841c | ||
|
|
95256b3c07 | ||
|
|
a7109edd94 | ||
|
|
0500b1ba3e | ||
|
|
e8fa866d3a | ||
|
|
3e0962674f | ||
|
|
3295d54e21 | ||
|
|
be8899e6aa | ||
|
|
b5aff8401f | ||
|
|
933d42174f | ||
|
|
33715a50a3 | ||
|
|
3be53a3c2f | ||
|
|
4c004cff39 | ||
|
|
1c623b11f6 | ||
|
|
898dc536c6 | ||
|
|
2b708cb119 | ||
|
|
c6096f64c5 | ||
|
|
b9c6ebab26 | ||
|
|
bc07e8cce4 | ||
|
|
289687bd1c | ||
|
|
ee3b833d37 | ||
|
|
ad63cd4904 | ||
|
|
d58eaa815d | ||
|
|
f71b35b3f6 | ||
|
|
10eef2def8 | ||
|
|
07727fe74a | ||
|
|
ef87ce7d10 | ||
|
|
22fae29fb7 | ||
|
|
981980ac31 | ||
|
|
6246fffacd | ||
|
|
e128aa980c | ||
|
|
21002fe811 | ||
|
|
13ac1dcc0f | ||
|
|
1695e161be | ||
|
|
66cc5df1c6 | ||
|
|
fc22e70a00 | ||
|
|
43d020e35c | ||
|
|
6c1654791d | ||
|
|
4cca5e5887 | ||
|
|
24af03768f | ||
|
|
d2d8f9ab55 | ||
|
|
31e36b1e93 | ||
|
|
6c4dc180dd | ||
|
|
0273b1ae09 | ||
|
|
640effdebd | ||
|
|
d21a12cf62 | ||
|
|
6d9cdefe83 | ||
|
|
19d51157a5 | ||
|
|
4e2d5f2ee8 | ||
|
|
de5ec134a1 | ||
|
|
45399a7e81 | ||
|
|
e662d0f367 | ||
|
|
b7336abee0 | ||
|
|
dca678e62f | ||
|
|
39e95d7eee | ||
|
|
4b6f666105 | ||
|
|
a963130dd7 | ||
|
|
6f7d0eb14d | ||
|
|
8ad16912cf | ||
|
|
e17093af78 | ||
|
|
c5997e92f0 | ||
|
|
7be4d61e92 | ||
|
|
af244aeef3 | ||
|
|
005449337c | ||
|
|
a6d294236b | ||
|
|
f5461e304c | ||
|
|
3087f4c1c9 | ||
|
|
1b0a1ba7ed | ||
|
|
2bda83b48d | ||
|
|
41d042c05f | ||
|
|
b826791a01 | ||
|
|
2a384c4a84 | ||
|
|
f9dc020f90 | ||
|
|
466e40abe5 | ||
|
|
f131340d6d | ||
|
|
7e2a46c522 | ||
|
|
6dd96965de | ||
|
|
1bcc35dda0 | ||
|
|
2b861845e9 | ||
|
|
6cab217353 | ||
|
|
a5bafe7962 | ||
|
|
096bf74fcf | ||
|
|
a55ec0a319 | ||
|
|
61f44c9361 | ||
|
|
55a96565b5 | ||
|
|
15a607fc11 | ||
|
|
1329cfe9f8 | ||
|
|
3ff03c0c5e | ||
|
|
3030a247b1 | ||
|
|
22c2e2ab8a | ||
|
|
be48ff0699 | ||
|
|
a1d15e7c89 | ||
|
|
ad2c53d626 | ||
|
|
8c0cb259bf | ||
|
|
472f860074 | ||
|
|
d8981440bb | ||
|
|
7f2e3cf63a | ||
|
|
f7dbd14d57 | ||
|
|
106a24176e | ||
|
|
c83fcab116 | ||
|
|
4cb8697f60 | ||
|
|
6bd7b64c78 | ||
|
|
e5882c8220 | ||
|
|
72e3da5dc7 | ||
|
|
7b0b6c4e7a | ||
|
|
683390b02d | ||
|
|
e189bd8eca | ||
|
|
5282ef9709 | ||
|
|
b38e4b4520 | ||
|
|
9f14fd52de | ||
|
|
2345d02c63 | ||
|
|
6f219c485e | ||
|
|
a06ed48867 | ||
|
|
d6929326e7 | ||
|
|
7fb546943e | ||
|
|
37400fa94e | ||
|
|
8c1b242931 | ||
|
|
176557a004 | ||
|
|
427f8d6185 | ||
|
|
d584c1ed0f | ||
|
|
a8d1b579d7 | ||
|
|
5a9174376b | ||
|
|
cedd9d6e81 | ||
|
|
29584d69fd | ||
|
|
236deef28e | ||
|
|
ca84e28ee5 | ||
|
|
81bf1687f8 | ||
|
|
7afd75ed24 | ||
|
|
3dbc6a6645 | ||
|
|
d8b790047f | ||
|
|
fb9a7d180f |
@@ -18,4 +18,7 @@ stamp-h1
|
||||
*.shar.gz
|
||||
gnulib
|
||||
gnulib/*
|
||||
gnulib/*/*
|
||||
gnulib/*/*
|
||||
rmt
|
||||
rmt/*
|
||||
rmt/*/*
|
||||
|
||||
@@ -20,4 +20,5 @@
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = ChangeLog.1 PORTS
|
||||
SUBDIRS = doc lib src scripts po tests
|
||||
SUBDIRS = doc lib rmt src scripts po tests
|
||||
|
||||
|
||||
123
NEWS
123
NEWS
@@ -5,8 +5,69 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
version 1.15 - Sergey Poznyakoff, 2004-12-20
|
||||
|
||||
version 1.13.93
|
||||
* Compressed archives are recognised automatically, it is no longer
|
||||
necessary to specify -Z, -z, or -j options to read them. Thus, you can
|
||||
now run `tar tf archive.tar.gz'.
|
||||
|
||||
* When restoring incremental dumps, --one-file-system option
|
||||
prevents directory hierarchies residing on different devices
|
||||
from being purged.
|
||||
|
||||
With the previous versions of tar it was dangerous to create
|
||||
incremental dumps with --one-file-system option, since they
|
||||
would recursively remove mount points when restoring from the
|
||||
back up. This change fixes the bug.
|
||||
|
||||
* Renamed --strip-path to --strip-components for consistency with
|
||||
the GNU convention.
|
||||
|
||||
* Skipping archive members is sped up if the archive media supports
|
||||
seeks.
|
||||
|
||||
* Restore script starts restoring only if it is given --all (-a) option,
|
||||
or some patterns. This is to prevent accidental restores.
|
||||
|
||||
* `tar --verify' prints a warning if during archive creation some of
|
||||
the file names had their prefixes stripped off.
|
||||
|
||||
* New option --exclude-caches instructs tar to exclude cache directories
|
||||
automatically on archive creation. Cache directories are those
|
||||
containing a standardized tag file, as specified at:
|
||||
|
||||
http://www.brynosaurus.com/cachedir/spec.html
|
||||
|
||||
* New configure option --with-rmt allows to specify full path name to
|
||||
the `rmt' utility. This supercedes DEFAULT_RMT_COMMAND variable
|
||||
introduced in version 1.14
|
||||
|
||||
* New configure variable DEFAULT_RMT_DIR allows to specify the directory
|
||||
where to install `rmt' utility. This is necessary since modifying
|
||||
--libexecdir as was suggested for version 1.14 produced a side effect: it
|
||||
also modified installation prefix for backup scripts (if
|
||||
--enable-backup-scripts was given).
|
||||
|
||||
* Bugfixes:
|
||||
** Fixed flow in recognizing files to be included in incremental dumps.
|
||||
** Correctly recognize sparse archive members when used with -T option.
|
||||
** GNU multivolume headers cannot store filenames longer than 100 characters.
|
||||
Do not allow multivolume archives to begin with such filenames.
|
||||
** If a member with link count > 2 was stored in the archive twice,
|
||||
previous versions of tar were not able to extract it, since they
|
||||
were trying to link the file to itself, which always failed and
|
||||
lead to removing the already extracted copy. Preserve the first
|
||||
extracted copy in such cases.
|
||||
** Restore script was passing improper argument to tar --listed option (which
|
||||
didn't affect the functionality, but was logically incorrect).
|
||||
** Fixed verification of created archives.
|
||||
** Fixed unquoting of file names containing backslash escapes (previous
|
||||
versions failed to recognize \a and \v).
|
||||
** When attempting to delete a non-existing member from the archive, previous
|
||||
versions of tar used to overwrite last archive block with zeroes.
|
||||
|
||||
|
||||
version 1.14 - Sergey Poznyakoff, 2004-05-11
|
||||
|
||||
* Added support for POSIX.1-2001 and ustar archive formats.
|
||||
* New option --format allows to select the output archive format
|
||||
@@ -45,8 +106,26 @@ version 1.13.93
|
||||
-o option.
|
||||
|
||||
* --incremental and --listed-incremental options work correctly on
|
||||
individual files, as well as on directories.
|
||||
|
||||
individual files, as well as on directories.
|
||||
|
||||
* New scripts: backup (replaces old level-0 and level-1) and restore.
|
||||
The scripts are compiled and installed if --enable-backup-scripts
|
||||
option is given to configure.
|
||||
|
||||
* By default tar searches "rmt" utility in "$prefix/libexec/rmt",
|
||||
which is consistent with the location where the version of "rmt"
|
||||
included in the package is installed. Previous versions of tar
|
||||
used "/etc/rmt". To install "rmt" to its traditional location,
|
||||
run configure with option --libexecdir=/etc. Otherwise, if you
|
||||
already have rmt installed and wish to use it, instead of the
|
||||
shipped in version, set the variable DEFAULT_RMT_COMMAND to
|
||||
the full path name of the utility, e.g. ./configure
|
||||
DEFAULT_RMT_COMMAND=/etc/rmt.
|
||||
|
||||
Notice also that the full path name of the "rmt" utility to
|
||||
use can be set at runtime, by giving option --rmt-command to
|
||||
tar.
|
||||
|
||||
* Removed obsolete command line options:
|
||||
** --absolute-paths superseded by --absolute-names
|
||||
** --block-compress is not needed any longer
|
||||
@@ -59,32 +138,38 @@ individual files, as well as on directories.
|
||||
* New message translations fi (Finnish), gl (Galician), hr (Croatian),
|
||||
hu (Hungarian), ms (Malaysian), nb (Norwegian), ro (Romanian), sk
|
||||
(Slovak), zh_CN (Chinese simplified), zh_TW (Chinese traditional).
|
||||
The code 'no' for Norwegian has been withdrawn; use 'nb' instead.
|
||||
The code 'no' for Norwegian (Bokm<6B>l) has been withdrawn; use 'nb' instead.
|
||||
|
||||
* Bug fixes.
|
||||
|
||||
|
||||
version 1.13.25 - Paul Eggert, 2001-09-26
|
||||
|
||||
* Bug fixes.
|
||||
|
||||
|
||||
version 1.13.24 - Paul Eggert, 2001-09-22
|
||||
|
||||
* New option --overwrite-dir.
|
||||
* Fixes for buffer overrun, porting, and copyright notice problems.
|
||||
* The message translations for Korean are available again.
|
||||
|
||||
|
||||
version 1.13.23 - Paul Eggert, 2001-09-13
|
||||
|
||||
* Bug, porting, and copyright notice fixes.
|
||||
|
||||
|
||||
version 1.13.22 - Paul Eggert, 2001-08-29
|
||||
|
||||
* Bug fixes.
|
||||
|
||||
|
||||
version 1.13.21 - Paul Eggert, 2001-08-28
|
||||
|
||||
* Porting and copyright notice fixes.
|
||||
|
||||
|
||||
version 1.13.20 - Paul Eggert, 2001-08-27
|
||||
|
||||
* Some bugs were fixed:
|
||||
@@ -111,6 +196,7 @@ version 1.13.20 - Paul Eggert, 2001-08-27
|
||||
The translation for Korean has been withdrawn due to encoding errors.
|
||||
It will be reissued once those are fixed.
|
||||
|
||||
|
||||
version 1.13.19 - Paul Eggert, 2001-01-13
|
||||
|
||||
* The -I option has been withdrawn, as it was buggy and confusing.
|
||||
@@ -119,6 +205,7 @@ version 1.13.19 - Paul Eggert, 2001-01-13
|
||||
* With an option like -N DATE, if DATE starts with "/" or ".", it is taken
|
||||
to be a file name; the last-modified time of that file is used as the date.
|
||||
|
||||
|
||||
version 1.13.18 - Paul Eggert, 2000-10-29
|
||||
|
||||
* Some security problems have been fixed. `tar -x' now modifies only
|
||||
@@ -149,11 +236,13 @@ version 1.13.18 - Paul Eggert, 2000-10-29
|
||||
|
||||
* `tar --delete -f -' now works again.
|
||||
|
||||
|
||||
version 1.13.17 - Paul Eggert, 2000-01-07.
|
||||
|
||||
* `tar --delete -f -' is no longer allowed; it was too buggy.
|
||||
* Diagnostic messages have been made more regular and consistent.
|
||||
|
||||
|
||||
version 1.13.16 - Paul Eggert, 1999-12-13.
|
||||
|
||||
* By default, tar now refuses to overwrite an existing file when
|
||||
@@ -197,17 +286,20 @@ version 1.13.16 - Paul Eggert, 1999-12-13.
|
||||
* tar now ignores socket files when creating an archive.
|
||||
Previously tar archived sockets as fifos, which caused problems.
|
||||
|
||||
|
||||
version 1.13.15 - Paul Eggert, 1999-12-03.
|
||||
|
||||
* If a file's ctime changes when being archived, report an error.
|
||||
Previously tar looked at mtime, which missed some errors.
|
||||
|
||||
|
||||
version 1.13.14 - Paul Eggert, 1999-11-07.
|
||||
|
||||
* New translations ja, pt_BR.
|
||||
* New options --help and --version for rmt.
|
||||
* Ignore Solaris door files when creating an archive.
|
||||
|
||||
|
||||
version 1.13.13 - Paul Eggert, 1999-10-11.
|
||||
|
||||
* Invalid headers in tar files now elicit errors, not just warnings.
|
||||
@@ -215,6 +307,7 @@ version 1.13.13 - Paul Eggert, 1999-10-11.
|
||||
* If you specify an invalid date, `tar' now substitutes (time_t) -1.
|
||||
* `configure --with-dmalloc' is no longer available.
|
||||
|
||||
|
||||
version 1.13.12 - Paul Eggert, 1999-09-24.
|
||||
|
||||
* `tar' now supports hard links to symbolic links.
|
||||
@@ -245,7 +338,7 @@ version 1.13.12 - Paul Eggert, 1999-09-24.
|
||||
|
||||
* Some diagnostics have been reworded for consistency.
|
||||
|
||||
|
||||
|
||||
version 1.13.11 - Paul Eggert, 1999-08-23.
|
||||
|
||||
* The short name of the --bzip option has been changed to -I,
|
||||
@@ -265,14 +358,14 @@ version 1.13.11 - Paul Eggert, 1999-08-23.
|
||||
numeric UTC offsets like `-0500' instead of abbreviations like
|
||||
`EST', as abbreviations are not standardized and are ambiguous.
|
||||
|
||||
|
||||
|
||||
version 1.13.10 - Paul Eggert, 1999-08-20.
|
||||
|
||||
* `tar' now uses signed base-64 when outputting header values that are
|
||||
out of the range of the standard unsigned base-8 format. [This
|
||||
change was superseded in 1.13.12, described above.]
|
||||
|
||||
|
||||
|
||||
version 1.13.9 - Paul Eggert, 1999-08-18.
|
||||
|
||||
* `tar' now writes two zero blocks at end-of-archive instead of just one.
|
||||
@@ -284,14 +377,14 @@ version 1.13.9 - Paul Eggert, 1999-08-18.
|
||||
* `tar' now reads buggy tar files that have a null byte at the start of a
|
||||
numeric header field.
|
||||
|
||||
|
||||
|
||||
version 1.13.8 - Paul Eggert, 1999-08-16.
|
||||
|
||||
* For compatibility with traditional `tar', intermediate directories
|
||||
created automatically by root are no longer given the uid and gid of
|
||||
the original file or directory.
|
||||
|
||||
|
||||
|
||||
version 1.13.7 - Paul Eggert, 1999-08-14.
|
||||
|
||||
* --listed-incremental and --newer are now incompatible options.
|
||||
@@ -301,7 +394,7 @@ version 1.13.7 - Paul Eggert, 1999-08-14.
|
||||
|
||||
* --diff without --absolute-names no longer falls back on absolute names.
|
||||
|
||||
|
||||
|
||||
version 1.13.6 - Paul Eggert, 1999-08-11.
|
||||
|
||||
* An --exclude pattern containing / now excludes a file only if it matches an
|
||||
@@ -328,30 +421,30 @@ version 1.13.6 - Paul Eggert, 1999-08-11.
|
||||
|
||||
* New option -y or --bzip2 for bzip2 compression, by popular request.
|
||||
|
||||
|
||||
|
||||
version 1.13.5 - Paul Eggert, 1999-07-20.
|
||||
|
||||
* Do the delayed updates of file metadata even after a fatal error.
|
||||
|
||||
|
||||
|
||||
version 1.13.4 - Paul Eggert, 1999-07-20.
|
||||
|
||||
* Do not chmod unless we are root or the -p option was given;
|
||||
this matches historical practice.
|
||||
|
||||
|
||||
|
||||
version 1.13.3 - Paul Eggert, 1999-07-16.
|
||||
|
||||
* A path name is excluded if any of its file name components matches an
|
||||
excluded pattern, even if the path name was specified on the command line.
|
||||
Also see 1.13.6 for later changes in this area.
|
||||
|
||||
|
||||
|
||||
version 1.13.2 - Paul Eggert, 1999-07-14.
|
||||
|
||||
* Bug reporting address changed to <bug-tar@gnu.org>.
|
||||
|
||||
|
||||
|
||||
version 1.13.1 - Paul Eggert, 1999-07-12.
|
||||
|
||||
* Bug fixes only.
|
||||
|
||||
128
PORTS
128
PORTS
@@ -1,48 +1,60 @@
|
||||
* Ports of GNU tar and other micro-tars -*- outline -*-
|
||||
Ports of GNU tar and other tars
|
||||
See the end of file for copying conditions.
|
||||
|
||||
Please write tar-bugs@gnu.ai.mit.edu if you are aware of various ports
|
||||
of GNU tar to non-Unix systems not listed here, or for corrections.
|
||||
* Introduction
|
||||
|
||||
Most entries in this file are out of date, unfortunately. Such
|
||||
entries are marked with an `X'. Run grep '^\*\*[^X]' PORTS to
|
||||
extract valid entries.
|
||||
|
||||
Please write bug-tar@gnu.org if you are aware of various ports of GNU tar
|
||||
to non-GNU and non-Unix systems not listed here, or for corrections.
|
||||
Please provide the goal system, a complete and stable URL, the maintainer
|
||||
name and address, the tar version used as a base, and your comments.
|
||||
|
||||
.* Amiga
|
||||
* GNU/Linux and Unix
|
||||
|
||||
. + ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/GNUtar-1.11.8.lha
|
||||
** Star is a tape archiver similar to tar.
|
||||
<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/star.html>
|
||||
|
||||
* Amiga
|
||||
|
||||
**X ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/GNUtar-1.11.8.lha
|
||||
maintained by Enrico Forestieri <enrico@com.unipr.it>
|
||||
Based on tar 1.11.8.
|
||||
|
||||
. + ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
|
||||
**X ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
|
||||
maintained by the ADE group <fnf@fishpond.ninemoons.com>
|
||||
Based on tar 1.11.8, needs ixemul.library.
|
||||
|
||||
. + ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/gnutar.lha
|
||||
**X ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/gnutar.lha
|
||||
maintained by <mscheler@wuarchive.wustl.edu>
|
||||
|
||||
.* DEC alpha (NT)
|
||||
* DEC alpha (NT)
|
||||
|
||||
. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
**X ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
maintained by Drew Bliss & Geoff Voelker
|
||||
|
||||
.* DEC VAX (VMS)
|
||||
* DEC VAX (VMS)
|
||||
|
||||
. + http://www.lp.se/free/vmstar/
|
||||
**X http://www.lp.se/free/vmstar/
|
||||
maintained by Richard Levitte <levitte@lp.se>
|
||||
This is not GNU tar, but a separate implementation.
|
||||
|
||||
. + maintained by William Bader <william@nscs.fast.net>
|
||||
** maintained by William Bader <william@nscs.fast.net>
|
||||
For V4.7. Based on an old PDtar. Requires compatible shared libraries
|
||||
to run V5 or V6 executables.
|
||||
|
||||
.* IBM/PC (DV/X)
|
||||
* IBM/PC (DV/X)
|
||||
|
||||
. + ftp://qdeck.com/ (?)
|
||||
**X ftp://qdeck.com/ (?)
|
||||
maintained by David Ronis <ronis@gibbs.chem.mcgill.ca>
|
||||
For Desqview/X. Everything works besides compression. Copy of hacked
|
||||
sources available, some of DV/X's programmer's library also needed.
|
||||
|
||||
.* IBM/PC (MSDOS)
|
||||
* IBM/PC (MSDOS)
|
||||
|
||||
. + http://www.simtel.net/simtel.net/
|
||||
**X http://www.simtel.net/simtel.net/
|
||||
http://www.leo.org/pub/comp/platforms/pc/gnuish (Germany)
|
||||
ftp://ftp.simtel.net/simtelnet/gnu
|
||||
ftp://ftp.leo.org/pub/comp/platforms/pc/gnuish
|
||||
@@ -50,82 +62,112 @@
|
||||
You get many GNU tools, not only `tar'. The GNUish project is described
|
||||
in `gnuish_t.htm'.
|
||||
|
||||
. + The DJGPP development tools also include some `tar' utilities.
|
||||
** The DJGPP development tools also include some `tar' utilities.
|
||||
|
||||
. + ftp://ftp.mcs.com/mcsnet.users/les/dos-gnutar/
|
||||
**X ftp://ftp.mcs.com/mcsnet.users/les/dos-gnutar/
|
||||
maintained by Leslie Mikesell <les@mcs.net>
|
||||
Based on tar 1.11.2. Support for SCSI (via ASPI) and network (rsh over
|
||||
packet driver). No support for win95 long file names.
|
||||
|
||||
. + ftp://ftp.wu-wien.ac.at:pub/src/PCmisc/aspi-tar/*
|
||||
**X ftp://ftp.wu-wien.ac.at/pub/src/PCmisc/aspi-tar/*
|
||||
maintained by Christoph Splittgerber <chris@orion.sdata.de>
|
||||
Based on tar 1.10. Support for SCSI (via ASPI).
|
||||
|
||||
. + ftp://wuarchive (?)
|
||||
**X ftp://wuarchive (?)
|
||||
Several DOS version based on PDtar. John Gilmore <gnu@toad.com> says
|
||||
he has copies of several vintages saved.
|
||||
|
||||
. + ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.exe
|
||||
**X ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.exe
|
||||
ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.taz
|
||||
ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.zip
|
||||
|
||||
. + ftp://ftp.cdrom.com/.4/os2/archiver/tar.zip
|
||||
**X ftp://ftp.cdrom.com/.4/os2/archiver/tar.zip
|
||||
Based on PDtar.
|
||||
|
||||
. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
**X ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
maintained by Drew Bliss & Geoff Voelker
|
||||
GNU tar for NT (intel and Alpha platforms).
|
||||
|
||||
. + ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
|
||||
** ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
|
||||
maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
|
||||
The `untgz' program is a fast .tar or .tar.gz (.tgz) extractor.
|
||||
|
||||
. + http://people.darmstadt.netsurf.de/tst/tar.htm
|
||||
**X http://people.darmstadt.netsurf.de/tst/tar.htm
|
||||
maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
|
||||
This is not a `tar' port, but an index of them.
|
||||
|
||||
.* IBM/PC (OS/2)
|
||||
* IBM/PC (OS/2)
|
||||
|
||||
. + http://www.leo.org/pub/comp/os/os2/leo/gnu/archiver/gtar254.zip
|
||||
**X http://www.leo.org/pub/comp/os/os2/leo/gnu/archiver/gtar254.zip
|
||||
http://www.leo.org/pub/comp/os/os2/leo/gnu/archiver/gtak254.zip
|
||||
maintained by Andreas Kaiser <Andreas.Kaiser@stuttgart.netsurf.de>
|
||||
Version 2.54. Based on tar 1.10. The second archive contains SCSI
|
||||
drivers (DAT streamers notably) and rmt-type programs.
|
||||
|
||||
. + ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
|
||||
maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
|
||||
The `untgz' program is a fast .tar or .tar.gz (.tgz) extractor.
|
||||
* IBM/PC (Win32: Windows 95, NT 3.5 or NT 4.0)
|
||||
|
||||
.* IBM/PC (Win32: Windows 95, NT 3.5 or NT 4.0)
|
||||
|
||||
. + ftp://ftp.cygnus.com:~ftp/pub/sac/win32/usersrc/*
|
||||
**X ftp://ftp.cygnus.com:~ftp/pub/sac/win32/usersrc/*
|
||||
maintained by Cygnus
|
||||
GNU-Win32 B17.1 distribution. Download all files, `cat' them together,
|
||||
and `untar' the result. You get many GNU tools, not only `tar'.
|
||||
Based on tar 1.11.2.
|
||||
|
||||
. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
**X ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
maintained by Drew Bliss & Geoff Voelker
|
||||
GNU tar for NT (intel and Alpha platforms).
|
||||
|
||||
. + ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
|
||||
** ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
|
||||
maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
|
||||
The `untgz' program is a fast .tar or .tar.gz (.tgz) extractor.
|
||||
|
||||
.* IBM/PC (Windows 3.1)
|
||||
* IBM/PC (Windows 3.1)
|
||||
|
||||
. + ftp://ftp.mcs.com/mcsnet.users/les/win-gnutar/
|
||||
**X ftp://ftp.mcs.com/mcsnet.users/les/win-gnutar/
|
||||
maintained by Leslie Mikesell <les@mcs.net>
|
||||
Support for network (rsh over winsock). No support for win95 long
|
||||
file names.
|
||||
|
||||
. + ftp://ftp.gamesdomain.ru/.1/os/windows/programr/tar.zip
|
||||
**X ftp://ftp.gamesdomain.ru/.1/os/windows/programr/tar.zip
|
||||
Based on GNU tar 1.11.2.
|
||||
|
||||
.* Macintosh
|
||||
* Macintosh
|
||||
|
||||
. + There is a tar in Stuffit Expander which is available many places and
|
||||
comes with MacOS. It creates some spurious files but works on average.
|
||||
** Paulo Abreu (paulotex at yahoo dot com) did a
|
||||
limited port of GNU tar to Darwin, with support for resource forks
|
||||
and finder info, but this no longer seems to be available.
|
||||
|
||||
. + There is an excellent GNU tar bundled in Tenon MachTen, but it does not
|
||||
seem to be available separately.
|
||||
** There is a tar in Stuffit Expander which is available many places and
|
||||
comes with MacOS. It creates some spurious files but works on average.
|
||||
|
||||
** There is an excellent GNU tar bundled in Tenon MachTen, but it does not
|
||||
seem to be available separately.
|
||||
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright (C) 1999, 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
GNU tar is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 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; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
Local Variables:
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
version-control: never
|
||||
End:
|
||||
|
||||
37
README
37
README
@@ -46,6 +46,36 @@ in the environment before configuring (the behavior of `-[0-7]' or
|
||||
`-[0-7]lmh' options in `tar' are then derived automatically). Similarly,
|
||||
`DEFAULT_BLOCKING' can be preset to something else than 20.
|
||||
|
||||
** Selecting full pathname of the "rmt" binary.
|
||||
|
||||
Previous versions of tar always looked for "rmt" binary in the
|
||||
directory "/etc/rmt". However, the "rmt" program included
|
||||
in the distribution was installed under "$prefix/libexec/rmt".
|
||||
To fix this discrepancy, tar now looks for "$prefix/libexec/rmt".
|
||||
If you do not want this behavior, specify full path name of
|
||||
"rmt" binary using DEFAULT_RMT_DIR variable, e.g.:
|
||||
|
||||
./configure DEFAULT_RMT_DIR=/etc
|
||||
|
||||
If you already have a copy of "rmt" installed and wish to use it
|
||||
instead of the version supplied with the distribution, use --with-rmt
|
||||
option:
|
||||
|
||||
./configure --with-rmt=/etc/rmt
|
||||
|
||||
This will also disable building the included version of rmt.
|
||||
|
||||
** Installing backup scripts.
|
||||
|
||||
This version of tar is shipped with the shell scripts for producing
|
||||
incremental backups (dumps) and restoring filesystems from them.
|
||||
The name of the backup script is "backup". The name of the
|
||||
restore script is "restore". They are installed in "$prefix/sbin"
|
||||
directory.
|
||||
|
||||
Use option --enable-backup-scripts to compile and install these
|
||||
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.
|
||||
@@ -169,9 +199,10 @@ and new `tar' features.
|
||||
|
||||
* What's next?
|
||||
|
||||
In the future we will try to release tar-1.14 as soon as possible and
|
||||
start merging with paxutils afterwards. We'll also try to rewrite
|
||||
some parts of the documentation after paxutils has been merged.
|
||||
GNU tar will be merged into GNU paxutils: a project containing
|
||||
several utilities related to creating and handling archives in
|
||||
various formats. The project will include tar, cpio and pax
|
||||
utilities.
|
||||
|
||||
* Bug reporting.
|
||||
|
||||
|
||||
22
README-alpha
22
README-alpha
@@ -24,25 +24,33 @@ Before building the package, run "bootstrap". It obtains various
|
||||
additional files from the CVS repository and the Translation Project
|
||||
site and prepares the source directory for building.
|
||||
|
||||
When run without arguments, bootstrap will try to obtain gnulib files
|
||||
from CVS repository on savannah using anonymous SSH access. Then, it
|
||||
will fetch the po files from tar page at Translation Project, and,
|
||||
finally, it will start autoconfiguration process. Simply running
|
||||
it without arguments should do in most cases. Several options
|
||||
allow to control the behavior of bootstrap:
|
||||
|
||||
When run without arguments, bootstrap will try to obtain gnulib and
|
||||
paxutils files from their corresponding CVS repositories on Savannah
|
||||
using anonymous SSH access. Then, it will fetch the po files from tar
|
||||
page at Translation Project, and, finally, it will start autoconfiguration
|
||||
process. Simply running it without arguments should do in most cases.
|
||||
Several options allow to control the behavior of bootstrap:
|
||||
|
||||
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
|
||||
sources reside. Use this if you already
|
||||
have gnulib sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
|
||||
--paxutils-srcdir=DIRNAME Specify the local directory where paxutils
|
||||
sources reside. Use this if you already
|
||||
have paxutils sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
|
||||
--cvs-auth=METHOD Set the CVS access method used for downloading
|
||||
gnulib files. METHOD is one of the keywords
|
||||
accepted by cvs -d option (see info cvs
|
||||
repository).
|
||||
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
|
||||
--no-po Do not download po files.
|
||||
|
||||
Notice also that when using CVS authentication method "ext", bootstrap
|
||||
|
||||
27
THANKS
27
THANKS
@@ -4,7 +4,7 @@ Public domain tar was written by John Gilmore, with contributions
|
||||
from Henry Spencer, Fred Fish, Ian Darwin, Geoff Collyer, Stan Barber,
|
||||
Guy Harris, Dave Brower, Richard Todd, Michael Rendell, Stu Heiss and
|
||||
Rich $alz. The FSF version, named GNU tar, was derived from PDTAR by
|
||||
Jay Fenlason and Joy Kendall, and was maintained in turn by François
|
||||
Jay Fenlason and Joy Kendall, and was maintained in turn by Fran<EFBFBD>§ois
|
||||
Pinard and Paul Eggert.
|
||||
|
||||
Many people further contributed to GNU tar by reporting problems,
|
||||
@@ -62,6 +62,7 @@ Bob Mende Pie mende@piecomputer.rutgers.edu
|
||||
Bradley A. Smith basmith@prometheus.chem.umn.edu
|
||||
Brendan Kehoe brendan@cygnus.com
|
||||
Brett Gaines gaines@saifr00.ateng.az.honeywell.com
|
||||
Bryan Ford baford@mit.edu
|
||||
Brian Perkins bperkins@netspace.org
|
||||
Brian R. Smith brian@cygnus.com
|
||||
Bruce Evans bde@runx.oz.au
|
||||
@@ -164,7 +165,7 @@ Ezra Peisach epeisach@mit.edu
|
||||
Fabio d'Alessi cars@civ.bio.unipd.it
|
||||
Frank Koenen koenfr@lidp.com
|
||||
Franz-Werner Gergen gergen@edvulx.mpi-stuttgart.mpg.de
|
||||
François Pinard pinard@iro.umontreal.ca
|
||||
Fran<EFBFBD>§ois Pinard pinard@iro.umontreal.ca
|
||||
Fritz Elfert fritz@fsun.triltsch.de
|
||||
George Chyu gschyu@ccgate.dp.beckman.com
|
||||
Gerben Wierda gerben@rna.indiv.nluug.nl
|
||||
@@ -178,12 +179,13 @@ Greg Chung gchung@caip.rutgers.edu
|
||||
Greg Hudson ghudson@mit.edu
|
||||
Greg Maples greg@clari.net
|
||||
Greg McGary gkm@cstone.net
|
||||
Göran Uddeborg gvran@uddeborg.pp.se
|
||||
G<EFBFBD>¶ran Uddeborg gvran@uddeborg.pp.se
|
||||
Hans Guerth 100664.3101@compuserve.com
|
||||
Harald König koenig@tat.physik.uni-tuebingen.de
|
||||
Harald K<EFBFBD>¶nig koenig@tat.physik.uni-tuebingen.de
|
||||
Harald Milz hm@seneca.ix.de
|
||||
Heiko Schinke mdqac@biochemtech.uni-halle.de
|
||||
Heiko Schlichting heiko@fu-berlin.de
|
||||
Helmut Waitzmann Helmut.Waitzmann@web.de
|
||||
Henrik Bakman hb@csd.uu.se
|
||||
Hernan Prieto Schmidt hernan@pea.usp.br
|
||||
Hiroyuki Bessho bsh@grotto.iijnet.or.jp
|
||||
@@ -237,6 +239,7 @@ John David Anglin dave@hiauly1.hia.nrc.ca
|
||||
John Gilmore gnu@toad.com
|
||||
John J. Szetela johns@angelo.amd.com
|
||||
John L. Chmielewski jlc@attmail.com
|
||||
John L. Males jlmales@yahoo.com
|
||||
John Oleynick juo@klinzhai.rutgers.edu
|
||||
John R. Vanderpool fish@daacdev1.stx.com
|
||||
John Rouillard rouilj@cs.umb.edu
|
||||
@@ -251,11 +254,12 @@ Joy Kendall jak8@world.std.com
|
||||
Judy Ricker jricker@gdstech.grumman.com
|
||||
Juha Sarlin juha@tds.kth.se
|
||||
Jurgen Botz jbotz@orixa.mtholyoke.edu
|
||||
Jürgen Lüters jlueters@t-online.de
|
||||
Jürgen Reiss reiss@psychologie.uni-wuerzburg.de
|
||||
J<EFBFBD>¼rgen L<EFBFBD>¼ters jlueters@t-online.de
|
||||
J<EFBFBD>¼rgen Reiss reiss@psychologie.uni-wuerzburg.de
|
||||
Jyh-Shyang Wang erik@vsp.ee.nctu.edu.tw
|
||||
Jörg Weule weule@cs.uni-duesseldorf.de
|
||||
Jörgen Hägg Jorgen.Hagg@axis.se
|
||||
J<EFBFBD>¶rg Weule weule@cs.uni-duesseldorf.de
|
||||
J<EFBFBD>¶rgen H<EFBFBD>¤gg Jorgen.Hagg@axis.se
|
||||
J<EFBFBD>¶rgen Weigert jw@suse.de
|
||||
Kai Petzke wpp@marie.physik.tu-berlin.de
|
||||
Kai Schlichting kai@computel.com
|
||||
Karl Berry karl@cs.umb.edu
|
||||
@@ -279,10 +283,12 @@ Larry Creech lcreech@lonestar.rcclub.org
|
||||
Larry Schwimmer rosebud@cyclone.stanford.edu
|
||||
Laurent Caillat-Vallet caillat@noe.lyon.cemagref.fr
|
||||
Laurent Sainte-Marthe smarthe@genethon.fr
|
||||
Leland Lucius llucius@tiny.net
|
||||
Les Mikesell les@mcs.com
|
||||
Loren J. Rittle rittle@comm.mot.com
|
||||
Loïc Prylli Loic.Prylli@lip.ens-lyon.fr
|
||||
Lo<EFBFBD>¯c Prylli Loic.Prylli@lip.ens-lyon.fr
|
||||
Luke Mewburn lukem@connect.com.au
|
||||
Mads Martin Joergensen mmj@suse.de
|
||||
Machael Stone mstone@cs.loyola.edu
|
||||
Manfred Weichel Manfred.Weichel@mch.sni.de
|
||||
Manuel Munier Manuel.Munier@loria.fr
|
||||
@@ -299,6 +305,7 @@ Markus Kuhn mskuhn@cip.informatik.uni-erlangen.de
|
||||
Martin Bellenberg sunsoft@ifm.uni-hamburg.de
|
||||
Martin Goik goik@HDM-Stuttgart.de
|
||||
Martin Mares mj@k332.feld.cvut.cz
|
||||
Martin Simmons ZYHYLCRMZPRP@spammotel.com
|
||||
Marty Leisner leisner@eso.mc.xerox.com
|
||||
Massimo Dal Zotto dz@cs.unitn.it
|
||||
Mats Lofkvist d87-mal@nada.kth.se
|
||||
@@ -443,7 +450,7 @@ Tarang Kumar Patel mombasa@ptolemy.arc.nasa.gov
|
||||
Ted Rule Ted_Rule@flextech.co.uk
|
||||
The King elvis@gnu.org
|
||||
Thomas Bushnell n/BSG thomas@gnu.org
|
||||
Thomas König Thomas.Koenig@ciw.uni-karlsruhe.de
|
||||
Thomas K<EFBFBD>¶nig Thomas.Koenig@ciw.uni-karlsruhe.de
|
||||
Thomas Krebs krebs@faps.uni-erlangen.de
|
||||
Thomas M. Browder Jr. browder@use1.eglin.af.mil
|
||||
Thomas Priesner priesner@flo.sh.bosch.de
|
||||
|
||||
23
TODO
23
TODO
@@ -2,8 +2,16 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Incorporate fixes from major distributions, e.g., Debian GNU/Linux.
|
||||
|
||||
* Add support for restoring file time stamps to sub-second resolution,
|
||||
if the file system supports this.
|
||||
|
||||
* Add support for restoring the attributes of symbolic links, for
|
||||
OSes like FreeBSD that have the lutimes and lchmod functions.
|
||||
|
||||
* --append should bail out if the two archives are of different types.
|
||||
|
||||
* Add support for GNU private keywords in POSIX 1003.1-2001 headers,
|
||||
so that the GNU extensions (--sparse, --incremental, --label and
|
||||
so that the GNU extensions (--incremental, --label and
|
||||
--multi-volume) may be used with POSIX archives.
|
||||
|
||||
* Add support for a 'pax' command that conforms to POSIX 1003.1-2001.
|
||||
@@ -16,9 +24,10 @@ so that the GNU extensions (--sparse, --incremental, --label and
|
||||
UNIX98 tar warns if all links cannot be resolved.
|
||||
(GNU tar --check-links option)
|
||||
|
||||
Perhaps we could announce a phase-in period where "l" changes in semantics.
|
||||
In the meanwhile we could make the "l" semantics to be determined by the
|
||||
value of POSIXLY_CORRECT variable.
|
||||
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.
|
||||
|
||||
@@ -30,7 +39,7 @@ so that the GNU extensions (--sparse, --incremental, --label and
|
||||
It would be useful to be able to use '--remove-files' with '--diff',
|
||||
to remove all files that compare successfully, when verifying a backup.
|
||||
|
||||
* Add tests for testing the added functonality.
|
||||
* Add tests for the new functonality.
|
||||
|
||||
* Consider this:
|
||||
|
||||
@@ -47,10 +56,10 @@ so that the GNU extensions (--sparse, --incremental, --label and
|
||||
|
||||
(http://mail.gnu.org/archive/html/bug-gnu-utils/2002-05/msg00022.html)
|
||||
|
||||
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
|
||||
191
bootstrap
191
bootstrap
@@ -2,7 +2,7 @@
|
||||
|
||||
# Bootstrap 'tar' from CVS.
|
||||
|
||||
# Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003, 2004 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,15 +19,25 @@
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Written by Paul Eggert.
|
||||
# Written by Paul Eggert and Sergey Poznyakoff.
|
||||
|
||||
# URL of our text domain page in Translation Project
|
||||
TP_URL="http://www2.iro.umontreal.ca/~gnutra/po/maint/tar/"
|
||||
|
||||
# Ensure file names are sorted consistently across platforms;
|
||||
# e.g., m4/ulonglong_gl.m4 should follow m4/ulonglong.m4.
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
usage: $0 [--gnulib-srcdir=DIR][--cvs-auth=AUTH-METHOD][--cvs-user=USERNAME][--no-po]
|
||||
usage: $0 [--gnulib-srcdir=DIR][--paxutils-srcdir=DIR][--cvs-auth=AUTH-METHOD][--cvs-user=USERNAME][--no-po]
|
||||
Options are:
|
||||
--paxutils-srcdir=DIRNAME Specify the local directory where paxutils
|
||||
sources reside. Use this if you already
|
||||
have paxutils sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
|
||||
sources reside. Use this if you already
|
||||
have gnulib sources on your machine, and
|
||||
@@ -40,15 +50,35 @@ usage() {
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
--no-po Do not download po files.
|
||||
|
||||
--update-po[=LANG] Update po file(s) and exit.
|
||||
|
||||
Running without arguments will suffice in most cases. It is equivalent
|
||||
to
|
||||
to
|
||||
|
||||
./bootstrap --cvs-auth=ext --cvs-user=anoncvs
|
||||
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
update_po() {
|
||||
if [ $# = 1 ]; then
|
||||
case $1 in
|
||||
*.po) POFILE=$1;;
|
||||
*) POFILE=${1}.po;;
|
||||
esac
|
||||
echo "$0: getting translation for $1..."
|
||||
wget -r -C 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 -C off $TP_URL &&
|
||||
rm -f index.html index.html.[0-9]*
|
||||
ls *.po | sed 's/\.po$//' >LINGUAS
|
||||
) || exit
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse options.
|
||||
|
||||
DOWNLOAD_PO=yes
|
||||
@@ -60,18 +90,33 @@ do
|
||||
exit;;
|
||||
--gnulib-srcdir=*)
|
||||
GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;;
|
||||
--paxutils-srcdir=*)
|
||||
PAXUTILS_SRCDIR=`expr "$option" : '--paxutils-srcdir=\(.*\)'`;;
|
||||
--cvs-auth=*)
|
||||
CVS_AUTH=`expr "$option" : '--cvs-auth=\(.*\)'`;;
|
||||
--cvs-user=*)
|
||||
CVS_USER=`expr "$option" : '--cvs-user=\(.*\)'`;;
|
||||
--no-po)
|
||||
DOWNLOAD_PO=no;;
|
||||
--update-po=*)
|
||||
DOWNLOAD_PO=`expr "$option" : '--update-po=\(.*\)'`;;
|
||||
--update-po)
|
||||
DOWNLOAD_PO=only;;
|
||||
*)
|
||||
echo >&2 "$0: $option: unknown option"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
case $DOWNLOAD_PO in
|
||||
only) update_po
|
||||
exit 0
|
||||
;;
|
||||
no|yes) ;;
|
||||
*) update_po $DOWNLOAD_PO
|
||||
exit 0
|
||||
esac
|
||||
|
||||
echo "$0: Bootstrapping CVS tar..."
|
||||
|
||||
build_cvs_prefix() {
|
||||
@@ -84,36 +129,44 @@ build_cvs_prefix() {
|
||||
CVS_RSH=ssh
|
||||
export CVS_RSH
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# checkout package
|
||||
checkout() {
|
||||
if [ ! -d $1 ]; then
|
||||
echo "$0: getting $1 files..."
|
||||
|
||||
trap exit 1 2 13 15
|
||||
trap 'rm -fr $1; exit 1' 0
|
||||
|
||||
case "${CVS_AUTH--}" in
|
||||
-) build_cvs_prefix ext anoncvs
|
||||
;;
|
||||
pserver) build_cvs_prefix $CVS_AUTH ${CVS_USER:-anoncvs}
|
||||
;;
|
||||
gserver|server)
|
||||
build_cvs_prefix $CVS_AUTH ${CVS_USER--}
|
||||
;;
|
||||
ext) build_cvs_prefix $CVS_AUTH ${CVS_USER--}
|
||||
;;
|
||||
*) echo "$0: Unknown CVS access method" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
if [ "${CVS_AUTH--}" = "pserver" ]; then
|
||||
cvs -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/$1 login || exit
|
||||
fi
|
||||
cvs -q -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/$1 co $1 || exit
|
||||
|
||||
trap 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Get gnulib files.
|
||||
|
||||
case ${GNULIB_SRCDIR--} in
|
||||
-)
|
||||
if [ ! -d gnulib ]; then
|
||||
echo "$0: getting gnulib files..."
|
||||
|
||||
trap exit 1 2 13 15
|
||||
trap 'rm -fr gnulib; exit 1' 0
|
||||
|
||||
case "${CVS_AUTH--}" in
|
||||
-) build_cvs_prefix ext anoncvs;;
|
||||
pserver) build_cvs_prefix $CVS_AUTH ${CVS_USER:-anoncvs};;
|
||||
gserver|server)
|
||||
build_cvs_prefix $CVS_AUTH ${CVS_USER--};;
|
||||
ext) build_cvs_prefix $CVS_AUTH ${CVS_USER--};;
|
||||
*) echo "$0: Unknown CVS access method" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
if [ "${CVS_AUTH--}" = "pserver" ]; then
|
||||
cvs -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/gnulib login || exit
|
||||
fi
|
||||
cvs -q -d ${CVS_PREFIX}subversions.gnu.org:/cvsroot/gnulib co gnulib || exit
|
||||
|
||||
trap 0
|
||||
fi
|
||||
GNULIB_SRCDIR=gnulib
|
||||
-) checkout gnulib
|
||||
GNULIB_SRCDIR=gnulib
|
||||
esac
|
||||
|
||||
<$GNULIB_SRCDIR/gnulib-tool || exit
|
||||
@@ -121,6 +174,7 @@ esac
|
||||
gnulib_modules='
|
||||
alloca
|
||||
argmatch
|
||||
argp
|
||||
backupfile
|
||||
dirname
|
||||
error
|
||||
@@ -132,10 +186,13 @@ full-write
|
||||
getdate
|
||||
getline
|
||||
getopt
|
||||
getpagesize
|
||||
gettext
|
||||
gettime
|
||||
hash
|
||||
human
|
||||
lchown
|
||||
localcharset
|
||||
memset
|
||||
modechange
|
||||
obstack
|
||||
@@ -149,9 +206,11 @@ stdbool
|
||||
stpcpy
|
||||
strtol
|
||||
strtoul
|
||||
timespec
|
||||
unlocked-io
|
||||
utime
|
||||
xalloc
|
||||
xalloc-die
|
||||
xgetcwd
|
||||
xstrtoumax
|
||||
'
|
||||
@@ -159,11 +218,13 @@ xstrtoumax
|
||||
previous_gnulib_modules=
|
||||
while [ "$gnulib_modules" != "$previous_gnulib_modules" ]; do
|
||||
previous_gnulib_modules=$gnulib_modules
|
||||
# In gnulib `alloca-opt' duplicates `alloca', so make sure not
|
||||
# to use it.
|
||||
gnulib_modules=`
|
||||
(echo "$gnulib_modules"
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-dependencies $gnulib_module
|
||||
done) | sort -u
|
||||
done) | sed 's/alloca-opt/alloca/' | sort -u
|
||||
`
|
||||
done
|
||||
|
||||
@@ -181,14 +242,17 @@ for gnulib_file in $gnulib_files; do
|
||||
|
||||
case $gnulib_file in
|
||||
m4/codeset.m4) continue;;
|
||||
m4/glibc21.m4) continue;;
|
||||
m4/intdiv0.m4) continue;;
|
||||
m4/inttypes_h.m4) continue;;
|
||||
m4/inttypes.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 &&
|
||||
@@ -196,16 +260,59 @@ for gnulib_file in $gnulib_files; do
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
|
||||
done
|
||||
|
||||
echo "$0: Creating m4/gnulib.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([tar_GNULIB],["
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-autoconf-snippet $gnulib_module
|
||||
done | sed '/AM_GNU_GETTEXT/d'
|
||||
echo "])") > ./m4/gnulib.m4
|
||||
|
||||
echo "$0: Creating lib/Makefile.am"
|
||||
(cat lib/Makefile.tmpl
|
||||
|
||||
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
|
||||
|
||||
# Get paxutils files
|
||||
case ${PAXUTILS_SRCDIR--} in
|
||||
-) checkout paxutils
|
||||
PAXUTILS_SRCDIR=paxutils
|
||||
esac
|
||||
|
||||
# copy_files srcdir dstdir
|
||||
copy_files() {
|
||||
for file in `cat $1/DISTFILES`
|
||||
do
|
||||
case $file in
|
||||
"#*") continue;;
|
||||
esac
|
||||
echo "$0: Copying file $1/$file"
|
||||
cp -p $1/$file $2/`expr $file : '.*/\(.*\)'`
|
||||
done
|
||||
}
|
||||
|
||||
copy_files ${PAXUTILS_SRCDIR}/m4 m4
|
||||
|
||||
if [ -d rmt ]; then
|
||||
:
|
||||
else
|
||||
mkdir rmt
|
||||
fi
|
||||
|
||||
copy_files ${PAXUTILS_SRCDIR}/rmt rmt
|
||||
|
||||
copy_files ${PAXUTILS_SRCDIR}/lib lib
|
||||
|
||||
copy_files ${PAXUTILS_SRCDIR}/tests tests
|
||||
|
||||
# Get translations.
|
||||
|
||||
if test "$DOWNLOAD_PO" = "yes"; then
|
||||
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 -C off $TP_URL &&
|
||||
ls *.po | sed 's/\.po$//' >LINGUAS
|
||||
) || exit
|
||||
update_po
|
||||
fi
|
||||
|
||||
# Reconfigure, getting other files.
|
||||
|
||||
137
configure.ac
137
configure.ac
@@ -18,7 +18,7 @@
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
AC_INIT([GNU tar], [1.13.93], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.15], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([config])
|
||||
AC_CONFIG_HEADERS([config.h:config.hin])
|
||||
@@ -29,40 +29,26 @@ gl_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
AC_EXEEXT
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_YACC
|
||||
AC_SYS_LARGEFILE
|
||||
AC_ISC_POSIX
|
||||
AC_C_INLINE
|
||||
|
||||
AC_CHECK_HEADERS(fcntl.h linux/fd.h memory.h net/errno.h \
|
||||
sgtty.h string.h \
|
||||
sys/buf.h sys/device.h sys/gentape.h \
|
||||
sys/param.h sys/device.h sys/gentape.h \
|
||||
sys/inet.h sys/io/trioctl.h \
|
||||
sys/mtio.h sys/tprintf.h sys/tape.h \
|
||||
sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
|
||||
unistd.h)
|
||||
|
||||
AC_CHECK_HEADERS([sys/buf.h], [], [],
|
||||
[#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif])
|
||||
|
||||
AC_HEADER_SYS_WAIT
|
||||
AM_STDBOOL_H
|
||||
|
||||
if test $ac_cv_header_sys_mtio_h = yes; then
|
||||
AC_CACHE_CHECK(for remote tape header files, tar_cv_header_rmt,
|
||||
[AC_TRY_CPP([
|
||||
#if HAVE_SGTTY_H
|
||||
# include <sgtty.h>
|
||||
#endif
|
||||
#include <sys/socket.h>],
|
||||
tar_cv_header_rmt=yes, tar_cv_header_rmt=no)])
|
||||
test $tar_cv_header_rmt = yes && RMT='rmt$(EXEEXT)'
|
||||
AC_SUBST(RMT)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(which ioctl field to test for reversed bytes,
|
||||
tar_cv_header_mtio_check_field,
|
||||
[AC_EGREP_HEADER(mt_model, sys/mtio.h,
|
||||
tar_cv_header_mtio_check_field=mt_model,
|
||||
tar_cv_header_mtio_check_field=mt_type)])
|
||||
AC_DEFINE_UNQUOTED(MTIO_CHECK_FIELD, $tar_cv_header_mtio_check_field,
|
||||
[Define to mt_model (v.g., for DG/UX), else to mt_type.])
|
||||
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_MAJOR
|
||||
AC_HEADER_STAT
|
||||
@@ -95,61 +81,18 @@ 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
|
||||
|
||||
AM_FUNC_GETLINE
|
||||
|
||||
gl_BACKUPFILE
|
||||
gl_DIRNAME
|
||||
gl_ERROR
|
||||
gl_EXCLUDE
|
||||
gl_FILEBLOCKS
|
||||
gl_FUNC_ALLOCA
|
||||
gl_FUNC_FNMATCH_GNU
|
||||
gl_FUNC_MEMSET
|
||||
gl_FUNC_MKTIME
|
||||
gl_FUNC_RMDIR
|
||||
gl_FUNC_STRTOL
|
||||
gl_FUNC_STRTOUL
|
||||
gl_FUNC_STRTOIMAX
|
||||
gl_FUNC_STRTOUMAX
|
||||
gl_GETDATE
|
||||
gl_GETOPT
|
||||
gl_HASH
|
||||
gl_HUMAN
|
||||
gl_MODECHANGE
|
||||
gl_OBSTACK
|
||||
gl_PATHMAX
|
||||
gl_QUOTE
|
||||
gl_QUOTEARG
|
||||
gl_SAFE_READ
|
||||
gl_SAFE_WRITE
|
||||
gl_SAVE_CWD
|
||||
gl_SAVEDIR
|
||||
gl_STRCASE
|
||||
gl_TIME_R
|
||||
gl_XALLOC
|
||||
gl_XGETCWD
|
||||
gl_XSTRTOL
|
||||
gl_FUNC_STPCPY
|
||||
|
||||
jm_FUNC_FTRUNCATE
|
||||
jm_FUNC_GLIBC_UNLOCKED_IO
|
||||
jm_FUNC_CHOWN
|
||||
jm_FUNC_LCHOWN
|
||||
jm_FUNC_MALLOC
|
||||
jm_FUNC_REALLOC
|
||||
jm_FUNC_UTIME
|
||||
jm_XSTRTOUMAX
|
||||
|
||||
AC_CHECK_MEMBERS([struct stat.st_spare1, struct stat.st_atim.tv_nsec, struct stat.st_atimespec.tv_nsec, struct stat.st_atimensec], , ,
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>])
|
||||
|
||||
|
||||
# Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all*
|
||||
# programs in the package would end up linked with that potentially-shared
|
||||
# library, inducing unnecessary run-time overhead.
|
||||
@@ -169,7 +112,7 @@ LIBS=$tar_save_LIBS
|
||||
AC_CHECK_FUNCS(fsync lstat mkfifo readlink strerror symlink setlocale utimes)
|
||||
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
|
||||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||||
AC_CHECK_DECLS([valloc])
|
||||
AC_CHECK_DECLS([time],,, [#include <time.h>])
|
||||
|
||||
# Set LIB_SETSOCKOPT to -lnsl -lsocket if necessary.
|
||||
tar_save_LIBS=$LIBS
|
||||
@@ -216,6 +159,9 @@ fi
|
||||
|
||||
AC_MSG_CHECKING(for default archive format)
|
||||
|
||||
AC_ARG_VAR([DEFAULT_ARCHIVE_FORMAT],
|
||||
[Set the default archive format. Allowed values are: V7, OLDGNU, USTAR, POSIX, GNU. Default is GNU])
|
||||
|
||||
if test -z "$DEFAULT_ARCHIVE_FORMAT"; then
|
||||
DEFAULT_ARCHIVE_FORMAT="GNU"
|
||||
fi
|
||||
@@ -229,6 +175,8 @@ AC_MSG_RESULT($DEFAULT_ARCHIVE_FORMAT)
|
||||
|
||||
AC_MSG_CHECKING(for default archive)
|
||||
|
||||
AC_ARG_VAR([DEFAULT_ARCHIVE],
|
||||
[Set the name of the default archive (default: -)])
|
||||
if test -z "$DEFAULT_ARCHIVE"; then
|
||||
DEFAULT_ARCHIVE=-
|
||||
else
|
||||
@@ -262,24 +210,54 @@ AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE, "$DEFAULT_ARCHIVE",
|
||||
[Define to a string giving the full name of the default archive file.])
|
||||
AC_MSG_RESULT($DEFAULT_ARCHIVE)
|
||||
|
||||
AC_ARG_VAR([DEFAULT_BLOCKING],
|
||||
[Define default blocking factor (default: 20)])
|
||||
AC_MSG_CHECKING(for default blocking)
|
||||
DEFAULT_BLOCKING=${DEFAULT_BLOCKING-20}
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING,
|
||||
[Define to a number giving the default blocking size for archives.])
|
||||
AC_MSG_RESULT($DEFAULT_BLOCKING)
|
||||
|
||||
PU_RMT
|
||||
|
||||
# Iconv
|
||||
AM_ICONV
|
||||
AC_CHECK_HEADERS(iconv.h)
|
||||
AC_CHECK_TYPE(iconv_t,:,
|
||||
AC_DEFINE(iconv_t, int,
|
||||
[Conversion descriptor type]),
|
||||
[
|
||||
#ifdef HAVE_ICONV_H
|
||||
# include <iconv.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-ngettext])
|
||||
AM_GNU_GETTEXT_VERSION(0.12.1)
|
||||
|
||||
# Iconv
|
||||
AC_CHECK_HEADERS(iconv.h,
|
||||
[AC_CHECK_TYPE(iconv_t,:,
|
||||
AC_DEFINE(iconv_t, int,
|
||||
[Conversion descriptor type]),
|
||||
[#include <iconv.h>])])
|
||||
# Initialize the test suite.
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
AC_CONFIG_FILES([tests/Makefile tests/atlocal]) # FIXME: tests/preset?
|
||||
AM_MISSING_PROG([AUTOM4TE], [autom4te])
|
||||
|
||||
AC_CHECK_LIB(iconv, iconv)
|
||||
AC_SUBST(BACKUP_LIBEXEC_SCRIPTS)
|
||||
AC_SUBST(BACKUP_SBIN_SCRIPTS)
|
||||
AC_ARG_ENABLE(backup-scripts,
|
||||
AC_HELP_STRING([--enable-backup-scripts],
|
||||
[Create and install backup and restore scripts]),
|
||||
[case $enableval in
|
||||
yes) BACKUP_LIBEXEC_SCRIPTS='$(BACKUP_LIBEXEC_SCRIPTS_LIST)'
|
||||
BACKUP_SBIN_SCRIPTS='$(BACKUP_SBIN_SCRIPTS_LIST)'
|
||||
;;
|
||||
esac])
|
||||
|
||||
AC_SUBST(BACKUP_SED_COND)
|
||||
if date +%Y-%m-%d 2>/dev/null >&2; then
|
||||
BACKUP_SED_COND='/^\#ELSE_DATE_FORMAT_OK/,/^\#ENDIF_DATE_FORMAT_OK/d;/^\#IF_DATE_FORMAT_OK/d'
|
||||
else
|
||||
BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
|
||||
fi
|
||||
|
||||
|
||||
AC_OUTPUT([Makefile\
|
||||
@@ -287,6 +265,5 @@ AC_OUTPUT([Makefile\
|
||||
lib/Makefile\
|
||||
po/Makefile.in\
|
||||
scripts/Makefile\
|
||||
src/Makefile\
|
||||
tests/Makefile\
|
||||
tests/preset])
|
||||
rmt/Makefile\
|
||||
src/Makefile])
|
||||
|
||||
87
directory
Normal file
87
directory
Normal file
@@ -0,0 +1,87 @@
|
||||
%%comments:
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
Texts. A copy of the license is included in the file COPYING.
|
||||
|
||||
%%name: tar
|
||||
|
||||
%%short-description: Creates tar archives
|
||||
|
||||
%%full-description:
|
||||
GNU tar is an archiver that creates and handles file archives in various
|
||||
formats. You can use tar to create file archives, to extract files from
|
||||
previously created archives, store additional files, or update or list
|
||||
files which were already stored.
|
||||
|
||||
The program saves many files together into a single tape or disk
|
||||
archive, and can restore individual files from the archive. It
|
||||
includes multivolume support, the ability to archive sparse files,
|
||||
automatic archive compression/decompression, remote archives and
|
||||
special features that allow 'tar' to be used for incremental and full
|
||||
backups.
|
||||
|
||||
The supported archive formats are: V7 tar, GNU, ustar and POSIX (also
|
||||
known as pax interchange format). GNU tar is also able to read and
|
||||
extract 'star' archives.
|
||||
|
||||
Tar can direct its output to available devices, files, or other
|
||||
programs (using pipes); tar can even access remote devices or files
|
||||
(as archives).
|
||||
|
||||
%%category: system, backup
|
||||
|
||||
%%license: GPL
|
||||
|
||||
%%maintainer: Sergey Poznyakoff <gray@Mirddin.farlep.net>,
|
||||
Jeff Bailey <jbailey@nisa.net>,
|
||||
Paul Eggert <eggert@CS.UCLA.EDU>
|
||||
|
||||
%%updated: 20 Dec 2004
|
||||
|
||||
%%keywords: archive, backup, tar, pax
|
||||
|
||||
%%interface: Command line
|
||||
|
||||
%%programs: tar, rmt
|
||||
|
||||
%%GNU: yes
|
||||
|
||||
%%web-page: http://www.gnu.org/software/tar
|
||||
|
||||
%%doc: English user reference included
|
||||
|
||||
%%doc: English user manual in Texinfo, Dvi, Postscript, HTML, Plaintext is available from http://www.gnu.org/software/tar/manual/tar.html
|
||||
|
||||
%%developers:
|
||||
John Gilmore,
|
||||
Thomas Bushnell,
|
||||
Paul Eggert <eggert@twinsun.com>,
|
||||
Sergey Poznyakoff <gray@Mirddin.farlep.net>
|
||||
|
||||
%%contributors: Jay Fenlason,
|
||||
Joy Kendall,
|
||||
Francois Pinard <pinard@iro.umontreal.ca>
|
||||
|
||||
%%source-tarball: ftp://ftp.gnu.org/pub/gnu/tar/tar-1.15.tar.gz
|
||||
%%source-info: http://savannah.gnu.org/projects/tar
|
||||
|
||||
%%repository:
|
||||
:pserver:anoncvs@subversions.gnu.org:/cvsroot/tar login,
|
||||
:pserver:anoncvs@subversions.gnu.org:/cvsroot/tar co tar,
|
||||
http://savannah.gnu.org/cvs/?group=tar,
|
||||
http://savannah.gnu.org/cgi-bin/viewcvs/tar/tar,
|
||||
|
||||
%%source-language: C
|
||||
|
||||
%%related-programs: GNU cpio
|
||||
|
||||
%%version: 1.15 (stable) released on 20 Dec 2004
|
||||
|
||||
%%bug-list: bug-tar@gnu.org bug-tar@gnu.org http://mail.gnu.org/mailman/listinfo/bug-tar
|
||||
|
||||
%%entry-written-by: Sergey Poznyakoff <gray@gnu.org>
|
||||
|
||||
@@ -26,3 +26,9 @@ tar.ex
|
||||
tar.ats
|
||||
tar.exs
|
||||
tar.kws
|
||||
tmp-tar.*
|
||||
tmp2-tar.*
|
||||
html_mono
|
||||
html_node
|
||||
html_chapter
|
||||
*.stamp
|
||||
159
doc/Makefile.am
159
doc/Makefile.am
@@ -18,10 +18,10 @@
|
||||
## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
info_TEXINFOS = tar.texi
|
||||
tar_TEXINFOS = fdl.texi freemanuals.texi getdate.texi header.texi
|
||||
EXTRA_DIST = convtexi.pl
|
||||
|
||||
EXTRA_DIST = convtexi.pl fdl.texi freemanuals.texi getdate.texi header.texi
|
||||
|
||||
CLEANFILES = tmp-*
|
||||
CLEANFILES = tmp-* tmp2-* index.html
|
||||
|
||||
# The rendering level is anyone of PUBLISH, DISTRIB or PROOF.
|
||||
# Just call `make dvi RENDITION=PROOF' if you want PROOF rendition.
|
||||
@@ -31,7 +31,7 @@ $(srcdir)/tar.info: tar.texi fdl.texi freemanuals.texi getdate.texi \
|
||||
$(srcdir)/header.texi version.texi
|
||||
$(MAKEINFO) --no-split -D$(RENDITION) -I$(srcdir) tar.texi -o $@
|
||||
|
||||
tar.dvi: tar.texi getdate.texi $(srcdir)/header.texi version.texi
|
||||
tmp-tar.texi: tar.texi getdate.texi $(srcdir)/header.texi version.texi
|
||||
$(MAKEINFO) -D$(RENDITION) -Etmp-tar.tmp -otmp-tar.info \
|
||||
-I$(srcdir) tar.texi
|
||||
rm -f tmp-tar.sed tmp-tar.info*
|
||||
@@ -41,6 +41,8 @@ tar.dvi: tar.texi getdate.texi $(srcdir)/header.texi version.texi
|
||||
|| echo >>tmp-tar.sed '/^@smallbook/d'
|
||||
sed -f tmp-tar.sed tmp-tar.tmp > tmp-tar.texi
|
||||
rm -f tmp-tar.sed tmp-tar.tmp
|
||||
|
||||
tar.dvi: tmp-tar.texi
|
||||
TEXINPUTS=$(top_srcdir)/config:$$TEXINPUTS \
|
||||
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
|
||||
$(TEXI2DVI) tmp-tar.texi
|
||||
@@ -49,3 +51,152 @@ tar.dvi: tar.texi getdate.texi $(srcdir)/header.texi version.texi
|
||||
$(srcdir)/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' >$@
|
||||
|
||||
##
|
||||
PROJECT=$(PACKAGE_TARNAME)
|
||||
BASE_URL="http://www.gnu.org/software/$(PROJECT)/manual/"
|
||||
TEXI2HTML=${SHELL} `cd $(top_srcdir); pwd`/config/missing --run texi2html
|
||||
INFO=${SHELL} `cd $(top_srcdir); pwd`/config/missing --run info
|
||||
DVIPDF=${SHELL} `cd $(top_srcdir); pwd`/config/missing --run dvipdf
|
||||
|
||||
clean-local:
|
||||
rm -rf $(WEBDOC) $(WEB_HTML_STAMPS)
|
||||
|
||||
html: html_mono.stamp html_node.stamp html_chapter.stamp
|
||||
|
||||
tmp2-$(PROJECT).texi: Makefile tmp-$(PROJECT).texi
|
||||
echo '/@copying/,/@end copying/{H;x;s/@copying//;s/@end copying//;x;}' > tmp2.sed
|
||||
echo '/@insertcopying/{x;h;}' >> tmp2.sed
|
||||
echo 's/\(.\)@ifset/\1\' >> tmp2.sed
|
||||
echo '@ifset/' >> tmp2.sed
|
||||
sed -f tmp2.sed tmp-$(PROJECT).texi > tmp2-$(PROJECT).texi
|
||||
rm -f tmp2.sed
|
||||
|
||||
html_node.stamp: tmp2-$(PROJECT).texi
|
||||
texi2html="$(TEXI2HTML)";\
|
||||
if ! test -d html_node; then mkdir html_node; fi; \
|
||||
cd html_node; \
|
||||
$$texi2html -menu -split_node -prefix $(PROJECT) ../tmp2-$(PROJECT).texi; \
|
||||
cd ..; \
|
||||
touch html_node.stamp
|
||||
|
||||
html_chapter.stamp: tmp2-$(PROJECT).texi
|
||||
texi2html="$(TEXI2HTML)";\
|
||||
if ! test -d html_chapter; then mkdir html_chapter; fi; \
|
||||
cd html_chapter; \
|
||||
$$texi2html -menu -split_chapter -prefix $(PROJECT) ../tmp2-$(PROJECT).texi; \
|
||||
cd ..; \
|
||||
touch html_chapter.stamp
|
||||
|
||||
html_mono.stamp: tmp2-$(PROJECT).texi
|
||||
texi2html="$(TEXI2HTML)";\
|
||||
if ! test -d html_mono; then mkdir html_mono; fi; \
|
||||
cd html_mono; \
|
||||
$$texi2html -menu -monolithic -prefix $(PROJECT) ../tmp2-$(PROJECT).texi; \
|
||||
cd ..; \
|
||||
touch html_mono.stamp
|
||||
|
||||
ps: $(PROJECT).ps
|
||||
|
||||
$(PROJECT).ps: $(PROJECT).dvi
|
||||
$(DVIPS) -o$(PROJECT).ps $(PROJECT).dvi
|
||||
|
||||
# Override the default rule. The texinfo <= 4.5 is unable to cope with
|
||||
# tar docs.
|
||||
$(PROJECT).pdf: $(PROJECT).dvi
|
||||
$(DVIPDF) $(PROJECT).dvi
|
||||
|
||||
text: $(PROJECT).text
|
||||
|
||||
$(PROJECT).text: Makefile $(PROJECT).info
|
||||
$(INFO) --node=Top --subnodes --out $(PROJECT).text -f ./$(PROJECT).info
|
||||
|
||||
$(PROJECT).info.tar.gz: Makefile
|
||||
rm -f $(PROJECT).info.tar.gz
|
||||
tar cf $(PROJECT).info.tar $(PROJECT).info*
|
||||
gzip -f $(PROJECT).info.tar
|
||||
|
||||
$(PROJECT).dvi.gz: Makefile $(PROJECT).dvi
|
||||
gzip -c $(PROJECT).dvi > $(PROJECT).dvi.gz
|
||||
|
||||
$(PROJECT).ps.gz: Makefile $(PROJECT).ps
|
||||
gzip -c $(PROJECT).ps > $(PROJECT).ps.gz
|
||||
|
||||
$(PROJECT).pdf.gz: Makefile $(PROJECT).pdf
|
||||
gzip -c $(PROJECT).pdf > $(PROJECT).pdf.gz
|
||||
|
||||
$(PROJECT).texi.tar.gz: Makefile $(info_TEXINFOS) $(tar_TEXINFOS)
|
||||
tar cfz $(PROJECT).texi.tar.gz $(info_TEXINFOS) $(tar_TEXINFOS)
|
||||
|
||||
WEB_HTML=\
|
||||
html_mono\
|
||||
html_node\
|
||||
html_chapter
|
||||
|
||||
WEB_HTML_STAMPS=$(patsubst %,%.stamp,$(WEB_HTML))
|
||||
|
||||
WEB_BIN=\
|
||||
$(PROJECT).info.tar.gz\
|
||||
$(PROJECT).dvi.gz\
|
||||
$(PROJECT).pdf.gz\
|
||||
$(PROJECT).ps.gz\
|
||||
$(PROJECT).texi.tar.gz\
|
||||
$(PROJECT).text
|
||||
|
||||
WEBDOC=$(WEB_HTML) $(WEB_BIN)
|
||||
|
||||
webdocdir: $(WEB_HTML_STAMPS) $(WEB_BIN) index.html
|
||||
if ! test -d $(WEBDOCDIR); then mkdir $(WEBDOCDIR); fi; \
|
||||
here=`cd $(srcdir) && pwd`; \
|
||||
webdocdir=`cd $(WEBDOCDIR) && pwd`; \
|
||||
for file in $(WEB_HTML) index.html; do \
|
||||
if test -d $$here/$$file; then \
|
||||
cp -pr $$here/$$file $$webdocdir/$$file; \
|
||||
else \
|
||||
test -f $$webdocdir/$$file \
|
||||
|| ln $$here/$$file $$webdocdir/$$file 2> /dev/null \
|
||||
|| cp -p $$here/$$file $$webdocdir/$$file || :; \
|
||||
fi; \
|
||||
done; \
|
||||
if ! test -d $(WEBDOCDIR)/other; then mkdir $(WEBDOCDIR)/other; fi;\
|
||||
for file in $(WEB_BIN); do \
|
||||
if test -d $$here/$$file; then \
|
||||
cp -pr $$here/$$file $$webdocdir/other/$$file; \
|
||||
else \
|
||||
test -f $$webdocdir/other/$$file \
|
||||
|| ln $$here/$$file $$webdocdir/other/$$file 2> /dev/null \
|
||||
|| cp -p $$here/$$file $$webdocdir/other/$$file || :; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
index.html: index.html.in $(WEBDOC)
|
||||
@echo "s^%BASE_URL%^$(BASE_URL)^;" > .webdoc
|
||||
@echo "s/%DATE%/`date`/;" >> .webdoc
|
||||
@echo "s/%UPDATED%/`date +'%B, %d'`/;" >> .webdoc
|
||||
@echo "s/%PACKAGE_NAME%/$(PACKAGE_NAME)/" >> .webdoc
|
||||
@echo "s/%PACKAGE%/$(PACKAGE)/" >> .webdoc
|
||||
@echo "s/%VERSION%/$(VERSION)/" >> .webdoc
|
||||
@for file in `sed -n 's,.*"other/%PACKAGE%\(.*\)".*,$(PACKAGE)\1,pg;s,.*"\(.*\)%PACKAGE%\(.*\)".*,\1$(PACKAGE)\2,pg' index.html.in`; \
|
||||
do\
|
||||
ls -sk $$file; \
|
||||
done |\
|
||||
$(AWK) -vPACKAGE=$(PACKAGE) \
|
||||
'BEGIN { len = length(PACKAGE) } \
|
||||
{ gsub("\\.", "_", $$2); \
|
||||
if (match($$2,"/")) \
|
||||
$$2=substr($$2,RSTART+1); \
|
||||
print "s/%" toupper(substr($$2,len+2)) "_SIZE%/" $$1 "/;" }' >> .webdoc
|
||||
sed -f .webdoc index.html.in > index.html
|
||||
rm -f .webdoc
|
||||
|
||||
webdocname=$(PACKAGE)-$(VERSION)-doc
|
||||
WEBDOCDIR=$(webdocname)
|
||||
|
||||
webdoc:
|
||||
$(MAKE) RENDITION=PUBLISH WEBDOCDIR=$(top_builddir)/doc/$(webdocname) webdocdir
|
||||
cd $(top_builddir)/doc &&\
|
||||
tar cfz $(webdocname).tar.gz $(webdocname) &&\
|
||||
rm -r $(webdocname)
|
||||
|
||||
## End of webdoc
|
||||
|
||||
|
||||
432
doc/getdate.texi
432
doc/getdate.texi
@@ -1,432 +0,0 @@
|
||||
@node Date input formats
|
||||
@chapter Date input formats
|
||||
|
||||
@c Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free Software
|
||||
@c Foundation, Inc.
|
||||
|
||||
@c Permission is granted to copy, distribute and/or modify this document
|
||||
@c under the terms of the GNU Free Documentation License, Version 1.1
|
||||
@c or any later version published by the Free Software Foundation;
|
||||
@c with no Invariant Sections, with no
|
||||
@c Front-Cover Texts, and with no Back-Cover Texts.
|
||||
@c A copy of the license is included in the section entitled ``GNU
|
||||
@c Free Documentation License''.
|
||||
|
||||
@cindex date input formats
|
||||
@findex getdate
|
||||
|
||||
First, a quote:
|
||||
|
||||
@quotation
|
||||
Our units of temporal measurement, from seconds on up to months, are so
|
||||
complicated, asymmetrical and disjunctive so as to make coherent mental
|
||||
reckoning in time all but impossible. Indeed, had some tyrannical god
|
||||
contrived to enslave our minds to time, to make it all but impossible
|
||||
for us to escape subjection to sodden routines and unpleasant surprises,
|
||||
he could hardly have done better than handing down our present system.
|
||||
It is like a set of trapezoidal building blocks, with no vertical or
|
||||
horizontal surfaces, like a language in which the simplest thought
|
||||
demands ornate constructions, useless particles and lengthy
|
||||
circumlocutions. Unlike the more successful patterns of language and
|
||||
science, which enable us to face experience boldly or at least
|
||||
level-headedly, our system of temporal calculation silently and
|
||||
persistently encourages our terror of time.
|
||||
|
||||
@dots{} It is as though architects had to measure length in feet, width
|
||||
in meters and height in ells; as though basic instruction manuals
|
||||
demanded a knowledge of five different languages. It is no wonder then
|
||||
that we often look into our own immediate past or future, last Tuesday
|
||||
or a week from Sunday, with feelings of helpless confusion. @dots{}
|
||||
|
||||
--- Robert Grudin, @cite{Time and the Art of Living}.
|
||||
@end quotation
|
||||
|
||||
This section describes the textual date representations that @sc{gnu}
|
||||
programs accept. These are the strings you, as a user, can supply as
|
||||
arguments to the various programs. The C interface (via the
|
||||
@code{getdate} function) is not described here.
|
||||
|
||||
@cindex beginning of time, for @acronym{POSIX}
|
||||
@cindex epoch, for @acronym{POSIX}
|
||||
Although the date syntax here can represent any possible time since the
|
||||
year zero, computer integers often cannot represent such a wide range of
|
||||
time. On @acronym{POSIX} systems, the clock starts at 1970-01-01 00:00:00
|
||||
@sc{utc}: @acronym{POSIX} does not require support for times before the
|
||||
@acronym{POSIX} Epoch and times far in the future. Traditional Unix systems
|
||||
have 32-bit signed @code{time_t} and can represent times from 1901-12-13
|
||||
20:45:52 through 2038-01-19 03:14:07 @sc{utc}. Systems with 64-bit
|
||||
signed @code{time_t} can represent all the times in the known
|
||||
lifetime of the universe.
|
||||
|
||||
@menu
|
||||
* General date syntax:: Common rules.
|
||||
* Calendar date items:: 19 Dec 1994.
|
||||
* Time of day items:: 9:20pm.
|
||||
* Time zone items:: @sc{est}, @sc{pdt}, @sc{gmt}, ...
|
||||
* Day of week items:: Monday and others.
|
||||
* Relative items in date strings:: next tuesday, 2 years ago.
|
||||
* Pure numbers in date strings:: 19931219, 1440.
|
||||
* Authors of getdate:: Bellovin, Eggert, Salz, Berets, et al.
|
||||
@end menu
|
||||
|
||||
|
||||
@node General date syntax
|
||||
@section General date syntax
|
||||
|
||||
@cindex general date syntax
|
||||
|
||||
@cindex items in date strings
|
||||
A @dfn{date} is a string, possibly empty, containing many items
|
||||
separated by whitespace. The whitespace may be omitted when no
|
||||
ambiguity arises. The empty string means the beginning of today (i.e.,
|
||||
midnight). Order of the items is immaterial. A date string may contain
|
||||
many flavors of items:
|
||||
|
||||
@itemize @bullet
|
||||
@item calendar date items
|
||||
@item time of the day items
|
||||
@item time zone items
|
||||
@item day of the week items
|
||||
@item relative items
|
||||
@item pure numbers.
|
||||
@end itemize
|
||||
|
||||
@noindent We describe each of these item types in turn, below.
|
||||
|
||||
@cindex numbers, written-out
|
||||
@cindex ordinal numbers
|
||||
@findex first @r{in date strings}
|
||||
@findex next @r{in date strings}
|
||||
@findex last @r{in date strings}
|
||||
A few numbers may be written out in words in most contexts. This is
|
||||
most useful for specifying day of the week items or relative items (see
|
||||
below). Here is the list: @samp{first} for 1, @samp{next} for 2,
|
||||
@samp{third} for 3, @samp{fourth} for 4, @samp{fifth} for 5,
|
||||
@samp{sixth} for 6, @samp{seventh} for 7, @samp{eighth} for 8,
|
||||
@samp{ninth} for 9, @samp{tenth} for 10, @samp{eleventh} for 11 and
|
||||
@samp{twelfth} for 12. Also, @samp{last} means exactly @math{-1}.
|
||||
|
||||
@cindex months, written-out
|
||||
When a month is written this way, it is still considered to be written
|
||||
numerically, instead of being ``spelled in full''; this changes the
|
||||
allowed strings.
|
||||
|
||||
@cindex language, in dates
|
||||
In the current implementation, only English is supported for words and
|
||||
abbreviations like @samp{AM}, @samp{DST}, @samp{EST}, @samp{first},
|
||||
@samp{January}, @samp{Sunday}, @samp{tomorrow}, and @samp{year}.
|
||||
|
||||
@cindex language, in dates
|
||||
@cindex time zone item
|
||||
The output of @command{date} is not always acceptable as a date string,
|
||||
not only because of the language problem, but also because there is no
|
||||
standard meaning for time zone items like @samp{IST}. When using
|
||||
@command{date} to generate a date string intended to be parsed later,
|
||||
specify a date format that is independent of language and that does not
|
||||
use time zone items other than @samp{UTC} and @samp{Z}. Here are some
|
||||
ways to do this:
|
||||
|
||||
@example
|
||||
$ LC_ALL=C TZ=UTC0 date
|
||||
Fri Dec 15 19:48:05 UTC 2000
|
||||
$ TZ=UTC0 date +"%Y-%m-%d %H:%M:%SZ"
|
||||
2000-12-15 19:48:05Z
|
||||
$ date --iso-8601=seconds # a GNU extension
|
||||
2000-12-15T11:48:05-0800
|
||||
$ date --rfc-822 # a GNU extension
|
||||
Fri, 15 Dec 2000 11:48:05 -0800
|
||||
$ date +"%Y-%m-%d %H:%M:%S %z" # %z is a GNU extension.
|
||||
2000-12-15 11:48:05 -0800
|
||||
@end example
|
||||
|
||||
@cindex case, ignored in dates
|
||||
@cindex comments, in dates
|
||||
Alphabetic case is completely ignored in dates. Comments may be introduced
|
||||
between round parentheses, as long as included parentheses are properly
|
||||
nested. Hyphens not followed by a digit are currently ignored. Leading
|
||||
zeros on numbers are ignored.
|
||||
|
||||
|
||||
@node Calendar date items
|
||||
@section Calendar date items
|
||||
|
||||
@cindex calendar date item
|
||||
|
||||
A @dfn{calendar date item} specifies a day of the year. It is
|
||||
specified differently, depending on whether the month is specified
|
||||
numerically or literally. All these strings specify the same calendar date:
|
||||
|
||||
@example
|
||||
1972-09-24 # @sc{iso} 8601.
|
||||
72-9-24 # Assume 19xx for 69 through 99,
|
||||
# 20xx for 00 through 68.
|
||||
72-09-24 # Leading zeros are ignored.
|
||||
9/24/72 # Common U.S. writing.
|
||||
24 September 1972
|
||||
24 Sept 72 # September has a special abbreviation.
|
||||
24 Sep 72 # Three-letter abbreviations always allowed.
|
||||
Sep 24, 1972
|
||||
24-sep-72
|
||||
24sep72
|
||||
@end example
|
||||
|
||||
The year can also be omitted. In this case, the last specified year is
|
||||
used, or the current year if none. For example:
|
||||
|
||||
@example
|
||||
9/24
|
||||
sep 24
|
||||
@end example
|
||||
|
||||
Here are the rules.
|
||||
|
||||
@cindex @sc{iso} 8601 date format
|
||||
@cindex date format, @sc{iso} 8601
|
||||
For numeric months, the @sc{iso} 8601 format
|
||||
@samp{@var{year}-@var{month}-@var{day}} is allowed, where @var{year} is
|
||||
any positive number, @var{month} is a number between 01 and 12, and
|
||||
@var{day} is a number between 01 and 31. A leading zero must be present
|
||||
if a number is less than ten. If @var{year} is 68 or smaller, then 2000
|
||||
is added to it; otherwise, if @var{year} is less than 100,
|
||||
then 1900 is added to it. The construct
|
||||
@samp{@var{month}/@var{day}/@var{year}}, popular in the United States,
|
||||
is accepted. Also @samp{@var{month}/@var{day}}, omitting the year.
|
||||
|
||||
@cindex month names in date strings
|
||||
@cindex abbreviations for months
|
||||
Literal months may be spelled out in full: @samp{January},
|
||||
@samp{February}, @samp{March}, @samp{April}, @samp{May}, @samp{June},
|
||||
@samp{July}, @samp{August}, @samp{September}, @samp{October},
|
||||
@samp{November} or @samp{December}. Literal months may be abbreviated
|
||||
to their first three letters, possibly followed by an abbreviating dot.
|
||||
It is also permitted to write @samp{Sept} instead of @samp{September}.
|
||||
|
||||
When months are written literally, the calendar date may be given as any
|
||||
of the following:
|
||||
|
||||
@example
|
||||
@var{day} @var{month} @var{year}
|
||||
@var{day} @var{month}
|
||||
@var{month} @var{day} @var{year}
|
||||
@var{day}-@var{month}-@var{year}
|
||||
@end example
|
||||
|
||||
Or, omitting the year:
|
||||
|
||||
@example
|
||||
@var{month} @var{day}
|
||||
@end example
|
||||
|
||||
|
||||
@node Time of day items
|
||||
@section Time of day items
|
||||
|
||||
@cindex time of day item
|
||||
|
||||
A @dfn{time of day item} in date strings specifies the time on a given
|
||||
day. Here are some examples, all of which represent the same time:
|
||||
|
||||
@example
|
||||
20:02:0
|
||||
20:02
|
||||
8:02pm
|
||||
20:02-0500 # In @sc{est} (U.S. Eastern Standard Time).
|
||||
@end example
|
||||
|
||||
More generally, the time of the day may be given as
|
||||
@samp{@var{hour}:@var{minute}:@var{second}}, where @var{hour} is
|
||||
a number between 0 and 23, @var{minute} is a number between 0 and
|
||||
59, and @var{second} is a number between 0 and 59. Alternatively,
|
||||
@samp{:@var{second}} can be omitted, in which case it is taken to
|
||||
be zero.
|
||||
|
||||
@findex am @r{in date strings}
|
||||
@findex pm @r{in date strings}
|
||||
@findex midnight @r{in date strings}
|
||||
@findex noon @r{in date strings}
|
||||
If the time is followed by @samp{am} or @samp{pm} (or @samp{a.m.}
|
||||
or @samp{p.m.}), @var{hour} is restricted to run from 1 to 12, and
|
||||
@samp{:@var{minute}} may be omitted (taken to be zero). @samp{am}
|
||||
indicates the first half of the day, @samp{pm} indicates the second
|
||||
half of the day. In this notation, 12 is the predecessor of 1:
|
||||
midnight is @samp{12am} while noon is @samp{12pm}.
|
||||
(This is the zero-oriented interpretation of @samp{12am} and @samp{12pm},
|
||||
as opposed to the old tradition derived from Latin
|
||||
which uses @samp{12m} for noon and @samp{12pm} for midnight.)
|
||||
|
||||
@cindex time zone correction
|
||||
@cindex minutes, time zone correction by
|
||||
The time may alternatively be followed by a time zone correction,
|
||||
expressed as @samp{@var{s}@var{hh}@var{mm}}, where @var{s} is @samp{+}
|
||||
or @samp{-}, @var{hh} is a number of zone hours and @var{mm} is a number
|
||||
of zone minutes. When a time zone correction is given this way, it
|
||||
forces interpretation of the time relative to
|
||||
Coordinated Universal Time (@sc{utc}), overriding any previous
|
||||
specification for the time zone or the local time zone. The @var{minute}
|
||||
part of the time of the day may not be elided when a time zone correction
|
||||
is used. This is the best way to specify a time zone correction by
|
||||
fractional parts of an hour.
|
||||
|
||||
Either @samp{am}/@samp{pm} or a time zone correction may be specified,
|
||||
but not both.
|
||||
|
||||
|
||||
@node Time zone items
|
||||
@section Time zone items
|
||||
|
||||
@cindex time zone item
|
||||
|
||||
A @dfn{time zone item} specifies an international time zone, indicated
|
||||
by a small set of letters, e.g., @samp{UTC} or @samp{Z}
|
||||
for Coordinated Universal
|
||||
Time. Any included periods are ignored. By following a
|
||||
non-daylight-saving time zone by the string @samp{DST} in a separate
|
||||
word (that is, separated by some white space), the corresponding
|
||||
daylight saving time zone may be specified.
|
||||
|
||||
Time zone items other than @samp{UTC} and @samp{Z}
|
||||
are obsolescent and are not recommended, because they
|
||||
are ambiguous; for example, @samp{EST} has a different meaning in
|
||||
Australia than in the United States. Instead, it's better to use
|
||||
unambiguous numeric time zone corrections like @samp{-0500}, as
|
||||
described in the previous section.
|
||||
|
||||
|
||||
@node Day of week items
|
||||
@section Day of week items
|
||||
|
||||
@cindex day of week item
|
||||
|
||||
The explicit mention of a day of the week will forward the date
|
||||
(only if necessary) to reach that day of the week in the future.
|
||||
|
||||
Days of the week may be spelled out in full: @samp{Sunday},
|
||||
@samp{Monday}, @samp{Tuesday}, @samp{Wednesday}, @samp{Thursday},
|
||||
@samp{Friday} or @samp{Saturday}. Days may be abbreviated to their
|
||||
first three letters, optionally followed by a period. The special
|
||||
abbreviations @samp{Tues} for @samp{Tuesday}, @samp{Wednes} for
|
||||
@samp{Wednesday} and @samp{Thur} or @samp{Thurs} for @samp{Thursday} are
|
||||
also allowed.
|
||||
|
||||
@findex next @var{day}
|
||||
@findex last @var{day}
|
||||
A number may precede a day of the week item to move forward
|
||||
supplementary weeks. It is best used in expression like @samp{third
|
||||
monday}. In this context, @samp{last @var{day}} or @samp{next
|
||||
@var{day}} is also acceptable; they move one week before or after
|
||||
the day that @var{day} by itself would represent.
|
||||
|
||||
A comma following a day of the week item is ignored.
|
||||
|
||||
|
||||
@node Relative items in date strings
|
||||
@section Relative items in date strings
|
||||
|
||||
@cindex relative items in date strings
|
||||
@cindex displacement of dates
|
||||
|
||||
@dfn{Relative items} adjust a date (or the current date if none) forward
|
||||
or backward. The effects of relative items accumulate. Here are some
|
||||
examples:
|
||||
|
||||
@example
|
||||
1 year
|
||||
1 year ago
|
||||
3 years
|
||||
2 days
|
||||
@end example
|
||||
|
||||
@findex year @r{in date strings}
|
||||
@findex month @r{in date strings}
|
||||
@findex fortnight @r{in date strings}
|
||||
@findex week @r{in date strings}
|
||||
@findex day @r{in date strings}
|
||||
@findex hour @r{in date strings}
|
||||
@findex minute @r{in date strings}
|
||||
The unit of time displacement may be selected by the string @samp{year}
|
||||
or @samp{month} for moving by whole years or months. These are fuzzy
|
||||
units, as years and months are not all of equal duration. More precise
|
||||
units are @samp{fortnight} which is worth 14 days, @samp{week} worth 7
|
||||
days, @samp{day} worth 24 hours, @samp{hour} worth 60 minutes,
|
||||
@samp{minute} or @samp{min} worth 60 seconds, and @samp{second} or
|
||||
@samp{sec} worth one second. An @samp{s} suffix on these units is
|
||||
accepted and ignored.
|
||||
|
||||
@findex ago @r{in date strings}
|
||||
The unit of time may be preceded by a multiplier, given as an optionally
|
||||
signed number. Unsigned numbers are taken as positively signed. No
|
||||
number at all implies 1 for a multiplier. Following a relative item by
|
||||
the string @samp{ago} is equivalent to preceding the unit by a
|
||||
multiplier with value @math{-1}.
|
||||
|
||||
@findex day @r{in date strings}
|
||||
@findex tomorrow @r{in date strings}
|
||||
@findex yesterday @r{in date strings}
|
||||
The string @samp{tomorrow} is worth one day in the future (equivalent
|
||||
to @samp{day}), the string @samp{yesterday} is worth
|
||||
one day in the past (equivalent to @samp{day ago}).
|
||||
|
||||
@findex now @r{in date strings}
|
||||
@findex today @r{in date strings}
|
||||
@findex this @r{in date strings}
|
||||
The strings @samp{now} or @samp{today} are relative items corresponding
|
||||
to zero-valued time displacement, these strings come from the fact
|
||||
a zero-valued time displacement represents the current time when not
|
||||
otherwise changed by previous items. They may be used to stress other
|
||||
items, like in @samp{12:00 today}. The string @samp{this} also has
|
||||
the meaning of a zero-valued time displacement, but is preferred in
|
||||
date strings like @samp{this thursday}.
|
||||
|
||||
When a relative item causes the resulting date to cross a boundary
|
||||
where the clocks were adjusted, typically for daylight-saving time,
|
||||
the resulting date and time are adjusted accordingly.
|
||||
|
||||
|
||||
@node Pure numbers in date strings
|
||||
@section Pure numbers in date strings
|
||||
|
||||
@cindex pure numbers in date strings
|
||||
|
||||
The precise interpretation of a pure decimal number depends
|
||||
on the context in the date string.
|
||||
|
||||
If the decimal number is of the form @var{yyyy}@var{mm}@var{dd} and no
|
||||
other calendar date item (@pxref{Calendar date items}) appears before it
|
||||
in the date string, then @var{yyyy} is read as the year, @var{mm} as the
|
||||
month number and @var{dd} as the day of the month, for the specified
|
||||
calendar date.
|
||||
|
||||
If the decimal number is of the form @var{hh}@var{mm} and no other time
|
||||
of day item appears before it in the date string, then @var{hh} is read
|
||||
as the hour of the day and @var{mm} as the minute of the hour, for the
|
||||
specified time of the day. @var{mm} can also be omitted.
|
||||
|
||||
If both a calendar date and a time of day appear to the left of a number
|
||||
in the date string, but no relative item, then the number overrides the
|
||||
year.
|
||||
|
||||
|
||||
@node Authors of getdate
|
||||
@section Authors of @code{getdate}
|
||||
|
||||
@cindex authors of @code{getdate}
|
||||
|
||||
@cindex Bellovin, Steven M.
|
||||
@cindex Salz, Rich
|
||||
@cindex Berets, Jim
|
||||
@cindex MacKenzie, David
|
||||
@cindex Meyering, Jim
|
||||
@cindex Eggert, Paul
|
||||
@code{getdate} was originally implemented by Steven M. Bellovin
|
||||
(@email{smb@@research.att.com}) while at the University of North Carolina
|
||||
at Chapel Hill. The code was later tweaked by a couple of people on
|
||||
Usenet, then completely overhauled by Rich $alz (@email{rsalz@@bbn.com})
|
||||
and Jim Berets (@email{jberets@@bbn.com}) in August, 1990. Various
|
||||
revisions for the @sc{gnu} system were made by David MacKenzie, Jim Meyering,
|
||||
Paul Eggert and others.
|
||||
|
||||
@cindex Pinard, F.
|
||||
@cindex Berry, K.
|
||||
This chapter was originally produced by Fran@,{c}ois Pinard
|
||||
(@email{pinard@@iro.umontreal.ca}) from the @file{getdate.y} source code,
|
||||
and then edited by K.@: Berry (@email{kb@@cs.umb.edu}).
|
||||
79
doc/index.html.in
Normal file
79
doc/index.html.in
Normal file
@@ -0,0 +1,79 @@
|
||||
<!-- X-URL: %BASE_URL% -->
|
||||
<!-- Date: %DATE% -->
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>%PACKAGE_NAME% Reference Manual - Table of Contents - GNU Project - Free Software Foundation (FSF)</TITLE>
|
||||
<LINK REV="made" HREF="mailto:gray@gnu.org">
|
||||
<BASE HREF="%BASE_URL%">
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=US-ASCII">
|
||||
<META NAME="keywords" CONTENT="tar rmt">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD">
|
||||
<H1>%PACKAGE_NAME% Reference Manual - Table of Contents</H1>
|
||||
<ADDRESS>Free Software Foundation</ADDRESS>
|
||||
<ADDRESS>last updated %UPDATED%</ADDRESS>
|
||||
<P>
|
||||
<A HREF="/graphics/gnu-head-sm.jpg"><IMG SRC="/graphics/gnu-head-sm.jpg"
|
||||
ALT=" [image of the Head of a GNU] "
|
||||
WIDTH="129" HEIGHT="122"> (jpeg 7k)</A>
|
||||
<A HREF="/graphics/gnu-head.jpg">(jpeg 21k)</A>
|
||||
<A HREF="/philosophy/gif.html">no gifs due to patent problems</A>
|
||||
<P>
|
||||
<P>
|
||||
<P><HR><P>
|
||||
<P>
|
||||
This manual is available in the following formats:
|
||||
<P>
|
||||
<UL>
|
||||
<LI>formatted in <A HREF="html_mono/%PACKAGE%.html">HTML
|
||||
(%HTML_SIZE%K characters)</A> entirely on one web page.</LI>
|
||||
<LI> formatted in <a href="html_chapter/%PACKAGE%_toc.html">HTML</a>
|
||||
with one web page per chapter.</LI>
|
||||
<LI> formatted in <a href="html_node/%PACKAGE%_toc.html">HTML</a>
|
||||
with one web page per node.</LI>
|
||||
<LI>formatted as an
|
||||
<A HREF="other/%PACKAGE%.info.tar.gz">Info document (%INFO_TAR_GZ_SIZE%K characters
|
||||
gzipped tar file)</A>.</LI>
|
||||
<LI>formatted as
|
||||
<A HREF="other/%PACKAGE%.text">ASCII text (%TEXT_SIZE%K characters)</A>.</LI>
|
||||
<LI>formatted as
|
||||
<A HREF="other/%PACKAGE%.dvi.gz">a TeX dvi file (%DVI_GZ_SIZE%K characters
|
||||
gzipped)</A>.</LI>
|
||||
<LI>formatted as
|
||||
<A href="other/%PACKAGE%.ps.gz">a PostScript file (%PS_GZ_SIZE%K characters
|
||||
gzipped)</A>.</LI>
|
||||
<LI>formatted as
|
||||
<A href="other/%PACKAGE%.pdf.gz">a PDF file (%PDF_GZ_SIZE%K characters
|
||||
gzipped)</A>.</LI>
|
||||
<LI>the original
|
||||
<A HREF="other/%PACKAGE%.texi.tar.gz">Texinfo source (%TEXI_TAR_GZ_SIZE%K characters
|
||||
gzipped tar file)</A></LI>
|
||||
</UL>
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
|
||||
Return to <A HREF="/home.html">GNU's home page</A>.
|
||||
<P>
|
||||
Send FSF & GNU inquiries & questions to
|
||||
<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>.
|
||||
Other <A HREF="/home.html#ContactInfo">ways to contact</A> the FSF.
|
||||
<P>
|
||||
Comments on these web pages to
|
||||
<A HREF="mailto:webmasters@www.gnu.org"><EM>webmasters@www.gnu.org</EM></A>,
|
||||
send other questions to
|
||||
<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>.
|
||||
<P>
|
||||
Copyright (C) 1997, 1998 Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111, USA
|
||||
<P>
|
||||
Verbatim copying and distribution of this entire article is
|
||||
permitted in any medium, provided this notice is preserved.<HR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: html
|
||||
end:
|
||||
-->
|
||||
1234
doc/tar.texi
1234
doc/tar.texi
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,33 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.am
|
||||
Makefile.in
|
||||
addext.c
|
||||
alloca.c
|
||||
alloca.h
|
||||
alloca_.h
|
||||
allocsa.c
|
||||
allocsa.h
|
||||
allocsa.valgrind
|
||||
argmatch.c
|
||||
argmatch.h
|
||||
argp-ba.c
|
||||
argp-eexst.c
|
||||
argp-fmtstream.c
|
||||
argp-fmtstream.h
|
||||
argp-fs-xinl.c
|
||||
argp-help.c
|
||||
argp-namefrob.h
|
||||
argp-parse.c
|
||||
argp-pv.c
|
||||
argp-pvh.c
|
||||
argp-xinl.c
|
||||
argp.h
|
||||
backupfile.c
|
||||
backupfile.h
|
||||
basename.c
|
||||
charset.alias
|
||||
chown.c
|
||||
config.charset
|
||||
dirname.c
|
||||
dirname.h
|
||||
error.c
|
||||
@@ -20,13 +37,17 @@ exclude.h
|
||||
exit.h
|
||||
exitfail.c
|
||||
exitfail.h
|
||||
fchown-stub.c
|
||||
fileblocks.c
|
||||
fnmatch.c
|
||||
fnmatch.h
|
||||
fnmatch_.h
|
||||
fnmatch_loop.c
|
||||
ftruncate.c
|
||||
full-write.c
|
||||
full-write.h
|
||||
getcwd.c
|
||||
getcwd.h
|
||||
getdate.c
|
||||
getdate.h
|
||||
getdate.y
|
||||
@@ -37,27 +58,40 @@ getndelim2.h
|
||||
getopt.c
|
||||
getopt.h
|
||||
getopt1.c
|
||||
getopt_.h
|
||||
getopt_int.h
|
||||
getpagesize.h
|
||||
gettext.h
|
||||
gettime.c
|
||||
gettimeofday.c
|
||||
hash.c
|
||||
hash.h
|
||||
human.c
|
||||
human.h
|
||||
lchown.c
|
||||
lchown.h
|
||||
malloc.c
|
||||
localcharset.c
|
||||
localcharset.h
|
||||
localedir.h
|
||||
mempcpy.c
|
||||
mempcpy.h
|
||||
memset.c
|
||||
mktime.c
|
||||
modechange.c
|
||||
modechange.h
|
||||
obstack.c
|
||||
obstack.h
|
||||
pathmax.h
|
||||
quote.c
|
||||
quote.h
|
||||
quotearg.c
|
||||
quotearg.h
|
||||
realloc.c
|
||||
ref-add.sed
|
||||
ref-add.sin
|
||||
ref-del.sed
|
||||
ref-del.sin
|
||||
rmdir.c
|
||||
rmt.h
|
||||
rtapelib.c
|
||||
safe-read.c
|
||||
safe-read.h
|
||||
safe-write.c
|
||||
@@ -66,29 +100,43 @@ save-cwd.c
|
||||
save-cwd.h
|
||||
savedir.c
|
||||
savedir.h
|
||||
setenv.c
|
||||
setenv.h
|
||||
stat-macros.h
|
||||
stdbool.h
|
||||
stdbool_.h
|
||||
stpcpy.c
|
||||
stpcpy.h
|
||||
strcase.h
|
||||
strcasecmp.c
|
||||
strchrnul.c
|
||||
strchrnul.h
|
||||
stripslash.c
|
||||
strncasecmp.c
|
||||
strndup.c
|
||||
strndup.h
|
||||
strnlen.c
|
||||
strtoimax.c
|
||||
strtol.c
|
||||
strtoll.c
|
||||
strtoul.c
|
||||
strtoull.c
|
||||
strtoumax.c
|
||||
stpcpy.c
|
||||
stpcpy.h
|
||||
sysexit.h
|
||||
sysexit_.h
|
||||
sysexits.h
|
||||
system.h
|
||||
time_r.c
|
||||
time_r.h
|
||||
timespec.h
|
||||
unlocked-io.h
|
||||
unsetenv.c
|
||||
utime.c
|
||||
xalloc-die.c
|
||||
xalloc.h
|
||||
xgetcwd.c
|
||||
xgetcwd.h
|
||||
xmalloc.c
|
||||
xstrdup.c
|
||||
xstrtol.c
|
||||
xstrtol.h
|
||||
xstrtoul.c
|
||||
|
||||
170
lib/Makefile.am
170
lib/Makefile.am
@@ -1,170 +0,0 @@
|
||||
# Makefile for GNU tar library.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
noinst_LIBRARIES = libtar.a
|
||||
|
||||
libtar_a_SOURCES = prepargs.c prepargs.h
|
||||
|
||||
libtar_a_LIBADD = $(LIBOBJS) $(ALLOCA)
|
||||
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
|
||||
|
||||
BUILT_SOURCES =
|
||||
EXTRA_DIST =
|
||||
MAINTAINERCLEANFILES =
|
||||
MOSTLYCLEANFILES =
|
||||
lib_OBJECTS = $(libtar_a_OBJECTS)
|
||||
|
||||
|
||||
# gnulib modules
|
||||
|
||||
# alloca
|
||||
BUILT_SOURCES += $(ALLOCA_H)
|
||||
EXTRA_DIST += alloca_.h
|
||||
|
||||
# We need the following in order to create an <alloca.h> when the system
|
||||
# doesn't have one that works with the given compiler.
|
||||
all-local $(lib_OBJECTS): $(ALLOCA_H)
|
||||
alloca.h: alloca_.h
|
||||
cp $(srcdir)/alloca_.h $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += alloca.h alloca.h-t
|
||||
|
||||
# argmatch
|
||||
libtar_a_SOURCES += argmatch.h argmatch.c
|
||||
|
||||
# backupfile
|
||||
libtar_a_SOURCES += backupfile.h backupfile.c addext.c
|
||||
|
||||
# dirname
|
||||
libtar_a_SOURCES += dirname.h dirname.c basename.c stripslash.c
|
||||
|
||||
# exclude
|
||||
libtar_a_SOURCES += exclude.h exclude.c
|
||||
|
||||
# exitfail
|
||||
libtar_a_SOURCES += exitfail.h exitfail.c
|
||||
|
||||
# exit
|
||||
libtar_a_SOURCES += exit.h
|
||||
|
||||
# fnmatch
|
||||
BUILT_SOURCES += $(FNMATCH_H)
|
||||
EXTRA_DIST += fnmatch_.h fnmatch_loop.c
|
||||
|
||||
# stpcpy
|
||||
EXTRA_DIST += stpcpy.c stpcpy.h
|
||||
|
||||
# We need the following in order to create an <fnmatch.h> when the system
|
||||
# doesn't have one that supports the required API.
|
||||
all-local $(lib_OBJECTS): $(FNMATCH_H)
|
||||
fnmatch.h: fnmatch_.h
|
||||
cp $(srcdir)/fnmatch_.h $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += fnmatch.h fnmatch.h-t
|
||||
|
||||
# full-write
|
||||
libtar_a_SOURCES += full-write.h full-write.c
|
||||
|
||||
# getdate
|
||||
libtar_a_SOURCES += getdate.h getdate.y
|
||||
BUILT_SOURCES += getdate.c
|
||||
MAINTAINERCLEANFILES += getdate.c
|
||||
#
|
||||
# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule.
|
||||
$(srcdir)/getdate.c: getdate.y
|
||||
cd $(srcdir) && \
|
||||
$(YACC) $(YFLAGS) getdate.y && \
|
||||
mv -f y.tab.c getdate.c
|
||||
|
||||
# getline
|
||||
libtar_a_SOURCES += getline.h
|
||||
EXTRA_DIST += getndelim2.h getndelim2.c
|
||||
|
||||
# getopt
|
||||
libtar_a_SOURCES += getopt.h getopt.c getopt1.c
|
||||
|
||||
# gettext
|
||||
libtar_a_SOURCES += gettext.h
|
||||
|
||||
# hash
|
||||
libtar_a_SOURCES += hash.h hash.c
|
||||
|
||||
# human
|
||||
libtar_a_SOURCES += human.h human.c
|
||||
|
||||
# lchown
|
||||
libtar_a_SOURCES += lchown.h
|
||||
|
||||
# modechange
|
||||
libtar_a_SOURCES += modechange.h modechange.c
|
||||
|
||||
# pathmax
|
||||
libtar_a_SOURCES += pathmax.h
|
||||
|
||||
# time_r
|
||||
EXTRA_DIST += time_r.h
|
||||
|
||||
# quote
|
||||
libtar_a_SOURCES += quote.h quote.c
|
||||
|
||||
# quotearg
|
||||
libtar_a_SOURCES += quotearg.h quotearg.c
|
||||
|
||||
# safe-read
|
||||
libtar_a_SOURCES += safe-read.h safe-read.c
|
||||
|
||||
# safe-write
|
||||
libtar_a_SOURCES += safe-write.h safe-write.c
|
||||
|
||||
# save-cwd
|
||||
libtar_a_SOURCES += save-cwd.h save-cwd.c
|
||||
|
||||
# savedir
|
||||
libtar_a_SOURCES += savedir.h savedir.c
|
||||
|
||||
# stdbool
|
||||
BUILT_SOURCES += $(STDBOOL_H)
|
||||
EXTRA_DIST += stdbool_.h
|
||||
|
||||
# strcase
|
||||
EXTRA_DIST += strcase.h
|
||||
|
||||
# We need the following in order to create an <stdbool.h> when the system
|
||||
# doesn't have one that works.
|
||||
all-local $(lib_OBJECTS): $(STDBOOL_H)
|
||||
stdbool.h: stdbool_.h
|
||||
sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' < $(srcdir)/stdbool_.h > $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += stdbool.h stdbool.h-t
|
||||
|
||||
# unlocked-io
|
||||
libtar_a_SOURCES += unlocked-io.h
|
||||
|
||||
# xalloc
|
||||
libtar_a_SOURCES += xalloc.h xmalloc.c xstrdup.c
|
||||
|
||||
# xgetcwd
|
||||
libtar_a_SOURCES += xgetcwd.h xgetcwd.c
|
||||
|
||||
# xstrtol
|
||||
libtar_a_SOURCES += xstrtol.h xstrtol.c xstrtoul.c
|
||||
|
||||
# xstrtoumax
|
||||
libtar_a_SOURCES += xstrtoumax.c
|
||||
56
lib/Makefile.tmpl
Normal file
56
lib/Makefile.tmpl
Normal file
@@ -0,0 +1,56 @@
|
||||
# Makefile for GNU tar library.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004
|
||||
# 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
noinst_LIBRARIES = libtar.a
|
||||
noinst_HEADERS = system.h localedir.h rmt.h
|
||||
libtar_a_SOURCES = prepargs.c prepargs.h rtapelib.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
DISTCLEANFILES = localedir.h
|
||||
localedir.h : Makefile
|
||||
echo '#define LOCALEDIR "$(localedir)"' >$@
|
||||
echo "#ifndef DEFAULT_RMT_COMMAND" >> $@
|
||||
echo "# define DEFAULT_RMT_COMMAND \"$(DEFAULT_RMT_DIR)/`echo \"rmt\" | sed 's,^.*/,,;$(transform)'`$(EXEEXT)\"" >> $@
|
||||
echo "#endif" >> $@
|
||||
|
||||
rtapelib.o: localedir.h
|
||||
|
||||
libtar_a_LIBADD = $(LIBOBJS) $(ALLOCA)
|
||||
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
|
||||
|
||||
BUILT_SOURCES =
|
||||
EXTRA_DIST = Makefile.tmpl
|
||||
MAINTAINERCLEANFILES =
|
||||
MOSTLYCLEANFILES =
|
||||
lib_OBJECTS = $(libtar_a_OBJECTS)
|
||||
|
||||
# Special rule for getdate
|
||||
#
|
||||
# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule.
|
||||
$(srcdir)/getdate.c: getdate.y
|
||||
cd $(srcdir) && \
|
||||
$(YACC) $(YFLAGS) getdate.y && \
|
||||
mv -f y.tab.c getdate.c
|
||||
|
||||
SUFFIXES = .o .c .h
|
||||
CLEANFILES =
|
||||
# gnulib modules
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
*_gl.m4
|
||||
Makefile
|
||||
Makefile.in
|
||||
alloca.m4
|
||||
allocsa.m4
|
||||
argp.m4
|
||||
backupfile.m4
|
||||
bison.m4
|
||||
chown.m4
|
||||
clock_time.m4
|
||||
codeset.m4
|
||||
d-ino.m4
|
||||
dirname.m4
|
||||
dos.m4
|
||||
eealloc.m4
|
||||
error.m4
|
||||
exclude.m4
|
||||
exitfail.m4
|
||||
@@ -15,13 +20,18 @@ extensions.m4
|
||||
fileblocks.m4
|
||||
fnmatch.m4
|
||||
ftruncate.m4
|
||||
getcwd-path-max.m4
|
||||
getcwd.m4
|
||||
getdate.m4
|
||||
getline.m4
|
||||
getndelim2.m4
|
||||
getopt.m4
|
||||
getpagesize.m4
|
||||
gettext.m4
|
||||
gettime.m4
|
||||
gettimeofday.m4
|
||||
glibc21.m4
|
||||
gnulib.m4
|
||||
hash.m4
|
||||
human.m4
|
||||
iconv.m4
|
||||
@@ -37,45 +47,52 @@ lcmessage.m4
|
||||
lib-ld.m4
|
||||
lib-link.m4
|
||||
lib-prefix.m4
|
||||
localcharset.m4
|
||||
longdouble.m4
|
||||
longlong.m4
|
||||
malloc.m4
|
||||
mbrtowc.m4
|
||||
mbstate_t.m4
|
||||
mempcpy.m4
|
||||
memset.m4
|
||||
mktime.m4
|
||||
modechange.m4
|
||||
nls.m4
|
||||
obstack.m4
|
||||
onceonly.m4
|
||||
pathmax.m4
|
||||
po.m4
|
||||
printf-posix.m4
|
||||
progtest.m4
|
||||
quote.m4
|
||||
quotearg.m4
|
||||
realloc.m4
|
||||
restrict.m4
|
||||
rmdir.m4
|
||||
rmt.m4
|
||||
safe-read.m4
|
||||
safe-write.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
setenv.m4
|
||||
signed.m4
|
||||
size_max.m4
|
||||
ssize_t.m4
|
||||
st_mtim.m4
|
||||
stdbool.m4
|
||||
stdint_h.m4
|
||||
stpcpy.m4
|
||||
strcase.m4
|
||||
strchrnul.m4
|
||||
strerror_r.m4
|
||||
strndup.m4
|
||||
strnlen.m4
|
||||
strtoimax.m4
|
||||
strtol.m4
|
||||
strtoll.m4
|
||||
strtoul.m4
|
||||
strtoull.m4
|
||||
strtoumax.m4
|
||||
stpcpy.m4
|
||||
sysexits.m4
|
||||
time_r.m4
|
||||
timespec.m4
|
||||
tm_gmtoff.m4
|
||||
uintmax_t.m4
|
||||
ulonglong.m4
|
||||
|
||||
@@ -24,6 +24,9 @@ lib/getopt.c
|
||||
lib/human.c
|
||||
lib/quotearg.c
|
||||
lib/xmalloc.c
|
||||
lib/rtapelib.c
|
||||
lib/argp-help.c
|
||||
rmt/rmt.c
|
||||
|
||||
# Package source files
|
||||
src/buffer.c
|
||||
@@ -37,8 +40,6 @@ src/list.c
|
||||
src/mangle.c
|
||||
src/misc.c
|
||||
src/names.c
|
||||
src/rmt.c
|
||||
src/rtapelib.c
|
||||
src/tar.c
|
||||
src/update.c
|
||||
src/xheader.c
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
backup.sh
|
||||
backup
|
||||
restore
|
||||
dump-remind
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# Makefile for GNU tar scripts.
|
||||
|
||||
# Copyright (C) 1994, 2003 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
@@ -13,7 +11,39 @@
|
||||
## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
EXTRA_DIST = WARNING backup-specs dump-remind level-0 level-1 weekly.new
|
||||
BACKUP_LIBEXEC_SCRIPTS_LIST=backup.sh dump-remind
|
||||
BACKUP_SBIN_SCRIPTS_LIST=backup restore
|
||||
libexec_SCRIPTS=@BACKUP_LIBEXEC_SCRIPTS@
|
||||
AM_INSTALLCHECK_STD_OPTIONS_EXEMPT=backup.sh dump-remind
|
||||
sbin_SCRIPTS=@BACKUP_SBIN_SCRIPTS@
|
||||
EXTRA_SCRIPTS=tarcat
|
||||
EXTRA_DIST=\
|
||||
backup.sh.in\
|
||||
backup.in\
|
||||
restore.in\
|
||||
dump-remind.in\
|
||||
backup-specs
|
||||
CLEANFILES=backup.sh backup restore dump-remind
|
||||
|
||||
SED_CMD="s,\@libexecdir\@,$(libexecdir),;\
|
||||
s,\@sysconfdir\@,$(sysconfdir),;\
|
||||
s,\@PACKAGE\@,$(PACKAGE),;\
|
||||
s,\@VERSION\@,$(VERSION),;\
|
||||
s,\@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),;\
|
||||
s,\@DATE_FORMAT_OK\@,$(DATE_FORMAT_OK),;@BACKUP_SED_COND@"
|
||||
|
||||
backup.sh: $(srcdir)/backup.sh.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
backup: $(srcdir)/backup.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
restore: $(srcdir)/restore.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
dump-remind: $(srcdir)/dump-remind.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
GNU tar scripts have not been updated in a long while. make will
|
||||
not not install them. Please consider the contents of this directory
|
||||
are provided as indicative for the time being.
|
||||
@@ -1,34 +1,68 @@
|
||||
# site-specific parameters for file system backup.
|
||||
# This is a sample configuration file for GNU tar backup script.
|
||||
# See end of file for copying conditions
|
||||
|
||||
# User name of administrator of backups.
|
||||
ADMINISTRATOR=backup-reports
|
||||
# User name or email address of the administrator of backups. A report
|
||||
# will be sent to this address when the backup terminates
|
||||
ADMINISTRATOR="root@localhost"
|
||||
|
||||
# Hour at which backups are normally done.
|
||||
# This should be a number from 0 to 23.
|
||||
BACKUP_HOUR=1
|
||||
# (Optional) Path to tar binary.
|
||||
TAR=/bin/tar
|
||||
|
||||
# Location of GNU tar. This must be the same for all hosts.
|
||||
TAR=/usr/local/gnubin/tar
|
||||
# (Optional) Path to rsh binary or its equivalent. You may wish to
|
||||
# set it to ssh as shown in the example below, to improve security.
|
||||
# In this case you will have to use public key authentication.
|
||||
RSH=/usr/local/bin/ssh
|
||||
|
||||
# (Optional) Path to rsh binary on remote mashines. This will be
|
||||
# passed via --rsh-command option to the remote invocation of
|
||||
# tar
|
||||
RSH_COMMAND=/usr/local/bin/ssh
|
||||
|
||||
# Name of temporary file to hold volume numbers. This needs to be accessible
|
||||
# by all the machines which have filesystems to be dumped.
|
||||
VOLNO_FILE=/root/volume
|
||||
|
||||
# Device to use for dumping. It should be on the host
|
||||
# on which the dump scripts are run.
|
||||
TAPE_FILE=/dev/nrsmt0
|
||||
|
||||
# Command to obtain status of tape drive, including error count.
|
||||
# On some tape drives there may not be such a command;
|
||||
# then simply use `TAPE_STATUS=false'.
|
||||
#
|
||||
# Might also consider
|
||||
# TAPE_STATUS="mt -f ${TAPE_FILE} status"
|
||||
# if `mts' is missing, though this alternative is rather verbose.
|
||||
TAPE_STATUS="mts -t ${TAPE_FILE}"
|
||||
TAPE_FILE=/dev/rmt0
|
||||
|
||||
# Blocking factor to use for writing the dump.
|
||||
BLOCKING=124
|
||||
|
||||
# Name of temporary file to hold volume numbers. This needs to be accessible
|
||||
# by all the machines which have filesystems to be dumped.
|
||||
VOLNO_FILE=/home/gd2/dump/volnofile
|
||||
# List of file systems to be dumped. If prefixed with a HOST:
|
||||
# the filesystem is accessed on the given HOST, unless it
|
||||
# coincides with the local machine name.
|
||||
# If a file system starts with a slash, it is handled as a local
|
||||
# one.
|
||||
BACKUP_DIRS='remote1:/etc remote1:/var/spool/crontab'
|
||||
# Alternatively, you may leave this variable unassigned, and
|
||||
# keep the list of filesystems to be dumped in file
|
||||
# $SYSCONFDIR/backup/dirs, one filesystem per line. Empty
|
||||
# lines and shell comments are allowed in this file. The location
|
||||
# of this file may be overridden using DIRLIST variable, e.g.:
|
||||
# DIRLIST=/etc/my-backup/dirlist
|
||||
|
||||
# List of individual files to be dumped.
|
||||
# These should be accesible from the machine on which the dump is run.
|
||||
BACKUP_FILES=''
|
||||
# This list may also be kept in file $SYSCONFDIR/backup/files, the
|
||||
# format of which is the same as described above. The location of
|
||||
# this file may be overridden by setting FILELIST variable:
|
||||
# FILELIST=/etc/my-backup/filelist
|
||||
|
||||
# Name of 'exclude file list'. It is searched under $SYSCONFDIR/tar-backup
|
||||
# on remote machines
|
||||
XLIST=exclude_files
|
||||
|
||||
# Default directory for storing incremental listings on remote
|
||||
# machines is $SYSCONFDIR/tar-backup. It can be overridden using
|
||||
# REMOTEBACKUPDIR variable
|
||||
|
||||
# Default directory for storing backup logs is $SYSCONFDIR/backup/log.
|
||||
# It can also be overridden via LOGPATH variable.
|
||||
|
||||
# Time to sleep between dumps of any two successive filesystems
|
||||
SLEEP_TIME=15
|
||||
|
||||
# Script to be run when it's time to insert a new tape in for the next
|
||||
# volume. Administrators may want to tailor this script for their site.
|
||||
@@ -36,37 +70,6 @@ VOLNO_FILE=/home/gd2/dump/volnofile
|
||||
# probably defined in the manual.
|
||||
#DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind'
|
||||
|
||||
# List of file systems to be dumped.
|
||||
# Actually, any directory may be used, but if it has subdirectories on
|
||||
# other file systems, they are not included.
|
||||
# The host name specifies which host to run tar on.
|
||||
# It should normally be the host that actually has the file system.
|
||||
# If GNU tar is not installed on that machine, then you can specify some
|
||||
# other host which can access the file system through NFS.
|
||||
# Although these are arranged one per line, that is not mandatory.
|
||||
# It does not work to use # for comments within the string.
|
||||
|
||||
BACKUP_DIRS='
|
||||
albert:/fs/fsf
|
||||
sugar-bombs:/fs/gd
|
||||
albert:/fs/gd2
|
||||
churchy:/fs/gd3
|
||||
nutrimat:/fs/gp
|
||||
nutrimat:/fs/gp2
|
||||
albert:/fs/mailer
|
||||
placebo:/archive
|
||||
nutrimat:/fs/dist
|
||||
albert:/
|
||||
albert:/usr
|
||||
nutrimat:/
|
||||
placebo:/
|
||||
ernst:/usr1
|
||||
'
|
||||
|
||||
# List of individual files to be dumped.
|
||||
# These should be accesible from the machine on which the dump is run.
|
||||
BACKUP_FILES=''
|
||||
|
||||
# Message to display on the terminal while waiting for dump time. Usually
|
||||
# this will just be some literal text, preferably something more
|
||||
# entertaining than this. The awk script here saves some redundant
|
||||
@@ -78,5 +81,20 @@ SLEEP_MESSAGE="`awk '
|
||||
\"D O N O T T O U C H T H I S T E R M I N A L !!!!!\"
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
# eof
|
||||
## 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
255
scripts/backup.in
Normal file
255
scripts/backup.in
Normal file
@@ -0,0 +1,255 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright 2004, Free Software Foundation
|
||||
#
|
||||
# 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 1, 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
. ${LIBDIR-@libexecdir@}/backup.sh
|
||||
|
||||
DUMP_LEVEL=0
|
||||
TIME=
|
||||
NOW=`now`
|
||||
|
||||
usage() {
|
||||
cat - <<EOF
|
||||
usage: $PROGNAME [OPTIONS] [WHEN]
|
||||
Options are:
|
||||
|
||||
-l, --level=LEVEL Do backup level LEVEL (default $DUMP_LEVEL).
|
||||
-f, --force Force backup even if today's log file already
|
||||
exists.
|
||||
-v, --verbose[=LEVEL] Set verbosity level. Default 100.
|
||||
-t, --time=TIME Wait till TIME, then do backup.
|
||||
|
||||
Informational options:
|
||||
-h, --help Display this help message.
|
||||
-L, --license Display program license.
|
||||
-V, --version Display program version.
|
||||
|
||||
Optional argument WHEN is for backward compatibility only. It has been
|
||||
superseded by --time option.
|
||||
TIME argument can be one of:
|
||||
|
||||
now -- do backup immediately.
|
||||
HH -- do backup at HH hours.
|
||||
HH:MM -- do backup at HH:MM.
|
||||
|
||||
Send bug reports to @PACKAGE_BUGREPORT@.
|
||||
EOF
|
||||
}
|
||||
|
||||
# For compatibility with previous versions, deduce the backup level
|
||||
# from the command name
|
||||
case "$PROGNAME" in
|
||||
level-[0-9]) DUMP_LEVEL=`expr $PROGNAME : 'level-\([0-9][0-9]*\)'`;;
|
||||
esac
|
||||
|
||||
for opt
|
||||
do
|
||||
if [ -z "$prev" ]; then
|
||||
option=$opt
|
||||
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
|
||||
else
|
||||
option="${prev}=$opt"
|
||||
prev=""
|
||||
optarg=$opt
|
||||
fi
|
||||
case $option in
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
;;
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
--t=*|--ti=*|--tim=*|--time=*)
|
||||
TIME=$optarg
|
||||
;;
|
||||
-t) prev=--t;;
|
||||
-t*) TIME=`expr $option : "-t\(.*\)"`;;
|
||||
--t|--ti|--tim|--time)
|
||||
prev=$option
|
||||
;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "backup (@PACKAGE@ @VERSION@)"
|
||||
exit 0;;
|
||||
-L|--li|--lic|--lice|--licen|--licens|--license)
|
||||
license
|
||||
exit;;
|
||||
-h|--h|--he|--hel|--help)
|
||||
usage
|
||||
exit;;
|
||||
-f|--f|--fo|--for|--forc|--force)
|
||||
FORCE=yes
|
||||
;;
|
||||
*) if [ "x$TIME" != "x" ]; then
|
||||
bailout "Extra argument. Try $PROGNAME --help for more info."
|
||||
else
|
||||
TIME=$option
|
||||
fi;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "x$TIME" = x ]; then
|
||||
bailout "No backup time specified. Try $PROGNAME --help for more info."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
init_backup
|
||||
|
||||
# Maybe sleep until around specified or default hour.
|
||||
wait_time $TIME
|
||||
|
||||
if [ $DUMP_LEVEL -ne 0 ]; then
|
||||
PREV_LEVEL=`expr $DUMP_LEVEL - 1`
|
||||
PREV_DATE=`ls -t ${LOGPATH}/log-*-level-$PREV_LEVEL|
|
||||
head -1|
|
||||
sed "s,${LOGPATH}/log-\(.*\)-level.*,\1,"`
|
||||
if [ "x$PREV_DATE" = x ]; then
|
||||
bailout "Can't determine date of the previous backup"
|
||||
fi
|
||||
message 0 "Backup from $PREV_DATE to $NOW"
|
||||
fi
|
||||
|
||||
# start doing things
|
||||
|
||||
# Make sure the log file did not already exist. Create it.
|
||||
|
||||
if [ "x$FORCE" = "xyes" ]; then
|
||||
rm ${LOGFILE}
|
||||
fi
|
||||
|
||||
if [ -f "${LOGFILE}" ] ; then
|
||||
bailout "Log file ${LOGFILE} already exists."
|
||||
else
|
||||
touch "${LOGFILE}"
|
||||
fi
|
||||
message 1 "Ready for backup."
|
||||
message 10 "TAR invocation: $TAR_PART1"
|
||||
message 20 "Variables:"
|
||||
message 20 "BACKUP_DIRS=$BACKUP_DIRS"
|
||||
message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
|
||||
# The buch of commands below is run in a subshell for which all output is
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
message 1 "preparing tapes"
|
||||
$MT_BEGIN "${TAPE_FILE}"
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
|
||||
set - ${BACKUP_DIRS}
|
||||
while [ $# -ne 0 ] ; do
|
||||
date="`date`"
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
remotehost="`expr \"${1}\" : '\([^/][^/]*\):.*'`"
|
||||
if [ -z "$remotehost" ]; then
|
||||
remotehost=$localhost
|
||||
fi
|
||||
|
||||
echo "Backing up ${1} at ${date}"
|
||||
message 10 "fs=$fs"
|
||||
message 10 "fsname=$fsname"
|
||||
message 10 "remotehost=$remotehost"
|
||||
if [ $DUMP_LEVEL -eq 0 ]; then
|
||||
make_level_log ${remotehost}
|
||||
else
|
||||
echo "Last `prev_level` dump on this filesystem was on $PREV_DATE"
|
||||
remote_run "${remotehost}" cp "`level_log_name ${fsname} $PREV_LEVEL`" "`level_log_name temp`"
|
||||
fi
|
||||
|
||||
${DUMP_BEGIN-:} $DUMP_LEVEL $remotehost $fs $fsname
|
||||
backup_host ${remotehost} \
|
||||
"--listed=`level_log_name temp`" \
|
||||
"--label='`print_level` backup of ${fs} on ${remotehost} at ${NOW}'" \
|
||||
-C ${ROOT_FS}${fs} .
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
flush_level_log ${remotehost} ${fsname}
|
||||
fi
|
||||
${MT_STATUS}
|
||||
${DUMP_END-:} $DUMP_LEVEL $remotehost $fs $fsname
|
||||
echo "sleeping ${SLEEP_TIME} seconds"
|
||||
sleep ${SLEEP_TIME}
|
||||
shift
|
||||
done
|
||||
|
||||
# Dump any individual files requested.
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
message 1 "processing individual files"
|
||||
|
||||
date="`date`"
|
||||
|
||||
if [ $DUMP_LEVEL -eq 0 ]; then
|
||||
make_level_log $localhost
|
||||
else
|
||||
echo "Last `prev_level` dump on this filesystem was on $PREV_DATE"
|
||||
remote_run "${localhost}" cp "`level_log_name MISC $PREV_LEVEL`" "`level_log_name temp`"
|
||||
fi
|
||||
|
||||
echo "Backing up miscellaneous files at ${date}"
|
||||
|
||||
${DUMP_BEGIN-:} $DUMP_LEVEL $localhost MISC MISC
|
||||
backup_host $localhost \
|
||||
"--listed=`level_log_name temp`"\
|
||||
"--label='`print_level` backup of miscellaneous files at ${NOW}'" \
|
||||
${BACKUP_FILES}
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of miscellaneous files failed."
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
flush_level_log $localhost MISC
|
||||
fi
|
||||
${MT_STATUS}
|
||||
${DUMP_END-:} $DUMP_LEVEL $localhost MISC MISC
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
message 1 "final cleanup"
|
||||
|
||||
$MT_REWIND "${TAPE_FILE}"
|
||||
$MT_OFFLINE "${TAPE_FILE}"
|
||||
echo "."
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
if test "${ADMINISTRATOR}" != NONE; then
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
fi
|
||||
|
||||
# EOF
|
||||
346
scripts/backup.sh.in
Normal file
346
scripts/backup.sh.in
Normal file
@@ -0,0 +1,346 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright 2004, Free Software Foundation
|
||||
#
|
||||
# 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 1, 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
PROGNAME=`basename $0`
|
||||
CONFIGPATH="$SYSCONFDIR/backup"
|
||||
REMOTEBACKUPDIR="$SYSCONFDIR/tar-backup"
|
||||
CONFIGFILE=${CONFIGPATH}/backup-specs
|
||||
DIRLIST=${CONFIGPATH}/dirs
|
||||
FILELIST=${CONFIGPATH}/files
|
||||
LOGPATH=${CONFIGPATH}/log
|
||||
|
||||
# Default functions for running various magnetic tape commands
|
||||
mt_begin() {
|
||||
mt -f "$1" retension
|
||||
}
|
||||
|
||||
mt_rewind() {
|
||||
mt -f "$1" rewind
|
||||
}
|
||||
|
||||
mt_offline() {
|
||||
mt -f "$1" offl
|
||||
}
|
||||
|
||||
mt_status() {
|
||||
mt -f "$1" status
|
||||
}
|
||||
|
||||
# The main configuration file may override any of these variables
|
||||
MT_BEGIN=mt_begin
|
||||
MT_REWIND=mt_rewind
|
||||
MT_OFFLINE=mt_offl
|
||||
MT_STATUS=mt_status
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
# to run longer than 24 hours (as may be the case if someone forgets to put
|
||||
# in the next volume of the tape in adequate time), the backup date won't
|
||||
# appear too misleading.
|
||||
startdate="`date`"
|
||||
here="`pwd`"
|
||||
# Save local hostname
|
||||
localhost="`hostname | sed -e 's/\..*//' | tr A-Z a-z`"
|
||||
|
||||
# Produce a diagnostic output
|
||||
message() {
|
||||
if [ "$VERBOSE" != "" ]; then
|
||||
if [ $VERBOSE -ge $1 ]; then
|
||||
shift
|
||||
echo "$@" >&2
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Bail out and exit.
|
||||
bailout() {
|
||||
echo "$PROGNAME: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Return current date
|
||||
now() {
|
||||
#IF_DATE_FORMAT_OK
|
||||
date +%Y-%m-%d
|
||||
#ELSE_DATE_FORMAT_OK
|
||||
LC_ALL=C date | \
|
||||
sed 's/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
||||
/-[0-9]$/s/\([0-9]\)$/0\1/
|
||||
/Jan/{s/Jan/01/p;q;}
|
||||
/Feb/{s/Feb/02/p;q;}
|
||||
/Mar/{s/Mar/03/p;q;}
|
||||
/Apr/{s/Apr/04/p;q;}
|
||||
/May/{s/May/05/p;q;}
|
||||
/Jun/{s/Jun/06/p;q;}
|
||||
/Jul/{s/Jul/07/p;q;}
|
||||
/Aug/{s/Aug/08/p;q;}
|
||||
/Sep/{s/Sep/09/p;q;}
|
||||
/Oct/{s/Oct/10/p;q;}
|
||||
/Nov/{s/Nov/11/p;q;}
|
||||
/Dec/{s/Dec/12/p;q;}'
|
||||
#ENDIF_DATE_FORMAT_OK
|
||||
}
|
||||
|
||||
# Bail out if we don't have root privileges.
|
||||
test_root() {
|
||||
if [ ! -w ${ROOT_FS-/} ]; then
|
||||
bailout "The backup must be run as root or else some files will fail to be dumped."
|
||||
fi
|
||||
case "${ROOT_FS}" in
|
||||
*/) ;;
|
||||
*) ROOT_FS="${ROOT_FS}/"
|
||||
esac
|
||||
}
|
||||
|
||||
advice() {
|
||||
echo "Directory $1 is not found." >&2
|
||||
cat >&2 <<EOF
|
||||
The following directories and files are needed for the backup to function:
|
||||
|
||||
1. Directory with configuration files and file lists:
|
||||
$CONFIGPATH
|
||||
2. Directory for backup log files
|
||||
$LOGPATH
|
||||
3. Main configuration file
|
||||
$CONFIGFILE
|
||||
|
||||
Please, create these and invoke the script again.
|
||||
EOF
|
||||
}
|
||||
|
||||
init_common() {
|
||||
# Check if the necessary directories exist
|
||||
if [ ! -d $CONFIGPATH ]; then
|
||||
advice $CONFIGPATH
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d $LOGPATH ]; then
|
||||
if mkdir $LOGPATH; then
|
||||
:
|
||||
else
|
||||
advice $LOGPATH
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
||||
if [ ! -r $CONFIGFILE ]; then
|
||||
echo "$PROGNAME: cannot read $CONFIGFILE. Stop." >&2
|
||||
exit 1
|
||||
fi
|
||||
. $CONFIGFILE
|
||||
|
||||
# Environment sanity check
|
||||
|
||||
test_root
|
||||
|
||||
if [ x"${ADMINISTRATOR}" = x ]; then
|
||||
bailout "ADMINISTRATOR not defined"
|
||||
fi
|
||||
|
||||
[ x"$TAR" = x ] && TAR=tar
|
||||
[ x"$SLEEP_TIME" = x ] && SLEEP_TIME=60
|
||||
|
||||
if [ x$VOLNO_FILE = x ]; then
|
||||
bailout "VOLNO_FILE not specified"
|
||||
fi
|
||||
|
||||
if [ -r $DIRLIST ]; then
|
||||
BACKUP_DIRS="$BACKUP_DIRS `cat $DIRLIST`"
|
||||
fi
|
||||
if [ -r $FILELIST ]; then
|
||||
BACKUP_FILES="$BACKUP_FILES `cat $FILELIST`"
|
||||
fi
|
||||
|
||||
if [ \( x"$BACKUP_DIRS" = x \) -a \( x"$BACKUP_FILES" = x \) ]; then
|
||||
bailout "Neither BACKUP_DIRS nor BACKUP_FILES specified"
|
||||
fi
|
||||
if [ "$RSH" = "" ]; then
|
||||
RSH=rsh
|
||||
fi
|
||||
POSIXLY_CORRECT=1
|
||||
export POSIXLY_CORRECT
|
||||
}
|
||||
|
||||
init_backup() {
|
||||
init_common
|
||||
TAR_PART1="${TAR} -c --format=gnu --multi-volume --one-file-system --sparse --volno-file=${VOLNO_FILE}"
|
||||
if [ "x$XLIST" != x ]; then
|
||||
TAR_PART1="${TAR_PART1} \`test -r $REMOTEBACKUPDIR/$XLIST && echo \"--exclude-from $REMOTEBACKUPDIR/$XLIST\"\`"
|
||||
fi
|
||||
if [ "$RSH_COMMAND" != "" ]; then
|
||||
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
|
||||
fi
|
||||
if [ x$BLOCKING != x ]; then
|
||||
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
|
||||
fi
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
# Set logfile name
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-0''
|
||||
# They go in the directory `@sysconfdir@/log'.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="${LOGPATH}/log-`now`-level-${DUMP_LEVEL}"
|
||||
}
|
||||
|
||||
init_restore() {
|
||||
init_common
|
||||
# FIXME: Replace --list with --extract
|
||||
TAR_PART1="${TAR} --extract --multi-volume"
|
||||
if [ "$RSH_COMMAND" != "" ]; then
|
||||
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
|
||||
fi
|
||||
if [ x$BLOCKING != x ]; then
|
||||
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
|
||||
fi
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
LOGFILE="${LOGPATH}/restore-`now`"
|
||||
}
|
||||
|
||||
wait_time() {
|
||||
if [ "${1}" != "now" ]; then
|
||||
if [ "${1}x" != "x" ]; then
|
||||
spec="${1}"
|
||||
else
|
||||
spec="${BACKUP_HOUR}"
|
||||
fi
|
||||
|
||||
pausetime="`date | awk -v spec=\"${spec}\" '
|
||||
BEGIN {
|
||||
split(spec, time, ":")
|
||||
}
|
||||
{
|
||||
split($4, now, ":")
|
||||
diff = 3600 * (time[1] - now[1]) + 60 * (time[2] - now[2]);
|
||||
if (diff < 0)
|
||||
diff += 3600 * 24
|
||||
print diff
|
||||
}'`"
|
||||
clear
|
||||
echo "${SLEEP_MESSAGE}"
|
||||
sleep "${pausetime}"
|
||||
fi
|
||||
}
|
||||
|
||||
level_log_name() {
|
||||
echo "$REMOTEBACKUPDIR/${1}.level-${2-$DUMP_LEVEL}"
|
||||
}
|
||||
|
||||
# Prepare a temporary level logfile
|
||||
# usage: make_level_log HOSTNAME
|
||||
make_level_log() {
|
||||
if [ "z${localhost}" != "z$1" ] ; then
|
||||
$RSH "$1" mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
|
||||
$RSH "$1" rm -f `level_log_name temp`
|
||||
else
|
||||
mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
|
||||
rm -f `level_log_name temp`
|
||||
fi
|
||||
}
|
||||
|
||||
# Rename temporary log
|
||||
# usage: flush_level_log HOSTNAME FSNAME
|
||||
flush_level_log() {
|
||||
message 10 "RENAME: `level_log_name temp` --> `level_log_name $2`"
|
||||
if [ "z${localhost}" != "z$1" ] ; then
|
||||
$RSH "$1" mv -f `level_log_name temp` "`level_log_name $2`"
|
||||
else
|
||||
mv -f `level_log_name temp` "`level_log_name $2`"
|
||||
fi
|
||||
}
|
||||
|
||||
# Return the timestamp of the last backup.
|
||||
# usage: get_dump_time LEVEL
|
||||
get_dump_time() {
|
||||
ls -r ${LOGPATH}/log-*-level-$1 \
|
||||
| head -1 \
|
||||
| sed "s,.*log-\(.*\)-level-$1,\1,"
|
||||
}
|
||||
|
||||
# Do actual backup on a host
|
||||
# usage: backup_host HOSTNAME [TAR_ARGUMENTS]
|
||||
backup_host() {
|
||||
message 10 "ARGS: $@"
|
||||
rhost=$1
|
||||
shift
|
||||
if [ "z${localhost}" != "z$rhost" ] ; then
|
||||
$RSH "$rhost" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" $@
|
||||
else
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
|
||||
message 10 "CMD: $CMD"
|
||||
sh -c "$CMD"
|
||||
message 10 "RC: $?"
|
||||
fi
|
||||
}
|
||||
|
||||
print_level() {
|
||||
if [ ${1-$DUMP_LEVEL} -eq 0 ]; then
|
||||
echo "Full"
|
||||
else
|
||||
echo "Level ${1-$DUMP_LEVEL}"
|
||||
fi
|
||||
}
|
||||
|
||||
prev_level() {
|
||||
print_level `expr $DUMP_LEVEL - 1` | tr A-Z a-z
|
||||
}
|
||||
|
||||
remote_run() {
|
||||
rhost=$1
|
||||
shift
|
||||
message 10 "REMOTE $rhost: $@"
|
||||
if [ "x$rhost" != "x${localhost}" ] ; then
|
||||
$RSH "${rhost}" "$@"
|
||||
else
|
||||
$*
|
||||
fi
|
||||
}
|
||||
|
||||
license() {
|
||||
cat - <<EOF
|
||||
This program is part of GNU tar
|
||||
Copyright 2004, Free Software Foundation
|
||||
|
||||
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 1, 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
EOF
|
||||
}
|
||||
9
scripts/dump-remind → scripts/dump-remind.in
Executable file → Normal file
9
scripts/dump-remind → scripts/dump-remind.in
Executable file → Normal file
@@ -13,11 +13,12 @@
|
||||
PATH="/usr/lib:/usr/local/gnubin:${PATH}"
|
||||
export PATH
|
||||
|
||||
# Get definition of TAPE_FILE, VOLNO_FILE, and so on.
|
||||
. /home/gd2/dump/backup-specs
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
. ${LIBPATH-@libexecdir@}/backup.sh
|
||||
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
mt -f "${TAPE_FILE}" offl
|
||||
MT_REWIND
|
||||
MT_OFFLINE
|
||||
|
||||
volno="`cat \"${VOLNO_FILE}\" 2> /dev/null`"
|
||||
if [ $? -ne 0 ]; then
|
||||
200
scripts/level-0
200
scripts/level-0
@@ -1,200 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run this script as root on the machine that has the tape drive, to make a
|
||||
# full (level-0) dump.
|
||||
#
|
||||
# If you give `now' as an argument, the dump is done immediately.
|
||||
# Otherwise, it waits until 1am, or until the hour given as argument.
|
||||
# Specify the hour as a number from 0 to 23.
|
||||
#
|
||||
# You must edit the file `backup-specs' to set the parameters for your site.
|
||||
|
||||
# Useful for backup-specs, in case things have to be done slightly
|
||||
# differently for different dump levels.
|
||||
DUMP_LEVEL=0
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
|
||||
# This is not the most reliable test in the world. The following might be
|
||||
# more predictable:
|
||||
#
|
||||
# whoami="`whoami`"
|
||||
# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
|
||||
# if [ "${euid}" != 0 ]; then ...
|
||||
#
|
||||
if [ ! -w / ]; then
|
||||
echo "The backup must be run as root or else some files will fail to be dumped."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
||||
. ./backup-specs
|
||||
|
||||
# Maybe sleep until around specified or default hour.
|
||||
if [ "${1}" != "now" ]; then
|
||||
if [ "${1}x" != "x" ]; then
|
||||
spec="${1}"
|
||||
else
|
||||
spec="${BACKUP_HOUR}"
|
||||
fi
|
||||
|
||||
pausetime="`date | awk '
|
||||
{
|
||||
hr = substr($4, 1, 2);
|
||||
mn = substr($4, 4, 2);
|
||||
if((hr + 0) < (spec + 0))
|
||||
print 3600 * (spec - hr) - 60 * mn;
|
||||
else
|
||||
print 3600 * (spec + (24 - hr)) - 60 * mn;
|
||||
}' spec=\"${spec}\"`"
|
||||
|
||||
clear
|
||||
echo "${SLEEP_MESSAGE}"
|
||||
sleep "${pausetime}"
|
||||
fi
|
||||
|
||||
# start doing things
|
||||
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
# to run longer than 24 hours (as may be the case if someone forgets to put
|
||||
# in the next volume of the tape in adequate time), the backup date won't
|
||||
# appear too misleading.
|
||||
startdate="`date`"
|
||||
|
||||
here="`pwd`"
|
||||
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-0''
|
||||
# They go in the subdirectory `log' of the current directory.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="log/log-`date | sed -ne '
|
||||
s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
||||
/-[0-9]$/s/\([0-9]\)$/0\1/
|
||||
/Jan/{s/Jan/01/p;q;}
|
||||
/Feb/{s/Feb/02/p;q;}
|
||||
/Mar/{s/Mar/03/p;q;}
|
||||
/Apr/{s/Apr/04/p;q;}
|
||||
/May/{s/May/05/p;q;}
|
||||
/Jun/{s/Jun/06/p;q;}
|
||||
/Jul/{s/Jul/07/p;q;}
|
||||
/Aug/{s/Aug/08/p;q;}
|
||||
/Sep/{s/Sep/09/p;q;}
|
||||
/Oct/{s/Oct/10/p;q;}
|
||||
/Nov/{s/Nov/11/p;q;}
|
||||
/Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
|
||||
|
||||
localhost="`hostname | sed -e 's/\..*//'`"
|
||||
|
||||
TAR_PART1="${TAR} -c --multi-volume --one-file-system --blocking=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
|
||||
# Make sure the log file did not already exist. Create it.
|
||||
|
||||
if [ -f "${LOGFILE}" ] ; then
|
||||
echo "Log file ${LOGFILE} already exists." 1>&2
|
||||
exit 1
|
||||
else
|
||||
touch "${LOGFILE}"
|
||||
fi
|
||||
|
||||
# Most everything below here is run in a subshell for which all output is
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
# Caveat: Some version of `mt' require `-t', not `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
set - ${BACKUP_DIRS}
|
||||
while [ $# -ne 0 ] ; do
|
||||
date="`date`"
|
||||
remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
|
||||
# This filename must be absolute; it is opened on the machine that runs tar.
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
|
||||
TAR_PART3="--label='Full backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
|
||||
|
||||
echo "Backing up ${1} at ${date}"
|
||||
|
||||
# Actually back things up.
|
||||
|
||||
if [ "z${localhost}" != "z${remotehost}" ] ; then
|
||||
rsh "${remotehost}" mkdir /etc/tar-backup > /dev/null 2>&1
|
||||
rsh "${remotehost}" rm -f /etc/tar-backup/temp.level-0
|
||||
rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
|
||||
else
|
||||
mkdir /etc/tar-backup > /dev/null 2>&1
|
||||
rm -f /etc/tar-backup/temp.level-0
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
|
||||
fi
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
if [ "z${localhost}" != "z${remotehost}" ] ; then
|
||||
rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
|
||||
fi
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
sleep 60
|
||||
shift
|
||||
done
|
||||
|
||||
# Dump any individual files requested.
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
date="`date`"
|
||||
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
|
||||
TAR_PART3="--label='Full backup of miscellaneous files at ${date}'"
|
||||
|
||||
mkdir /etc/tar-backup > /dev/null 2>&1
|
||||
rm -f /etc/tar-backup/temp.level-0
|
||||
|
||||
echo "Backing up miscellaneous files at ${date}"
|
||||
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of miscellaneous files failed."
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/misc.level-0
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
# Caveat: some versions of `mt' use `-t' instead of `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
mt -f "${TAPE_FILE}" offl
|
||||
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
|
||||
# eof
|
||||
203
scripts/level-1
203
scripts/level-1
@@ -1,203 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run this script as root on the machine that has the tape drive, to make a
|
||||
# level-1 dump containing all files changed since the last full dump.
|
||||
#
|
||||
# If you give `now' as an argument, the dump is done immediately.
|
||||
# Otherwise, it waits until 1am.
|
||||
#
|
||||
# You must edit the file `backup-specs' to set the parameters for your site.
|
||||
|
||||
# Useful for backup-specs, in case things have to be done slightly
|
||||
# differently for different dump levels.
|
||||
DUMP_LEVEL=1
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
|
||||
# This is not the most reliable test in the world. The following might be
|
||||
# more predictable:
|
||||
#
|
||||
# whoami="`whoami`"
|
||||
# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
|
||||
# if [ "${euid}" != 0 ]; then ...
|
||||
#
|
||||
if [ ! -w / ]; then
|
||||
echo "The backup must be run as root or else some files will fail to be dumped."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
||||
. ./backup-specs
|
||||
|
||||
# Maybe sleep until around specified or default hour.
|
||||
if [ "z${1}" != "znow" ]; then
|
||||
if [ "${1}x" != "x" ]; then
|
||||
spec="${1}"
|
||||
else
|
||||
spec="${BACKUP_HOUR}"
|
||||
fi
|
||||
|
||||
pausetime="`date | awk '
|
||||
{
|
||||
hr = substr($4, 1, 2);
|
||||
mn = substr($4, 4, 2);
|
||||
if((hr + 0) < (spec + 0))
|
||||
print 3600 * (spec - hr) - 60 * mn;
|
||||
else
|
||||
print 3600 * (spec + (24 - hr)) - 60 * mn;
|
||||
}' spec=\"${spec}\"`"
|
||||
|
||||
clear
|
||||
echo "${SLEEP_MESSAGE}"
|
||||
sleep "${pausetime}"
|
||||
fi
|
||||
|
||||
# start doing things
|
||||
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
# to run longer than 24 hours (as may be the case if someone forgets to put
|
||||
# in the next volume of the tape in adequate time), the backup date won't
|
||||
# appear too misleading.
|
||||
startdate="`date`"
|
||||
|
||||
here="`pwd`"
|
||||
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-1''
|
||||
# They go in the subdirectory `log' of the current directory.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="log/log-`date | sed -ne '
|
||||
s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
||||
/-[0-9]$/s/\([0-9]\)$/0\1/
|
||||
/Jan/{s/Jan/01/p;q;}
|
||||
/Feb/{s/Feb/02/p;q;}
|
||||
/Mar/{s/Mar/03/p;q;}
|
||||
/Apr/{s/Apr/04/p;q;}
|
||||
/May/{s/May/05/p;q;}
|
||||
/Jun/{s/Jun/06/p;q;}
|
||||
/Jul/{s/Jul/07/p;q;}
|
||||
/Aug/{s/Aug/08/p;q;}
|
||||
/Sep/{s/Sep/09/p;q;}
|
||||
/Oct/{s/Oct/10/p;q;}
|
||||
/Nov/{s/Nov/11/p;q;}
|
||||
/Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
|
||||
|
||||
localhost="`hostname | sed -e 's/\..*//'`"
|
||||
|
||||
TAR_PART1="${TAR} -c --multi-volume --one-file-system --blocking=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
|
||||
# Make sure the log file did not already exist. Create it.
|
||||
|
||||
if [ -f "${LOGFILE}" ] ; then
|
||||
echo "Log file ${LOGFILE} already exists." 1>&2
|
||||
exit 1
|
||||
else
|
||||
touch "${LOGFILE}"
|
||||
fi
|
||||
|
||||
# Most everything below here is run in a subshell for which all output is
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
# Caveat: Some version of `mt' require `-t', not `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
set - ${BACKUP_DIRS}
|
||||
while [ $# -ne 0 ] ; do
|
||||
date="`date`"
|
||||
remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
|
||||
# This filename must be absolute; it is opened on the machine that runs tar.
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
|
||||
TAR_PART3="--label='level 1 backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
|
||||
|
||||
echo "Backing up ${1} at ${date}"
|
||||
echo "Last full dump on this filesystem:"
|
||||
|
||||
if [ "z${remotehost}" != "z${localhost}" ] ; then
|
||||
rsh "${remotehost}" "ls -l /etc/tar-backup/${fsname}.level-0; \
|
||||
cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1"
|
||||
else
|
||||
ls -l "/etc/tar-backup/${fsname}.level-0"
|
||||
cp "/etc/tar-backup/${fsname}.level-0" /etc/tar-backup/temp.level-1
|
||||
fi
|
||||
|
||||
# Actually back things up.
|
||||
|
||||
if [ "z${remotehost}" != "z${localhost}" ] ; then
|
||||
rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
|
||||
else
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
|
||||
fi
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed."
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
if [ "z${localhost}" != "z${remotehost}" ] ; then
|
||||
rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
|
||||
fi
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
sleep 60
|
||||
shift
|
||||
done
|
||||
|
||||
# Dump any individual files requested.
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
date="`date`"
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
|
||||
TAR_PART3="--label='Incremental backup of miscellaneous files at ${date}'"
|
||||
|
||||
echo "Backing up miscellaneous files at ${date}"
|
||||
echo "Last full dump of these files:"
|
||||
ls -l /etc/tar-backup/misc.level-0
|
||||
|
||||
rm -f /etc/tar-backup/temp.level-1
|
||||
cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1
|
||||
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of miscellaneous files failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
# Caveat: some versions of `mt' use `-t' instead of `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
mt -f "${TAPE_FILE}" offl
|
||||
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
|
||||
# eof
|
||||
236
scripts/restore.in
Normal file
236
scripts/restore.in
Normal file
@@ -0,0 +1,236 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright 2004, Free Software Foundation
|
||||
#
|
||||
# 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 1, 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
. ${LIBDIR-@libexecdir@}/backup.sh
|
||||
|
||||
usage() {
|
||||
cat - <<EOF
|
||||
usage: $PROGNAME [OPTIONS] [PATTERN [PATTERN...]]
|
||||
Options are:
|
||||
|
||||
-a, --all Restore all filesystems.
|
||||
-l, --level=LEVEL Start restoring from the given backup LEVEL
|
||||
(default $DUMP_LEVEL).
|
||||
-v, --verbose[=LEVEL] Set verbosity level. Default 100.
|
||||
|
||||
Informational options:
|
||||
-h, --help Display this help message.
|
||||
-L, --license Display program license.
|
||||
-V, --version Display program version.
|
||||
|
||||
Send bug reports to @PACKAGE_BUGREPORT@.
|
||||
EOF
|
||||
}
|
||||
|
||||
unset PATTERN
|
||||
DUMP_LEVEL=0
|
||||
CMDLINE="$0 $@"
|
||||
|
||||
for opt
|
||||
do
|
||||
if [ -z "$prev" ]; then
|
||||
option=$opt
|
||||
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
|
||||
else
|
||||
option="${prev}=$opt"
|
||||
prev=""
|
||||
optarg=$opt
|
||||
fi
|
||||
case $option in
|
||||
-a|--a|--al|--all)
|
||||
RESTORE_ALL=1
|
||||
;;
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
;;
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "restore (@PACKAGE@ @VERSION@)"
|
||||
exit 0;;
|
||||
-L|--li|--lic|--lice|--licen|--licens|--license)
|
||||
license
|
||||
exit;;
|
||||
-h|--h|--he|--hel|--help)
|
||||
usage
|
||||
exit;;
|
||||
-*) bailout "Unknown option $opt. Try $PROGNAME --help for more info.";;
|
||||
*) if [ -z "$PATTERN" ]; then
|
||||
PATTERN=$opt
|
||||
else
|
||||
PATTERN="$PATTERN|$opt"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$RESTORE_ALL" ]; then
|
||||
if [ -z "$PATTERN" ]; then
|
||||
usage
|
||||
exit;
|
||||
fi
|
||||
fi
|
||||
|
||||
init_restore
|
||||
cat > $LOGFILE <<EOF
|
||||
This file contains any messages produced by $PROGNAME.
|
||||
|
||||
It was created by GNU $PROGNAME, from @PACKAGE@ (@VERSION@).
|
||||
Invocation command line was
|
||||
|
||||
\$ $CMDLINE
|
||||
|
||||
EOF
|
||||
|
||||
restore_fs()
|
||||
{
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
remotehost="`expr \"${1}\" : '\([^/][^/]*\):.*'`"
|
||||
if [ -z "$remotehost" ]; then
|
||||
remotehost=$localhost
|
||||
fi
|
||||
message 10 "fs=$fs"
|
||||
message 10 "fsname=$fsname"
|
||||
message 10 "remotehost=$remotehost"
|
||||
|
||||
LOGPAT="`level_log_name ${fsname} '[0-9]'`"
|
||||
PREFIX="`level_log_name ${fsname} ''`"
|
||||
message 10 LOGPAT=$LOGPAT
|
||||
message 10 PREFIX=$PREFIX
|
||||
LEVELS=`remote_run "${remotehost}" ls $LOGPAT |
|
||||
sed "s,$PREFIX,," | sort -n`
|
||||
message 10 "LEVELS=$LEVELS"
|
||||
|
||||
echo "Starting restore of ${1} at level $DUMP_LEVEL."
|
||||
for level in $LEVELS
|
||||
do
|
||||
if [ $level -lt $DUMP_LEVEL ]; then
|
||||
message 10 "Skipping level $level"
|
||||
continue;
|
||||
fi
|
||||
message 10 "Restoring level $level"
|
||||
|
||||
DATE=`get_dump_time $level`
|
||||
FILE="`level_log_name ${fsname} ${level}`"
|
||||
message 10 "FILE=$FILE"
|
||||
|
||||
LABEL="`print_level $level` backup of ${fs} on ${remotehost} at ${DATE}"
|
||||
${RESTORE_BEGIN-:} $level $remotehost $fs $fsname
|
||||
backup_host ${remotehost} \
|
||||
"--listed=\"$FILE\"" \
|
||||
"--label=\"$LABEL\"" \
|
||||
-C ${ROOT_FS-/}$fs
|
||||
${RESTORE_END-:} $level $remotehost $fs $fsname
|
||||
done
|
||||
}
|
||||
|
||||
restore_files()
|
||||
{
|
||||
LOGPAT="`level_log_name MISC '[0-9]'`"
|
||||
PREFIX="`level_log_name MISC ''`"
|
||||
message 10 LOGPAT=$LOGPAT
|
||||
message 10 PREFIX=$PREFIX
|
||||
LEVELS=`remote_run "${localhost}" ls $LOGPAT | sed "s,$PREFIX,," | sort -n`
|
||||
message 10 "LEVELS=$LEVELS"
|
||||
|
||||
echo "Starting restore of miscellaneous files at level $DUMP_LEVEL."
|
||||
for level in $LEVELS
|
||||
do
|
||||
if [ $level -lt $DUMP_LEVEL ]; then
|
||||
message 10 "Skipping level $level"
|
||||
continue;
|
||||
fi
|
||||
message 10 "Restoring level $level"
|
||||
|
||||
DATE=`get_dump_time $level`
|
||||
FILE="`level_log_name MISC ${level}`"
|
||||
message 10 "FILE=$FILE"
|
||||
|
||||
LABEL="`print_level $level` backup of miscellaneous files at ${DATE}"
|
||||
${RESTORE_BEGIN-:} $level $localhost MISC MISC
|
||||
backup_host ${localhost} \
|
||||
"--listed=\"$FILE\"" \
|
||||
"--label=\"$LABEL\"" \
|
||||
-C ${ROOT_FS-/} $@
|
||||
${RESTORE_END-:} $level $localhost MISC MISC
|
||||
done
|
||||
}
|
||||
|
||||
# Operation Overwiew:
|
||||
#
|
||||
# 1. Determine the time of the last backup
|
||||
# 2. Create list of incremental listings to process
|
||||
# 3. For each filesystem:
|
||||
# 3.1. Start at the requested dump level (default 0) and proceed up to
|
||||
# the last available level:
|
||||
# 3.1.1 Deduce the volume label
|
||||
# 3.1.2. Invoke [rsh] tar --listed=FILE --label=LABEL [opts] -xf $TAPE_FILE
|
||||
# 4. End
|
||||
|
||||
(message 1 "Preparing for restore"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
|
||||
for dir in ${BACKUP_DIRS}
|
||||
do
|
||||
message 1 "Processing $dir"
|
||||
case $dir in
|
||||
${PATTERN-*}) restore_fs $dir;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
message 1 "processing miscellaneous files"
|
||||
if [ -z "$PATTERN" ]; then
|
||||
restore_files
|
||||
else
|
||||
RESTORE_FILES=""
|
||||
for file in ${BACKUP_FILES}
|
||||
do
|
||||
rel_file=`expr $file : '/\(.*\)'`
|
||||
case $file in
|
||||
$PATTERN) if [ -z "$RESTORE_FILES" ]; then
|
||||
RESTORE_FILES="$rel_file"
|
||||
else
|
||||
RESTORE_FILES="$RESTORE_FILES $rel_file"
|
||||
fi;;
|
||||
esac
|
||||
done
|
||||
[ -z "$RESTORE_FILES" ] || restore_files $RESTORE_FILES
|
||||
fi
|
||||
|
||||
fi) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
# EOF
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11
scripts/tarcat
Executable file
11
scripts/tarcat
Executable file
@@ -0,0 +1,11 @@
|
||||
#! /bin/sh
|
||||
# Usage: tarcat volume1 volume2 ...
|
||||
# concatenates a GNU tar multi-volume archive into a single tar archive.
|
||||
# Author: Bruno Haible <bruno@clisp.org>
|
||||
|
||||
cat "$1"
|
||||
shift
|
||||
for f
|
||||
do
|
||||
dd skip=1 if="$f"
|
||||
done
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/sh
|
||||
# start doing things
|
||||
TOBACKUP="albert:/"
|
||||
|
||||
HOST=`hostname | sed 's/\..*//'`
|
||||
TAPEFILE=/dev/rfd0a
|
||||
LOGFILE=tar-out
|
||||
BLOCKING=20
|
||||
TAR_PART1="/usr/local/bin/tar clbfVM $BLOCKING"
|
||||
|
||||
rm -f $LOGFILE
|
||||
|
||||
mt -f $TAPEFILE rewind
|
||||
|
||||
host=`echo $TOBACKUP | sed 's/:.*$//'`;
|
||||
fs=`echo $TOBACKUP | sed 's/^.*://'`;
|
||||
date=`date`;
|
||||
fsname=`echo $TOBACKUP | sed 's/\//:/g'`
|
||||
|
||||
TAR_PART2="'Weekly backup of $fs on $host at $date' -C $fs ."
|
||||
echo Backing up $TOBACKUP at $date | tee -a $LOGFILE
|
||||
|
||||
# Actually back things up.
|
||||
|
||||
if [ $HOST != $host ] ; then
|
||||
rsh $host $TAR_PART1 $HOST:$TAPEFILE $TAR_PART2
|
||||
else
|
||||
sh -c "exec $TAR_PART1 $TAPEFILE $TAR_PART2"
|
||||
fi
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo Backup of $TOBACKUP failed. | tee -a $LOGFILE
|
||||
echo mts at time of failure | tee -a $LOGFILE
|
||||
mts -t $TAPEFILE | tee -a $LOGFILE
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
echo $date > $fsname.lasttar
|
||||
fi
|
||||
sleep 60;
|
||||
|
||||
mt -f $TAPEFILE rewind
|
||||
mt -f $TAPEFILE offl
|
||||
@@ -3,4 +3,5 @@ Makefile
|
||||
localedir.h
|
||||
rmt
|
||||
tar
|
||||
.deps
|
||||
.deps
|
||||
.gdbinit
|
||||
|
||||
@@ -19,11 +19,8 @@
|
||||
## 02111-1307, USA.
|
||||
|
||||
bin_PROGRAMS = tar
|
||||
libexec_PROGRAMS = @RMT@
|
||||
EXTRA_PROGRAMS = rmt
|
||||
|
||||
noinst_HEADERS = arith.h common.h rmt.h system.h tar.h
|
||||
rmt_SOURCES = rmt.c
|
||||
noinst_HEADERS = arith.h common.h tar.h
|
||||
tar_SOURCES = \
|
||||
buffer.c\
|
||||
compare.c\
|
||||
@@ -36,22 +33,16 @@ tar_SOURCES = \
|
||||
mangle.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
rtapelib.c\
|
||||
sparse.c\
|
||||
system.c\
|
||||
tar.c\
|
||||
update.c\
|
||||
utf8.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I$(top_srcdir)/lib -I../lib
|
||||
INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib
|
||||
|
||||
DISTCLEANFILES = localedir.h
|
||||
localedir.h : Makefile
|
||||
echo '#define LOCALEDIR "$(localedir)"' >$@
|
||||
rmt.o tar.o : localedir.h
|
||||
tar.o: ../lib/localedir.h
|
||||
|
||||
LDADD = ../lib/libtar.a $(LIBINTL)
|
||||
LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
|
||||
|
||||
rmt_LDADD = $(LDADD) $(LIB_SETSOCKOPT)
|
||||
tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
|
||||
317
src/buffer.c
317
src/buffer.c
@@ -19,7 +19,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "rmt.h"
|
||||
#include <rmt.h>
|
||||
|
||||
/* Number of retries before giving up on read. */
|
||||
#define READ_ERROR_MAX 10
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
static tarlong prev_written; /* bytes written on previous volumes */
|
||||
static tarlong bytes_written; /* bytes written on this volume */
|
||||
static void *record_buffer; /* allocated memory */
|
||||
|
||||
/* FIXME: The following variables should ideally be static to this
|
||||
module. However, this cannot be done yet. The cleanup continues! */
|
||||
@@ -66,16 +67,19 @@ static pid_t child_pid;
|
||||
static int read_error_count;
|
||||
|
||||
/* Have we hit EOF yet? */
|
||||
static int hit_eof;
|
||||
static bool hit_eof;
|
||||
|
||||
/* Checkpointing counter */
|
||||
static int checkpoint;
|
||||
|
||||
static bool read_full_records = false;
|
||||
static bool reading_from_pipe = false;
|
||||
|
||||
/* We're reading, but we just read the last block and it's time to update.
|
||||
Declared in update.c
|
||||
|
||||
As least EXTERN like this one as possible. (?? --gray)
|
||||
FIXME: Either eliminate it or move it to common.h.
|
||||
FIXME: Either eliminate it or move it to common.h.
|
||||
*/
|
||||
extern bool time_to_start_writing;
|
||||
|
||||
@@ -109,11 +113,139 @@ static off_t real_s_sizeleft;
|
||||
/* Functions. */
|
||||
|
||||
void
|
||||
clear_read_error_count ()
|
||||
clear_read_error_count (void)
|
||||
{
|
||||
read_error_count = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Time-related functions */
|
||||
|
||||
double duration;
|
||||
|
||||
void
|
||||
set_start_time ()
|
||||
{
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
|
||||
#endif
|
||||
start_time = time (0);
|
||||
}
|
||||
|
||||
void
|
||||
compute_duration ()
|
||||
{
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
struct timespec now;
|
||||
if (clock_gettime (CLOCK_REALTIME, &now) == 0)
|
||||
duration += ((now.tv_sec - start_timespec.tv_sec)
|
||||
+ (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
|
||||
else
|
||||
#endif
|
||||
duration += time (NULL) - start_time;
|
||||
set_start_time ();
|
||||
}
|
||||
|
||||
|
||||
/* Compression detection */
|
||||
|
||||
enum compress_type {
|
||||
ct_none,
|
||||
ct_compress,
|
||||
ct_gzip,
|
||||
ct_bzip2
|
||||
};
|
||||
|
||||
struct zip_magic
|
||||
{
|
||||
enum compress_type type;
|
||||
unsigned char *magic;
|
||||
size_t length;
|
||||
char *program;
|
||||
char *option;
|
||||
};
|
||||
|
||||
static struct zip_magic magic[] = {
|
||||
{ ct_none, },
|
||||
{ ct_compress, "\037\235", 2, "compress", "-Z" },
|
||||
{ ct_gzip, "\037\213", 2, "gzip", "-z" },
|
||||
{ ct_bzip2, "BZh", 3, "bzip2", "-j" },
|
||||
};
|
||||
|
||||
#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
|
||||
|
||||
#define compress_option(t) magic[t].option
|
||||
#define compress_program(t) magic[t].program
|
||||
|
||||
/* Check if the file FD is a compressed archive. FD is guaranteed to
|
||||
represent a local file */
|
||||
enum compress_type
|
||||
check_compressed_archive (int fd)
|
||||
{
|
||||
struct zip_magic *p;
|
||||
size_t status;
|
||||
union block buf;
|
||||
|
||||
status = read (fd, &buf, sizeof buf);
|
||||
if (status != sizeof buf)
|
||||
{
|
||||
archive_read_error ();
|
||||
FATAL_ERROR ((0, 0, _("Quitting now.")));
|
||||
}
|
||||
|
||||
lseek (fd, 0, SEEK_SET); /* This will fail if fd==0, but that does not
|
||||
matter, since we do not handle compressed
|
||||
stdin anyway */
|
||||
|
||||
if (tar_checksum (&buf) == HEADER_SUCCESS)
|
||||
/* Probably a valid header */
|
||||
return ct_none;
|
||||
|
||||
for (p = magic + 1; p < magic + NMAGIC; p++)
|
||||
if (memcmp (buf.buffer, p->magic, p->length) == 0)
|
||||
return p->type;
|
||||
|
||||
return ct_none;
|
||||
}
|
||||
|
||||
/* Open an archive named archive_name_array[0]. Detect if it is
|
||||
a compressed archive of known type and use corresponding decompression
|
||||
program if so */
|
||||
int
|
||||
open_compressed_archive ()
|
||||
{
|
||||
enum compress_type type;
|
||||
int fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
if (fd == -1 || _isrmt (fd))
|
||||
return fd;
|
||||
|
||||
type = check_compressed_archive (fd);
|
||||
|
||||
if (type == ct_none)
|
||||
{
|
||||
if (rmtlseek (fd, (off_t) 0, SEEK_CUR) != 0)
|
||||
{
|
||||
/* Archive may be not seekable. Reopen it. */
|
||||
rmtclose (fd);
|
||||
fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* FD is not needed any more */
|
||||
rmtclose (fd);
|
||||
|
||||
/* Open compressed archive */
|
||||
use_compress_program_option = compress_program (type);
|
||||
child_pid = sys_child_open_for_uncompress ();
|
||||
read_full_records = reading_from_pipe = true;
|
||||
|
||||
return archive;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_total_written (void)
|
||||
{
|
||||
@@ -121,25 +253,16 @@ print_total_written (void)
|
||||
char bytes[sizeof (tarlong) * CHAR_BIT];
|
||||
char abbr[LONGEST_HUMAN_READABLE + 1];
|
||||
char rate[LONGEST_HUMAN_READABLE + 1];
|
||||
double seconds;
|
||||
|
||||
int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
|
||||
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
struct timespec now;
|
||||
if (clock_gettime (CLOCK_REALTIME, &now) == 0)
|
||||
seconds = ((now.tv_sec - start_timespec.tv_sec)
|
||||
+ (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
|
||||
else
|
||||
#endif
|
||||
seconds = time (0) - start_time;
|
||||
|
||||
sprintf (bytes, TARLONG_FORMAT, written);
|
||||
|
||||
/* 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 < seconds && written / seconds < (uintmax_t) -1
|
||||
? human_readable (written / seconds, rate, human_opts, 1, 1)
|
||||
(0 < duration && written / duration < (uintmax_t) -1
|
||||
? human_readable (written / duration, rate, human_opts, 1, 1)
|
||||
: "?"));
|
||||
}
|
||||
|
||||
@@ -156,7 +279,7 @@ reset_eof (void)
|
||||
{
|
||||
if (hit_eof)
|
||||
{
|
||||
hit_eof = 0;
|
||||
hit_eof = false;
|
||||
current_block = record_start;
|
||||
record_end = record_start + blocking_factor;
|
||||
access_mode = ACCESS_WRITE;
|
||||
@@ -176,7 +299,7 @@ find_next_block (void)
|
||||
flush_archive ();
|
||||
if (current_block == record_end)
|
||||
{
|
||||
hit_eof = 1;
|
||||
hit_eof = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -270,29 +393,28 @@ open_archive (enum access_mode wanted_access)
|
||||
save_name = 0;
|
||||
real_s_name = 0;
|
||||
|
||||
record_start =
|
||||
page_aligned_alloc (&record_buffer,
|
||||
(record_size
|
||||
+ (multi_volume_option ? 2 * BLOCKSIZE : 0)));
|
||||
if (multi_volume_option)
|
||||
{
|
||||
record_start = valloc (record_size + (2 * BLOCKSIZE));
|
||||
if (record_start)
|
||||
record_start += 2;
|
||||
}
|
||||
else
|
||||
record_start = valloc (record_size);
|
||||
if (!record_start)
|
||||
FATAL_ERROR ((0, 0, _("Cannot allocate memory for blocking factor %d"),
|
||||
blocking_factor));
|
||||
record_start += 2;
|
||||
|
||||
current_block = record_start;
|
||||
record_end = record_start + blocking_factor;
|
||||
/* When updating the archive, we start with reading. */
|
||||
access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
|
||||
|
||||
read_full_records = read_full_records_option;
|
||||
reading_from_pipe = false;
|
||||
|
||||
if (use_compress_program_option)
|
||||
{
|
||||
switch (wanted_access)
|
||||
{
|
||||
case ACCESS_READ:
|
||||
child_pid = sys_child_open_for_uncompress ();
|
||||
read_full_records = reading_from_pipe = true;
|
||||
break;
|
||||
|
||||
case ACCESS_WRITE:
|
||||
@@ -310,14 +432,24 @@ open_archive (enum access_mode wanted_access)
|
||||
}
|
||||
else if (strcmp (archive_name_array[0], "-") == 0)
|
||||
{
|
||||
read_full_records_option = 1; /* could be a pipe, be safe */
|
||||
read_full_records = true; /* could be a pipe, be safe */
|
||||
if (verify_option)
|
||||
FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
|
||||
|
||||
switch (wanted_access)
|
||||
{
|
||||
case ACCESS_READ:
|
||||
archive = STDIN_FILENO;
|
||||
{
|
||||
enum compress_type type;
|
||||
|
||||
archive = STDIN_FILENO;
|
||||
|
||||
type = check_compressed_archive (archive);
|
||||
if (type != ct_none)
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("Archive is compressed. Use %s option"),
|
||||
compress_option (type)));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACCESS_WRITE:
|
||||
@@ -339,8 +471,7 @@ open_archive (enum access_mode wanted_access)
|
||||
switch (wanted_access)
|
||||
{
|
||||
case ACCESS_READ:
|
||||
archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
archive = open_compressed_archive ();
|
||||
break;
|
||||
|
||||
case ACCESS_WRITE:
|
||||
@@ -408,8 +539,10 @@ open_archive (enum access_mode wanted_access)
|
||||
else
|
||||
strcpy (record_start->header.name, volume_label_option);
|
||||
|
||||
assign_string (¤t_stat_info.file_name, record_start->header.name);
|
||||
current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name);
|
||||
assign_string (¤t_stat_info.file_name,
|
||||
record_start->header.name);
|
||||
current_stat_info.had_trailing_slash =
|
||||
strip_trailing_slashes (current_stat_info.file_name);
|
||||
|
||||
record_start->header.typeflag = GNUTYPE_VOLHDR;
|
||||
TIME_TO_CHARS (start_time, record_start->header.mtime);
|
||||
@@ -512,17 +645,24 @@ flush_write (void)
|
||||
if (volume_label_option)
|
||||
record_start++;
|
||||
|
||||
if (strlen (real_s_name) > NAME_FIELD_SIZE)
|
||||
FATAL_ERROR ((0, 0,
|
||||
_("%s: file name too long to be stored in a GNU multivolume header"),
|
||||
quotearg_colon (real_s_name)));
|
||||
|
||||
memset (record_start, 0, BLOCKSIZE);
|
||||
|
||||
/* FIXME: Michael P Urban writes: [a long name file] is being written
|
||||
when a new volume rolls around [...] Looks like the wrong value is
|
||||
being preserved in real_s_name, though. */
|
||||
|
||||
strcpy (record_start->header.name, real_s_name);
|
||||
strncpy (record_start->header.name, real_s_name, NAME_FIELD_SIZE);
|
||||
record_start->header.typeflag = GNUTYPE_MULTIVOL;
|
||||
|
||||
OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
|
||||
OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
|
||||
record_start->oldgnu_header.offset);
|
||||
|
||||
tmp = verbose_option;
|
||||
verbose_option = 0;
|
||||
finish_header (¤t_stat_info, record_start, -1);
|
||||
@@ -597,7 +737,7 @@ archive_read_error (void)
|
||||
}
|
||||
|
||||
static void
|
||||
short_read (ssize_t status)
|
||||
short_read (size_t status)
|
||||
{
|
||||
size_t left; /* bytes left */
|
||||
char *more; /* pointer to next byte to read */
|
||||
@@ -606,26 +746,29 @@ short_read (ssize_t status)
|
||||
left = record_size - status;
|
||||
|
||||
while (left % BLOCKSIZE != 0
|
||||
|| (left && status && read_full_records_option))
|
||||
|| (left && status && read_full_records))
|
||||
{
|
||||
if (status)
|
||||
while ((status = rmtread (archive, more, left)) < 0)
|
||||
while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
|
||||
archive_read_error ();
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
WARN((0, 0, _("Read %s bytes from %s"),
|
||||
STRINGIFY_BIGINT (record_size - left, buf),
|
||||
*archive_name_cursor));
|
||||
if (!reading_from_pipe)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
WARN((0, 0, _("Read %s bytes from %s"),
|
||||
STRINGIFY_BIGINT (record_size - left, buf),
|
||||
*archive_name_cursor));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (! read_full_records_option)
|
||||
|
||||
if (! read_full_records)
|
||||
{
|
||||
unsigned long rest = record_size - left;
|
||||
|
||||
|
||||
FATAL_ERROR ((0, 0,
|
||||
ngettext ("Unaligned block (%lu byte) in archive",
|
||||
"Unaligned block (%lu bytes) in archive",
|
||||
@@ -642,8 +785,8 @@ short_read (ssize_t status)
|
||||
/* FIXME: for size=0, multi-volume support. On the first record, warn
|
||||
about the problem. */
|
||||
|
||||
if (!read_full_records_option && verbose_option
|
||||
&& record_start_block == 0 && status > 0)
|
||||
if (!read_full_records && verbose_option > 1
|
||||
&& record_start_block == 0 && status != 0)
|
||||
{
|
||||
unsigned long rsize = (record_size - left) / BLOCKSIZE;
|
||||
WARN ((0, 0,
|
||||
@@ -661,7 +804,7 @@ short_read (ssize_t status)
|
||||
void
|
||||
flush_read (void)
|
||||
{
|
||||
ssize_t status; /* result from system call */
|
||||
size_t status; /* result from system call */
|
||||
|
||||
if (checkpoint_option && !(++checkpoint % 10))
|
||||
WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
|
||||
@@ -703,9 +846,14 @@ flush_read (void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* The condition below used to include
|
||||
|| (status > 0 && !read_full_records)
|
||||
This is incorrect since even if new_volume() succeeds, the
|
||||
subsequent call to rmtread will overwrite the chunk of data
|
||||
already read in the buffer, so the processing will fail */
|
||||
|
||||
if ((status == 0
|
||||
|| (status < 0 && errno == ENOSPC)
|
||||
|| (status > 0 && !read_full_records_option))
|
||||
|| (status == SAFE_READ_ERROR && errno == ENOSPC))
|
||||
&& multi_volume_option)
|
||||
{
|
||||
union block *cursor;
|
||||
@@ -726,12 +874,12 @@ flush_read (void)
|
||||
break;
|
||||
}
|
||||
|
||||
while ((status =
|
||||
rmtread (archive, record_start->buffer, record_size)) < 0)
|
||||
while ((status = rmtread (archive, record_start->buffer, record_size))
|
||||
== SAFE_READ_ERROR)
|
||||
archive_read_error ();
|
||||
|
||||
|
||||
if (status != record_size)
|
||||
short_read (status);
|
||||
short_read (status);
|
||||
|
||||
cursor = record_start;
|
||||
|
||||
@@ -760,7 +908,7 @@ flush_read (void)
|
||||
{
|
||||
uintmax_t s1, s2;
|
||||
if (cursor->header.typeflag != GNUTYPE_MULTIVOL
|
||||
|| strcmp (cursor->header.name, real_s_name))
|
||||
|| strncmp (cursor->header.name, real_s_name, NAME_FIELD_SIZE))
|
||||
{
|
||||
WARN ((0, 0, _("%s is not continued on this volume"),
|
||||
quote (real_s_name)));
|
||||
@@ -799,7 +947,7 @@ flush_read (void)
|
||||
records_read++;
|
||||
return;
|
||||
}
|
||||
else if (status < 0)
|
||||
else if (status == SAFE_READ_ERROR)
|
||||
{
|
||||
archive_read_error ();
|
||||
goto error_loop; /* try again */
|
||||
@@ -881,6 +1029,42 @@ backspace_output (void)
|
||||
}
|
||||
}
|
||||
|
||||
off_t
|
||||
seek_archive (off_t size)
|
||||
{
|
||||
off_t start = current_block_ordinal ();
|
||||
off_t offset;
|
||||
off_t nrec, nblk;
|
||||
off_t skipped = (blocking_factor - (current_block - record_start));
|
||||
|
||||
size -= skipped * BLOCKSIZE;
|
||||
|
||||
if (size < record_size)
|
||||
return 0;
|
||||
/* FIXME: flush? */
|
||||
|
||||
/* Compute number of records to skip */
|
||||
nrec = size / record_size;
|
||||
offset = rmtlseek (archive, nrec * record_size, SEEK_CUR);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
if (offset % record_size)
|
||||
FATAL_ERROR ((0, 0, _("rmtlseek not stopped at a record boundary")));
|
||||
|
||||
/* Convert to number of records */
|
||||
offset /= BLOCKSIZE;
|
||||
/* Compute number of skipped blocks */
|
||||
nblk = offset - start;
|
||||
|
||||
/* Update buffering info */
|
||||
records_read += nblk / blocking_factor;
|
||||
record_start_block = offset - blocking_factor;
|
||||
current_block = record_end;
|
||||
|
||||
return nblk;
|
||||
}
|
||||
|
||||
/* Close the archive file. */
|
||||
void
|
||||
close_archive (void)
|
||||
@@ -889,21 +1073,22 @@ close_archive (void)
|
||||
flush_archive ();
|
||||
|
||||
sys_drain_input_pipe ();
|
||||
|
||||
if (verify_option)
|
||||
|
||||
compute_duration ();
|
||||
if (verify_option)
|
||||
verify_volume ();
|
||||
|
||||
if (rmtclose (archive) != 0)
|
||||
close_warn (*archive_name_cursor);
|
||||
|
||||
sys_wait_for_child (child_pid);
|
||||
|
||||
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
if (save_name)
|
||||
free (save_name);
|
||||
if (real_s_name)
|
||||
free (real_s_name);
|
||||
free (multi_volume_option ? record_start - 2 : record_start);
|
||||
free (record_buffer);
|
||||
}
|
||||
|
||||
/* Called to initialize the global volume number. */
|
||||
@@ -949,7 +1134,7 @@ closeout_volume_number (void)
|
||||
Return nonzero on success.
|
||||
*/
|
||||
static bool
|
||||
new_volume (enum access_mode access)
|
||||
new_volume (enum access_mode mode)
|
||||
{
|
||||
static FILE *read_file;
|
||||
static int looped;
|
||||
@@ -1071,14 +1256,14 @@ new_volume (enum access_mode access)
|
||||
|
||||
if (strcmp (archive_name_cursor[0], "-") == 0)
|
||||
{
|
||||
read_full_records_option = true;
|
||||
read_full_records = true;
|
||||
archive = STDIN_FILENO;
|
||||
}
|
||||
else if (verify_option)
|
||||
archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
|
||||
rsh_command_option);
|
||||
else
|
||||
switch (access)
|
||||
switch (mode)
|
||||
{
|
||||
case ACCESS_READ:
|
||||
archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
|
||||
@@ -1101,7 +1286,7 @@ new_volume (enum access_mode access)
|
||||
if (archive < 0)
|
||||
{
|
||||
open_warn (*archive_name_cursor);
|
||||
if (!verify_option && access == ACCESS_WRITE && backup_option)
|
||||
if (!verify_option && mode == ACCESS_WRITE && backup_option)
|
||||
undo_last_backup ();
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
111
src/common.h
111
src/common.h
@@ -1,7 +1,7 @@
|
||||
/* Common declarations for the tar program.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003 Free Software Foundation, Inc.
|
||||
2003, 2004 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
|
||||
@@ -38,11 +38,6 @@
|
||||
/* Some various global definitions. */
|
||||
|
||||
/* Name of file to use for interacting with user. */
|
||||
#if MSDOS
|
||||
# define TTY_NAME "con"
|
||||
#else
|
||||
# define TTY_NAME "/dev/tty"
|
||||
#endif
|
||||
|
||||
/* GLOBAL is defined to empty in tar.c only, and left alone in other *.c
|
||||
modules. Here, we merely set it to "extern" if it is not already set.
|
||||
@@ -85,6 +80,7 @@ GLOBAL int exit_status;
|
||||
#include <modechange.h>
|
||||
#include <quote.h>
|
||||
#include <safe-read.h>
|
||||
#include <timespec.h>
|
||||
|
||||
/* Log base 2 of common values. */
|
||||
#define LG_8 3
|
||||
@@ -128,6 +124,9 @@ GLOBAL size_t record_size;
|
||||
|
||||
GLOBAL bool absolute_names_option;
|
||||
|
||||
/* Display file times in UTC */
|
||||
GLOBAL bool utc_option;
|
||||
|
||||
/* This variable tells how to interpret newer_mtime_option, below. If zero,
|
||||
files get archived if their mtime is not less than newer_mtime_option.
|
||||
If nonzero, files get archived if *either* their ctime or mtime is not less
|
||||
@@ -156,11 +155,12 @@ GLOBAL int check_links_option;
|
||||
/* Patterns that match file names to be excluded. */
|
||||
GLOBAL struct exclude *excluded;
|
||||
|
||||
/* Exclude directories containing a cache directory tag. */
|
||||
GLOBAL bool exclude_caches_option;
|
||||
|
||||
/* Specified file containing names to work on. */
|
||||
GLOBAL const char *files_from_option;
|
||||
|
||||
GLOBAL bool force_local_option;
|
||||
|
||||
/* Specified value to be put into tar file in place of stat () results, or
|
||||
just -1 if such an override should not take place. */
|
||||
GLOBAL gid_t group_option;
|
||||
@@ -181,11 +181,12 @@ GLOBAL uintmax_t occurrence_option;
|
||||
|
||||
enum old_files
|
||||
{
|
||||
DEFAULT_OLD_FILES, /* default */
|
||||
DEFAULT_OLD_FILES, /* default */
|
||||
NO_OVERWRITE_DIR_OLD_FILES, /* --no-overwrite-dir */
|
||||
OVERWRITE_OLD_FILES, /* --overwrite */
|
||||
UNLINK_FIRST_OLD_FILES, /* --unlink-first */
|
||||
KEEP_OLD_FILES /* --keep-old-files */
|
||||
OVERWRITE_OLD_FILES, /* --overwrite */
|
||||
UNLINK_FIRST_OLD_FILES, /* --unlink-first */
|
||||
KEEP_OLD_FILES, /* --keep-old-files */
|
||||
KEEP_NEWER_FILES /* --keep-newer-files */
|
||||
};
|
||||
GLOBAL enum old_files old_files_option;
|
||||
|
||||
@@ -197,13 +198,23 @@ GLOBAL struct mode_change *mode_option;
|
||||
|
||||
GLOBAL bool multi_volume_option;
|
||||
|
||||
/* The same variable hold the time, whether mtime or ctime. Just fake a
|
||||
/* The same variable holds the time, whether mtime or ctime. Just fake a
|
||||
non-existing option, for making the code clearer, elsewhere. */
|
||||
#define newer_ctime_option newer_mtime_option
|
||||
|
||||
/* Specified threshold date and time. Files having an older time stamp
|
||||
do not get archived (also see after_date_option above). */
|
||||
GLOBAL time_t newer_mtime_option;
|
||||
GLOBAL struct timespec newer_mtime_option;
|
||||
|
||||
/* Return true if newer_mtime_option is initialized. */
|
||||
#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
|
||||
|
||||
/* Return true if the struct stat ST's M time is less than
|
||||
newer_mtime_option. */
|
||||
#define OLDER_STAT_TIME(st, m) \
|
||||
((st).st_##m##time < newer_mtime_option.tv_sec \
|
||||
|| ((st).st_##m##time == newer_mtime_option.tv_sec \
|
||||
&& TIMESPEC_NS ((st).st_##m##tim) < newer_mtime_option.tv_nsec))
|
||||
|
||||
/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
|
||||
GLOBAL int recursion_option;
|
||||
@@ -222,6 +233,9 @@ GLOBAL bool read_full_records_option;
|
||||
|
||||
GLOBAL bool remove_files_option;
|
||||
|
||||
/* Specified rmt command. */
|
||||
GLOBAL const char *rmt_command_option;
|
||||
|
||||
/* Specified remote shell command. */
|
||||
GLOBAL const char *rsh_command_option;
|
||||
|
||||
@@ -233,9 +247,9 @@ GLOBAL int same_owner_option;
|
||||
/* If positive, preserve permissions when extracting. */
|
||||
GLOBAL int same_permissions_option;
|
||||
|
||||
/* When set, strip the given number of path elements from the file name
|
||||
/* When set, strip the given number of file name components from the file name
|
||||
before extracting */
|
||||
GLOBAL size_t strip_path_elements;
|
||||
GLOBAL size_t strip_name_components;
|
||||
|
||||
GLOBAL bool show_omitted_dirs_option;
|
||||
|
||||
@@ -313,6 +327,10 @@ struct name
|
||||
GLOBAL dev_t ar_dev;
|
||||
GLOBAL ino_t ar_ino;
|
||||
|
||||
GLOBAL bool seekable_archive;
|
||||
|
||||
GLOBAL dev_t root_device;
|
||||
|
||||
|
||||
/* Declarations for each module. */
|
||||
|
||||
@@ -352,6 +370,8 @@ void clear_read_error_count (void);
|
||||
void xclose (int fd);
|
||||
void archive_write_error (ssize_t) __attribute__ ((noreturn));
|
||||
void archive_read_error (void);
|
||||
off_t seek_archive (off_t size);
|
||||
void set_start_time (void);
|
||||
|
||||
/* Module create.c. */
|
||||
|
||||
@@ -363,7 +383,7 @@ enum dump_status
|
||||
dump_status_not_implemented
|
||||
};
|
||||
|
||||
bool file_dumpable_p (struct tar_stat_info *stat);
|
||||
bool file_dumpable_p (struct tar_stat_info *);
|
||||
void create_archive (void);
|
||||
void pad_archive (off_t size_left);
|
||||
void dump_file (char *, int, dev_t);
|
||||
@@ -422,7 +442,7 @@ void delete_archive_members (void);
|
||||
char *get_directory_contents (char *, dev_t);
|
||||
void read_directory_file (void);
|
||||
void write_directory_file (void);
|
||||
void gnu_restore (char const *);
|
||||
void purge_directory (char const *);
|
||||
|
||||
/* Module list.c. */
|
||||
|
||||
@@ -481,6 +501,7 @@ 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);
|
||||
enum read_header tar_checksum (union block *header);
|
||||
void skip_file (off_t);
|
||||
void skip_member (void);
|
||||
|
||||
@@ -500,7 +521,15 @@ enum remove_option
|
||||
{
|
||||
ORDINARY_REMOVE_OPTION,
|
||||
RECURSIVE_REMOVE_OPTION,
|
||||
WANT_DIRECTORY_REMOVE_OPTION
|
||||
|
||||
/* FIXME: The following value is never used. It seems to be intended
|
||||
as a placeholder for a hypothetical option that should instruct tar
|
||||
to recursively remove subdirectories in purge_directory(),
|
||||
as opposed to the functionality of --recursive-unlink
|
||||
(RECURSIVE_REMOVE_OPTION value), which removes them in
|
||||
prepare_to_extract() phase. However, with the addition of more
|
||||
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);
|
||||
@@ -531,7 +560,7 @@ void open_diag (char const *name);
|
||||
void read_error (char const *);
|
||||
void read_error_details (char const *, off_t, size_t);
|
||||
void read_fatal (char const *) __attribute__ ((noreturn));
|
||||
void read_fatal_details (char const *, off_t, size_t);
|
||||
void read_fatal_details (char const *, off_t, size_t) __attribute__ ((noreturn));
|
||||
void read_warn_details (char const *, off_t, size_t);
|
||||
void read_diag_details (char const *name, off_t offset, size_t size);
|
||||
void readlink_error (char const *);
|
||||
@@ -555,7 +584,7 @@ void unlink_error (char const *);
|
||||
void utime_error (char const *);
|
||||
void waitpid_error (char const *);
|
||||
void write_error (char const *);
|
||||
void write_error_details (char const *, ssize_t, size_t);
|
||||
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)
|
||||
__attribute__ ((noreturn));
|
||||
@@ -563,18 +592,20 @@ void write_fatal_details (char const *, ssize_t, size_t)
|
||||
pid_t xfork (void);
|
||||
void xpipe (int[2]);
|
||||
|
||||
void *page_aligned_alloc (void **, size_t);
|
||||
|
||||
/* Module names.c. */
|
||||
|
||||
extern struct name *gnu_list_name;
|
||||
|
||||
void gid_to_gname (gid_t, char **gname);
|
||||
int gname_to_gid (char *gname, gid_t *);
|
||||
int gname_to_gid (char const *, gid_t *);
|
||||
void uid_to_uname (uid_t, char **uname);
|
||||
int uname_to_uid (char *uname, uid_t *);
|
||||
int uname_to_uid (char const *, uid_t *);
|
||||
|
||||
void init_names (void);
|
||||
void name_add (const char *);
|
||||
void name_init (int, char *const *);
|
||||
void name_init (void);
|
||||
void name_term (void);
|
||||
char *name_next (int);
|
||||
void name_close (void);
|
||||
@@ -595,9 +626,12 @@ bool excluded_name (char const *);
|
||||
|
||||
void add_avoided_name (char const *);
|
||||
bool is_avoided_name (char const *);
|
||||
bool is_individual_file (char const *);
|
||||
|
||||
bool contains_dot_dot (char const *);
|
||||
|
||||
bool removed_prefixes_p (void);
|
||||
|
||||
#define ISFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
(c)->found_count == occurrence_option)
|
||||
#define WASFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
@@ -605,11 +639,14 @@ bool contains_dot_dot (char const *);
|
||||
|
||||
/* Module tar.c. */
|
||||
|
||||
void usage (int);
|
||||
|
||||
int confirm (const char *, const char *);
|
||||
void request_stdin (const char *);
|
||||
|
||||
void tar_stat_init (struct tar_stat_info *st);
|
||||
void tar_stat_destroy (struct tar_stat_info *st);
|
||||
void usage (int) __attribute__ ((noreturn));
|
||||
|
||||
/* Module update.c. */
|
||||
|
||||
@@ -620,16 +657,22 @@ void update_archive (void);
|
||||
/* Module xheader.c. */
|
||||
|
||||
void xheader_decode (struct tar_stat_info *);
|
||||
void xheader_decode_global (void);
|
||||
void xheader_store (char const *, struct tar_stat_info const *, void *);
|
||||
void xheader_read (union block *, size_t);
|
||||
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 *);
|
||||
char *xheader_xhdr_name (struct tar_stat_info *st);
|
||||
char *xheader_ghdr_name (void);
|
||||
void xheader_write (char, char *, struct xheader *);
|
||||
void xheader_write_global (void);
|
||||
void xheader_set_option (char *string);
|
||||
|
||||
/* Module system.c */
|
||||
|
||||
void sys_stat_nanoseconds (struct tar_stat_info *stat);
|
||||
void sys_stat_nanoseconds (struct tar_stat_info *);
|
||||
void sys_detect_dev_null_output (void);
|
||||
void sys_save_archive_dev_ino (void);
|
||||
void sys_drain_input_pipe (void);
|
||||
@@ -640,17 +683,23 @@ bool sys_compare_gid (struct stat *a, struct stat *b);
|
||||
bool sys_file_is_archive (struct tar_stat_info *p);
|
||||
bool sys_compare_links (struct stat *link_data, struct stat *stat_data);
|
||||
int sys_truncate (int fd);
|
||||
void sys_reset_uid_gid (void);
|
||||
pid_t sys_child_open_for_compress (void);
|
||||
pid_t sys_child_open_for_uncompress (void);
|
||||
ssize_t sys_write_archive_buffer (void);
|
||||
size_t sys_write_archive_buffer (void);
|
||||
bool sys_get_archive_stat (void);
|
||||
|
||||
/* Module compare.c */
|
||||
void report_difference (struct tar_stat_info *st, const char *message, ...);
|
||||
|
||||
/* Module sparse.c */
|
||||
bool sparse_file_p (struct tar_stat_info *stat);
|
||||
enum dump_status sparse_dump_file (int fd, struct tar_stat_info *stat);
|
||||
enum dump_status sparse_extract_file (int fd, struct tar_stat_info *stat, off_t *size);
|
||||
bool sparse_diff_file (int fd, struct tar_stat_info *stat);
|
||||
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 *);
|
||||
|
||||
/* Module utf8.c */
|
||||
bool string_ascii_p (const char *str);
|
||||
bool utf8_convert (bool to_utf, char const *input, char **output);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Diff files from a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003 Free Software Foundation, Inc.
|
||||
2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1987-04-30.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#if HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
@@ -38,7 +38,7 @@ struct utimbuf
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "rmt.h"
|
||||
#include <rmt.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Nonzero if we are verifying at the moment. */
|
||||
@@ -54,15 +54,15 @@ static char *diff_buffer;
|
||||
void
|
||||
diff_init (void)
|
||||
{
|
||||
diff_buffer = valloc (record_size);
|
||||
if (!diff_buffer)
|
||||
xalloc_die ();
|
||||
void *ptr;
|
||||
diff_buffer = page_aligned_alloc (&ptr, record_size);
|
||||
}
|
||||
|
||||
/* Sigh about something that differs by writing a MESSAGE to stdlis,
|
||||
given MESSAGE is nonzero. Also set the exit status if not already. */
|
||||
void
|
||||
report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
report_difference (struct tar_stat_info *st __attribute__ ((unused)),
|
||||
const char *fmt, ...)
|
||||
{
|
||||
if (fmt)
|
||||
{
|
||||
@@ -74,35 +74,34 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
va_end (ap);
|
||||
fprintf (stdlis, "\n");
|
||||
}
|
||||
|
||||
|
||||
if (exit_status == TAREXIT_SUCCESS)
|
||||
exit_status = TAREXIT_DIFFERS;
|
||||
}
|
||||
|
||||
/* Take a buffer returned by read_and_process and do nothing with it. */
|
||||
static int
|
||||
process_noop (size_t size, char *data)
|
||||
process_noop (size_t size __attribute__ ((unused)),
|
||||
char *data __attribute__ ((unused)))
|
||||
{
|
||||
/* Yes, I know. SIZE and DATA are unused in this function. Some
|
||||
compilers may even report it. That's OK, just relax! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
process_rawdata (size_t bytes, char *buffer)
|
||||
{
|
||||
ssize_t status = safe_read (diff_handle, diff_buffer, bytes);
|
||||
size_t status = safe_read (diff_handle, diff_buffer, bytes);
|
||||
|
||||
if (status != bytes)
|
||||
{
|
||||
if (status < 0)
|
||||
if (status == SAFE_READ_ERROR)
|
||||
{
|
||||
read_error (current_stat_info.file_name);
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
report_difference (¤t_stat_info,
|
||||
report_difference (¤t_stat_info,
|
||||
ngettext ("Could only read %lu of %lu byte",
|
||||
"Could only read %lu of %lu bytes",
|
||||
bytes),
|
||||
@@ -279,7 +278,7 @@ diff_archive (void)
|
||||
|
||||
/* Need to treat sparse files completely differently here. */
|
||||
|
||||
if (current_header->header.typeflag == GNUTYPE_SPARSE)
|
||||
if (current_stat_info.is_sparse)
|
||||
sparse_diff_file (diff_handle, ¤t_stat_info);
|
||||
else
|
||||
{
|
||||
@@ -308,19 +307,20 @@ diff_archive (void)
|
||||
|
||||
case LNKTYPE:
|
||||
{
|
||||
struct stat link_data, stat_data;
|
||||
struct stat file_data;
|
||||
struct stat link_data;
|
||||
|
||||
if (!get_stat_data (current_stat_info.file_name, &stat_data))
|
||||
if (!get_stat_data (current_stat_info.file_name, &file_data))
|
||||
break;
|
||||
if (!get_stat_data (current_stat_info.link_name, &link_data))
|
||||
break;
|
||||
if (!sys_compare_links (&stat_data, &link_data))
|
||||
if (!sys_compare_links (&file_data, &link_data))
|
||||
report_difference (¤t_stat_info,
|
||||
_("Not linked to %s"),
|
||||
quote (current_stat_info.link_name));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
#ifdef HAVE_READLINK
|
||||
case SYMTYPE:
|
||||
{
|
||||
@@ -494,6 +494,14 @@ diff_archive (void)
|
||||
void
|
||||
verify_volume (void)
|
||||
{
|
||||
if (removed_prefixes_p ())
|
||||
{
|
||||
WARN((0, 0,
|
||||
_("Archive contains file names with leading prefixes removed.")));
|
||||
WARN((0, 0,
|
||||
_("Verification may fail to locate original files.")));
|
||||
}
|
||||
|
||||
if (!diff_buffer)
|
||||
diff_init ();
|
||||
|
||||
@@ -555,6 +563,7 @@ verify_volume (void)
|
||||
do
|
||||
{
|
||||
counter++;
|
||||
set_next_block_after (current_header);
|
||||
status = read_header (false);
|
||||
}
|
||||
while (status == HEADER_FAILURE);
|
||||
@@ -568,6 +577,8 @@ verify_volume (void)
|
||||
break;
|
||||
|
||||
diff_archive ();
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
xheader_destroy (&extended_header);
|
||||
}
|
||||
|
||||
access_mode = ACCESS_WRITE;
|
||||
|
||||
426
src/create.c
426
src/create.c
@@ -19,7 +19,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#if HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
@@ -337,11 +337,11 @@ string_to_chars (char *str, char *p, size_t s)
|
||||
b) current archive is /dev/null */
|
||||
|
||||
bool
|
||||
file_dumpable_p (struct tar_stat_info *stat)
|
||||
file_dumpable_p (struct tar_stat_info *st)
|
||||
{
|
||||
return !(dev_null_output
|
||||
|| (stat->archive_file_size == 0
|
||||
&& (stat->stat.st_mode & MODE_R) == MODE_R));
|
||||
|| (st->archive_file_size == 0
|
||||
&& (st->stat.st_mode & MODE_R) == MODE_R));
|
||||
}
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ start_private_header (const char *name, size_t size)
|
||||
{
|
||||
time_t t;
|
||||
union block *header = find_next_block ();
|
||||
|
||||
|
||||
memset (header->buffer, 0, sizeof (union block));
|
||||
|
||||
tar_copy_str (header->header.name, name, NAME_FIELD_SIZE);
|
||||
@@ -397,7 +397,7 @@ start_private_header (const char *name, size_t size)
|
||||
/* Create a new header and store there at most NAME_FIELD_SIZE bytes of
|
||||
the file name */
|
||||
|
||||
static union block *
|
||||
static union block *
|
||||
write_short_name (struct tar_stat_info *st)
|
||||
{
|
||||
union block *header = find_next_block ();
|
||||
@@ -406,6 +406,11 @@ write_short_name (struct tar_stat_info *st)
|
||||
return header;
|
||||
}
|
||||
|
||||
#define FILL(field,byte) do { \
|
||||
memset(field, byte, sizeof(field)-1); \
|
||||
(field)[sizeof(field)-1] = 0; \
|
||||
} while (0)
|
||||
|
||||
/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
|
||||
static void
|
||||
write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
@@ -413,8 +418,22 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
|
||||
size_t size = strlen (p) + 1;
|
||||
size_t bufsize;
|
||||
union block *header;
|
||||
|
||||
char *tmpname;
|
||||
|
||||
header = start_private_header ("././@LongLink", size);
|
||||
FILL(header->header.mtime, '0');
|
||||
FILL(header->header.mode, '0');
|
||||
FILL(header->header.uid, '0');
|
||||
FILL(header->header.gid, '0');
|
||||
FILL(header->header.devmajor, 0);
|
||||
FILL(header->header.devminor, 0);
|
||||
uid_to_uname (0, &tmpname);
|
||||
UNAME_TO_CHARS (tmpname, header->header.uname);
|
||||
free (tmpname);
|
||||
gid_to_gname (0, &tmpname);
|
||||
GNAME_TO_CHARS (tmpname, header->header.gname);
|
||||
free (tmpname);
|
||||
|
||||
strcpy (header->header.magic, OLDGNU_MAGIC);
|
||||
header->header.typeflag = type;
|
||||
finish_header (st, header, -1);
|
||||
@@ -459,18 +478,18 @@ write_ustar_long_name (const char *name)
|
||||
|
||||
if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)
|
||||
{
|
||||
WARN ((0, 0, _("%s: file name is too long (max %d); not dumped"),
|
||||
quotearg_colon (name),
|
||||
PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1));
|
||||
ERROR ((0, 0, _("%s: file name is too long (max %d); not dumped"),
|
||||
quotearg_colon (name),
|
||||
PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
i = split_long_name (name, length);
|
||||
if (i == 0 || length - i - 1 > NAME_FIELD_SIZE)
|
||||
{
|
||||
WARN ((0, 0,
|
||||
_("%s: file name is too long (cannot be split); not dumped"),
|
||||
quotearg_colon (name)));
|
||||
ERROR ((0, 0,
|
||||
_("%s: file name is too long (cannot be split); not dumped"),
|
||||
quotearg_colon (name)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -478,7 +497,7 @@ write_ustar_long_name (const char *name)
|
||||
memset (header->buffer, 0, sizeof (header->buffer));
|
||||
memcpy (header->header.prefix, name, i);
|
||||
memcpy (header->header.name, name + i + 1, length - i - 1);
|
||||
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -495,11 +514,11 @@ write_long_link (struct tar_stat_info *st)
|
||||
case V7_FORMAT: /* old V7 tar format */
|
||||
case USTAR_FORMAT:
|
||||
case STAR_FORMAT:
|
||||
WARN ((0, 0,
|
||||
_("%s: link name is too long; not dumped"),
|
||||
quotearg_colon (st->link_name)));
|
||||
break;
|
||||
|
||||
ERROR ((0, 0,
|
||||
_("%s: link name is too long; not dumped"),
|
||||
quotearg_colon (st->link_name)));
|
||||
break;
|
||||
|
||||
case OLDGNU_FORMAT:
|
||||
case GNU_FORMAT:
|
||||
write_gnu_long_link (st, st->link_name, GNUTYPE_LONGLINK);
|
||||
@@ -519,11 +538,20 @@ write_long_name (struct tar_stat_info *st)
|
||||
xheader_store ("path", st, NULL);
|
||||
break;
|
||||
|
||||
case V7_FORMAT:
|
||||
case V7_FORMAT:
|
||||
if (strlen (st->file_name) > NAME_FIELD_SIZE-1)
|
||||
{
|
||||
ERROR ((0, 0, _("%s: file name is too long (max %d); not dumped"),
|
||||
quotearg_colon (st->file_name),
|
||||
NAME_FIELD_SIZE - 1));
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USTAR_FORMAT:
|
||||
case STAR_FORMAT:
|
||||
return write_ustar_long_name (st->file_name);
|
||||
|
||||
|
||||
case OLDGNU_FORMAT:
|
||||
case GNU_FORMAT:
|
||||
write_gnu_long_link (st, st->file_name, GNUTYPE_LONGNAME);
|
||||
@@ -534,17 +562,16 @@ write_long_name (struct tar_stat_info *st)
|
||||
}
|
||||
return write_short_name (st);
|
||||
}
|
||||
|
||||
|
||||
static union block *
|
||||
write_extended (struct tar_stat_info *st, union block *old_header)
|
||||
{
|
||||
union block *header, hp;
|
||||
size_t size;
|
||||
char *p;
|
||||
|
||||
if (extended_header.buffer || extended_header.stk == NULL)
|
||||
return old_header;
|
||||
|
||||
return old_header;
|
||||
|
||||
xheader_finish (&extended_header);
|
||||
memcpy (hp.buffer, old_header, sizeof (hp));
|
||||
p = xheader_xhdr_name (st);
|
||||
@@ -555,7 +582,7 @@ write_extended (struct tar_stat_info *st, union block *old_header)
|
||||
return header;
|
||||
}
|
||||
|
||||
static union block *
|
||||
static union block *
|
||||
write_header_name (struct tar_stat_info *st)
|
||||
{
|
||||
if (archive_format == POSIX_FORMAT && !string_ascii_p (st->file_name))
|
||||
@@ -626,7 +653,7 @@ start_header (struct tar_stat_info *st)
|
||||
xheader_store ("uid", st, NULL);
|
||||
else
|
||||
UID_TO_CHARS (st->stat.st_uid, header->header.uid);
|
||||
|
||||
|
||||
if (st->stat.st_gid > MAXOCTAL7 && archive_format == POSIX_FORMAT)
|
||||
xheader_store ("gid", st, NULL);
|
||||
else
|
||||
@@ -656,19 +683,19 @@ start_header (struct tar_stat_info *st)
|
||||
else
|
||||
MAJOR_TO_CHARS (st->devminor, header->header.devminor);
|
||||
}
|
||||
else
|
||||
else if (archive_format != GNU_FORMAT && archive_format != OLDGNU_FORMAT)
|
||||
{
|
||||
MAJOR_TO_CHARS (0, header->header.devmajor);
|
||||
MINOR_TO_CHARS (0, header->header.devminor);
|
||||
}
|
||||
|
||||
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
xheader_store ("atime", st, NULL);
|
||||
xheader_store ("ctime", st, NULL);
|
||||
}
|
||||
else if (incremental_option)
|
||||
if (archive_format == OLDGNU_FORMAT)
|
||||
if (archive_format == OLDGNU_FORMAT || archive_format == GNU_FORMAT)
|
||||
{
|
||||
TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
|
||||
TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
|
||||
@@ -705,7 +732,7 @@ start_header (struct tar_stat_info *st)
|
||||
{
|
||||
uid_to_uname (st->stat.st_uid, &st->uname);
|
||||
gid_to_gname (st->stat.st_gid, &st->gname);
|
||||
|
||||
|
||||
if (archive_format == POSIX_FORMAT
|
||||
&& (strlen (st->uname) > UNAME_FIELD_SIZE
|
||||
|| !string_ascii_p (st->uname)))
|
||||
@@ -762,10 +789,6 @@ void
|
||||
finish_header (struct tar_stat_info *st,
|
||||
union block *header, off_t block_ordinal)
|
||||
{
|
||||
size_t i;
|
||||
int sum;
|
||||
char *p;
|
||||
|
||||
/* Note: It is important to do this before the call to write_extended(),
|
||||
so that the actual ustar header is printed */
|
||||
if (verbose_option
|
||||
@@ -798,40 +821,40 @@ pad_archive (off_t size_left)
|
||||
set_next_block_after (blk);
|
||||
size_left -= BLOCKSIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static enum dump_status
|
||||
dump_regular_file (int fd, struct tar_stat_info *stat)
|
||||
dump_regular_file (int fd, struct tar_stat_info *st)
|
||||
{
|
||||
off_t size_left = stat->stat.st_size;
|
||||
off_t size_left = st->stat.st_size;
|
||||
off_t block_ordinal;
|
||||
union block *blk;
|
||||
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
blk = start_header (stat);
|
||||
blk = start_header (st);
|
||||
if (!blk)
|
||||
return dump_status_fail;
|
||||
|
||||
/* Mark contiguous files, if we support them. */
|
||||
if (archive_format != V7_FORMAT && S_ISCTG (stat->stat.st_mode))
|
||||
if (archive_format != V7_FORMAT && S_ISCTG (st->stat.st_mode))
|
||||
blk->header.typeflag = CONTTYPE;
|
||||
|
||||
finish_header (stat, blk, block_ordinal);
|
||||
finish_header (st, blk, block_ordinal);
|
||||
|
||||
while (size_left > 0)
|
||||
{
|
||||
size_t bufsize, count;
|
||||
|
||||
|
||||
if (multi_volume_option)
|
||||
{
|
||||
assign_string (&save_name, stat->file_name);
|
||||
assign_string (&save_name, st->file_name);
|
||||
save_sizeleft = size_left;
|
||||
save_totsize = stat->stat.st_size;
|
||||
save_totsize = st->stat.st_size;
|
||||
}
|
||||
blk = find_next_block ();
|
||||
|
||||
|
||||
bufsize = available_space_after (blk);
|
||||
|
||||
|
||||
if (size_left < bufsize)
|
||||
{
|
||||
/* Last read -- zero out area beyond. */
|
||||
@@ -840,12 +863,12 @@ dump_regular_file (int fd, struct tar_stat_info *stat)
|
||||
if (count)
|
||||
memset (blk->buffer + size_left, 0, BLOCKSIZE - count);
|
||||
}
|
||||
|
||||
|
||||
count = (fd < 0) ? bufsize : safe_read (fd, blk->buffer, bufsize);
|
||||
if (count < 0)
|
||||
if (count == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (stat->orig_file_name,
|
||||
stat->stat.st_size - size_left, bufsize);
|
||||
read_diag_details (st->orig_file_name,
|
||||
st->stat.st_size - size_left, bufsize);
|
||||
pad_archive (size_left);
|
||||
return dump_status_short;
|
||||
}
|
||||
@@ -861,7 +884,7 @@ dump_regular_file (int fd, struct tar_stat_info *stat)
|
||||
ngettext ("%s: File shrank by %s byte; padding with zeros",
|
||||
"%s: File shrank by %s bytes; padding with zeros",
|
||||
size_left),
|
||||
quotearg_colon (stat->orig_file_name),
|
||||
quotearg_colon (st->orig_file_name),
|
||||
STRINGIFY_BIGINT (size_left, buf)));
|
||||
if (! ignore_failed_read_option)
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
@@ -872,7 +895,7 @@ dump_regular_file (int fd, struct tar_stat_info *stat)
|
||||
return dump_status_ok;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
|
||||
{
|
||||
if (fd >= 0)
|
||||
@@ -899,22 +922,63 @@ dump_regular_finish (int fd, struct tar_stat_info *st, time_t original_ctime)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dump_dir0 (char *directory,
|
||||
struct tar_stat_info *stat, int top_level, dev_t parent_device)
|
||||
/* Look in directory DIRNAME for a cache directory tag file
|
||||
with the magic name "CACHEDIR.TAG" and a standard header,
|
||||
as described at:
|
||||
http://www.brynosaurus.com/cachedir
|
||||
Applications can write this file into directories they create
|
||||
for use as caches containing purely regenerable, non-precious data,
|
||||
allowing us to avoid archiving them if --exclude-caches is specified. */
|
||||
|
||||
#define CACHEDIR_SIGNATURE "Signature: 8a477f597d28d172789f06886806bc55"
|
||||
#define CACHEDIR_SIGNATURE_SIZE (sizeof CACHEDIR_SIGNATURE - 1)
|
||||
|
||||
static bool
|
||||
check_cache_directory (char *dirname)
|
||||
{
|
||||
dev_t our_device = stat->stat.st_dev;
|
||||
|
||||
if (!is_avoided_name (stat->orig_file_name))
|
||||
static char tagname[] = "CACHEDIR.TAG";
|
||||
char *tagpath;
|
||||
int fd;
|
||||
int tag_present = false;
|
||||
|
||||
tagpath = xmalloc (strlen (dirname) + strlen (tagname) + 1);
|
||||
strcpy (tagpath, dirname);
|
||||
strcat (tagpath, tagname);
|
||||
|
||||
fd = open (tagpath, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
static char tagbuf[CACHEDIR_SIGNATURE_SIZE];
|
||||
|
||||
if (read (fd, tagbuf, CACHEDIR_SIGNATURE_SIZE)
|
||||
== CACHEDIR_SIGNATURE_SIZE
|
||||
&& memcmp (tagbuf, CACHEDIR_SIGNATURE, CACHEDIR_SIGNATURE_SIZE) == 0)
|
||||
tag_present = true;
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
free (tagpath);
|
||||
|
||||
return tag_present;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_dir0 (char *directory,
|
||||
struct tar_stat_info *st, int top_level, dev_t parent_device)
|
||||
{
|
||||
dev_t our_device = st->stat.st_dev;
|
||||
|
||||
if (!is_avoided_name (st->orig_file_name))
|
||||
{
|
||||
union block *blk = NULL;
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
stat->stat.st_size = 0; /* force 0 size on dir */
|
||||
st->stat.st_size = 0; /* force 0 size on dir */
|
||||
|
||||
blk = start_header (stat);
|
||||
blk = start_header (st);
|
||||
if (!blk)
|
||||
return;
|
||||
|
||||
|
||||
if (incremental_option)
|
||||
blk->header.typeflag = GNUTYPE_DUMPDIR;
|
||||
else /* if (standard_option) */
|
||||
@@ -923,7 +987,7 @@ dump_dir0 (char *directory,
|
||||
/* If we're gnudumping, we aren't done yet so don't close it. */
|
||||
|
||||
if (!incremental_option)
|
||||
finish_header (stat, blk, block_ordinal);
|
||||
finish_header (st, blk, block_ordinal);
|
||||
else if (gnu_list_name->dir_contents)
|
||||
{
|
||||
off_t size_left;
|
||||
@@ -931,8 +995,8 @@ dump_dir0 (char *directory,
|
||||
size_t bufsize;
|
||||
ssize_t count;
|
||||
const char *buffer, *p_buffer;
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
buffer = gnu_list_name->dir_contents; /* FOO */
|
||||
totsize = 0;
|
||||
if (buffer)
|
||||
@@ -944,14 +1008,14 @@ dump_dir0 (char *directory,
|
||||
}
|
||||
totsize++;
|
||||
OFF_TO_CHARS (totsize, blk->header.size);
|
||||
finish_header (stat, blk, block_ordinal);
|
||||
finish_header (st, blk, block_ordinal);
|
||||
p_buffer = buffer;
|
||||
size_left = totsize;
|
||||
while (size_left > 0)
|
||||
{
|
||||
if (multi_volume_option)
|
||||
{
|
||||
assign_string (&save_name, stat->orig_file_name);
|
||||
assign_string (&save_name, st->orig_file_name);
|
||||
save_sizeleft = size_left;
|
||||
save_totsize = totsize;
|
||||
}
|
||||
@@ -980,25 +1044,35 @@ dump_dir0 (char *directory,
|
||||
|
||||
if (one_file_system_option
|
||||
&& !top_level
|
||||
&& parent_device != stat->stat.st_dev)
|
||||
&& parent_device != st->stat.st_dev)
|
||||
{
|
||||
if (verbose_option)
|
||||
WARN ((0, 0,
|
||||
_("%s: file is on a different filesystem; not dumped"),
|
||||
quotearg_colon (stat->orig_file_name)));
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (exclude_caches_option
|
||||
&& check_cache_directory(st->orig_file_name))
|
||||
{
|
||||
if (verbose_option)
|
||||
WARN ((0, 0,
|
||||
_("%s: contains a cache directory tag; not dumped"),
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
char const *entry;
|
||||
size_t entry_len;
|
||||
char *name_buf = strdup (stat->orig_file_name);
|
||||
char *name_buf = strdup (st->orig_file_name);
|
||||
size_t name_size = strlen (name_buf);
|
||||
size_t name_len = name_size;
|
||||
|
||||
|
||||
/* Now output all the files in the directory. */
|
||||
/* FIXME: Should speed this up by cd-ing into the dir. */
|
||||
|
||||
|
||||
for (entry = directory; (entry_len = strlen (entry)) != 0;
|
||||
entry += entry_len + 1)
|
||||
{
|
||||
@@ -1011,7 +1085,7 @@ dump_dir0 (char *directory,
|
||||
if (!excluded_name (name_buf))
|
||||
dump_file (name_buf, 0, our_device);
|
||||
}
|
||||
|
||||
|
||||
free (name_buf);
|
||||
}
|
||||
}
|
||||
@@ -1029,22 +1103,22 @@ ensure_slash (char **pstr)
|
||||
(*pstr)[len] = '\0';
|
||||
}
|
||||
|
||||
bool
|
||||
dump_dir (struct tar_stat_info *stat, int top_level, dev_t parent_device)
|
||||
static bool
|
||||
dump_dir (struct tar_stat_info *st, int top_level, dev_t parent_device)
|
||||
{
|
||||
char *directory;
|
||||
|
||||
directory = savedir (stat->orig_file_name);
|
||||
directory = savedir (st->orig_file_name);
|
||||
if (!directory)
|
||||
{
|
||||
savedir_diag (stat->orig_file_name);
|
||||
savedir_diag (st->orig_file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
ensure_slash (&stat->orig_file_name);
|
||||
ensure_slash (&stat->file_name);
|
||||
ensure_slash (&st->orig_file_name);
|
||||
ensure_slash (&st->file_name);
|
||||
|
||||
dump_dir0 (directory, stat, top_level, parent_device);
|
||||
dump_dir0 (directory, st, top_level, parent_device);
|
||||
|
||||
free (directory);
|
||||
return true;
|
||||
@@ -1060,7 +1134,7 @@ create_archive (void)
|
||||
|
||||
open_archive (ACCESS_WRITE);
|
||||
xheader_write_global ();
|
||||
|
||||
|
||||
if (incremental_option)
|
||||
{
|
||||
size_t buffer_size = 1000;
|
||||
@@ -1127,8 +1201,9 @@ create_archive (void)
|
||||
static unsigned
|
||||
hash_link (void const *entry, unsigned n_buckets)
|
||||
{
|
||||
struct link const *link = entry;
|
||||
return (uintmax_t) (link->dev ^ link->ino) % n_buckets;
|
||||
struct link const *l = entry;
|
||||
uintmax_t num = l->dev ^ l->ino;
|
||||
return num % n_buckets;
|
||||
}
|
||||
|
||||
/* Compare two links for equality. */
|
||||
@@ -1160,41 +1235,41 @@ static Hash_table *link_table;
|
||||
/* Try to dump stat as a hard link to another file in the archive. If
|
||||
succeeded returns true */
|
||||
static bool
|
||||
dump_hard_link (struct tar_stat_info *stat)
|
||||
dump_hard_link (struct tar_stat_info *st)
|
||||
{
|
||||
if (link_table && stat->stat.st_nlink > 1)
|
||||
if (link_table && st->stat.st_nlink > 1)
|
||||
{
|
||||
struct link lp;
|
||||
struct link *dup;
|
||||
struct link *duplicate;
|
||||
off_t block_ordinal;
|
||||
union block *blk;
|
||||
|
||||
lp.ino = stat->stat.st_ino;
|
||||
lp.dev = stat->stat.st_dev;
|
||||
|
||||
if ((dup = hash_lookup (link_table, &lp)))
|
||||
lp.ino = st->stat.st_ino;
|
||||
lp.dev = st->stat.st_dev;
|
||||
|
||||
if ((duplicate = hash_lookup (link_table, &lp)))
|
||||
{
|
||||
/* We found a link. */
|
||||
char const *link_name = safer_name_suffix (dup->name, true);
|
||||
char const *link_name = safer_name_suffix (duplicate->name, true);
|
||||
|
||||
duplicate->nlink--;
|
||||
|
||||
dup->nlink--;
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
assign_string (&stat->link_name, link_name);
|
||||
assign_string (&st->link_name, link_name);
|
||||
if (NAME_FIELD_SIZE < strlen (link_name))
|
||||
write_long_link (stat);
|
||||
|
||||
stat->stat.st_size = 0;
|
||||
blk = start_header (stat);
|
||||
write_long_link (st);
|
||||
|
||||
st->stat.st_size = 0;
|
||||
blk = start_header (st);
|
||||
if (!blk)
|
||||
return true;
|
||||
tar_copy_str (blk->header.linkname, link_name, NAME_FIELD_SIZE);
|
||||
|
||||
blk->header.typeflag = LNKTYPE;
|
||||
finish_header (stat, blk, block_ordinal);
|
||||
finish_header (st, blk, block_ordinal);
|
||||
|
||||
if (remove_files_option && unlink (stat->orig_file_name) != 0)
|
||||
unlink_error (stat->orig_file_name);
|
||||
if (remove_files_option && unlink (st->orig_file_name) != 0)
|
||||
unlink_error (st->orig_file_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1203,25 +1278,25 @@ dump_hard_link (struct tar_stat_info *stat)
|
||||
}
|
||||
|
||||
static void
|
||||
file_count_links (struct tar_stat_info *stat)
|
||||
file_count_links (struct tar_stat_info *st)
|
||||
{
|
||||
if (stat->stat.st_nlink > 1)
|
||||
if (st->stat.st_nlink > 1)
|
||||
{
|
||||
struct link *dup;
|
||||
struct link *duplicate;
|
||||
struct link *lp = xmalloc (offsetof (struct link, name)
|
||||
+ strlen (stat->orig_file_name) + 1);
|
||||
lp->ino = stat->stat.st_ino;
|
||||
lp->dev = stat->stat.st_dev;
|
||||
lp->nlink = stat->stat.st_nlink;
|
||||
strcpy (lp->name, stat->orig_file_name);
|
||||
+ strlen (st->orig_file_name) + 1);
|
||||
lp->ino = st->stat.st_ino;
|
||||
lp->dev = st->stat.st_dev;
|
||||
lp->nlink = st->stat.st_nlink;
|
||||
strcpy (lp->name, st->orig_file_name);
|
||||
|
||||
if (! ((link_table
|
||||
|| (link_table = hash_initialize (0, 0, hash_link,
|
||||
compare_links, 0)))
|
||||
&& (dup = hash_insert (link_table, lp))))
|
||||
&& (duplicate = hash_insert (link_table, lp))))
|
||||
xalloc_die ();
|
||||
|
||||
if (dup != lp)
|
||||
if (duplicate != lp)
|
||||
abort ();
|
||||
lp->nlink--;
|
||||
}
|
||||
@@ -1230,7 +1305,7 @@ file_count_links (struct tar_stat_info *stat)
|
||||
/* For each dumped file, check if all its links were dumped. Emit
|
||||
warnings if it is not so. */
|
||||
void
|
||||
check_links ()
|
||||
check_links (void)
|
||||
{
|
||||
struct link *lp;
|
||||
|
||||
@@ -1257,8 +1332,8 @@ check_links ()
|
||||
/* FIXME: One should make sure that for *every* path leading to setting
|
||||
exit_status to failure, a clear diagnostic has been issued. */
|
||||
|
||||
void
|
||||
dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
static void
|
||||
dump_file0 (struct tar_stat_info *st, char *p,
|
||||
int top_level, dev_t parent_device)
|
||||
{
|
||||
union block *header;
|
||||
@@ -1266,26 +1341,26 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
time_t original_ctime;
|
||||
struct utimbuf restore_times;
|
||||
off_t block_ordinal = -1;
|
||||
|
||||
|
||||
if (interactive_option && !confirm ("add", p))
|
||||
return;
|
||||
|
||||
assign_string (&stat->orig_file_name, p);
|
||||
assign_string (&stat->file_name, safer_name_suffix (p, false));
|
||||
assign_string (&st->orig_file_name, p);
|
||||
assign_string (&st->file_name, safer_name_suffix (p, false));
|
||||
|
||||
if (deref_stat (dereference_option, p, &stat->stat) != 0)
|
||||
if (deref_stat (dereference_option, p, &st->stat) != 0)
|
||||
{
|
||||
stat_diag (p);
|
||||
return;
|
||||
}
|
||||
stat->archive_file_size = stat->stat.st_size;
|
||||
sys_stat_nanoseconds(stat);
|
||||
original_ctime = stat->stat.st_ctime;
|
||||
restore_times.actime = stat->stat.st_atime;
|
||||
restore_times.modtime = stat->stat.st_mtime;
|
||||
st->archive_file_size = st->stat.st_size;
|
||||
sys_stat_nanoseconds (st);
|
||||
original_ctime = st->stat.st_ctime;
|
||||
restore_times.actime = st->stat.st_atime;
|
||||
restore_times.modtime = st->stat.st_mtime;
|
||||
|
||||
#ifdef S_ISHIDDEN
|
||||
if (S_ISHIDDEN (stat->stat.st_mode))
|
||||
if (S_ISHIDDEN (st->stat.st_mode))
|
||||
{
|
||||
char *new = (char *) alloca (strlen (p) + 2);
|
||||
if (new)
|
||||
@@ -1298,30 +1373,33 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
#endif
|
||||
|
||||
/* See if we want only new files, and check if this one is too old to
|
||||
put in the archive. */
|
||||
put in the archive.
|
||||
|
||||
if (!S_ISDIR (stat->stat.st_mode)
|
||||
&& stat->stat.st_mtime < newer_mtime_option
|
||||
&& (!after_date_option || stat->stat.st_ctime < newer_ctime_option))
|
||||
This check is omitted if incremental_option is set *and* the
|
||||
requested file is not explicitely listed in the command line. */
|
||||
|
||||
if (!(incremental_option && !is_individual_file (p))
|
||||
&& !S_ISDIR (st->stat.st_mode)
|
||||
&& OLDER_STAT_TIME (st->stat, m)
|
||||
&& (!after_date_option || OLDER_STAT_TIME (st->stat, c)))
|
||||
{
|
||||
if (0 < top_level) /* equivalent to !incremental_option */
|
||||
if (!incremental_option)
|
||||
WARN ((0, 0, _("%s: file is unchanged; not dumped"),
|
||||
quotearg_colon (p)));
|
||||
/* FIXME: recheck this return. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if we are trying to dump the archive. */
|
||||
if (sys_file_is_archive (stat))
|
||||
if (sys_file_is_archive (st))
|
||||
{
|
||||
WARN ((0, 0, _("%s: file is the archive; not dumped"),
|
||||
quotearg_colon (p)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR (stat->stat.st_mode))
|
||||
if (S_ISDIR (st->stat.st_mode))
|
||||
{
|
||||
dump_dir (stat, top_level, parent_device);
|
||||
dump_dir (st, top_level, parent_device);
|
||||
if (atime_preserve_option)
|
||||
utime (p, &restore_times);
|
||||
return;
|
||||
@@ -1331,49 +1409,49 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
else
|
||||
{
|
||||
/* Check for multiple links. */
|
||||
if (dump_hard_link (stat))
|
||||
if (dump_hard_link (st))
|
||||
return;
|
||||
|
||||
|
||||
/* This is not a link to a previously dumped file, so dump it. */
|
||||
|
||||
if (S_ISREG (stat->stat.st_mode)
|
||||
|| S_ISCTG (stat->stat.st_mode))
|
||||
if (S_ISREG (st->stat.st_mode)
|
||||
|| S_ISCTG (st->stat.st_mode))
|
||||
{
|
||||
int fd;
|
||||
enum dump_status status;
|
||||
|
||||
if (file_dumpable_p (stat))
|
||||
if (file_dumpable_p (st))
|
||||
{
|
||||
fd = open (stat->orig_file_name,
|
||||
fd = open (st->orig_file_name,
|
||||
O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!top_level && errno == ENOENT)
|
||||
WARN ((0, 0, _("%s: File removed before we read it"),
|
||||
quotearg_colon (stat->orig_file_name)));
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
else
|
||||
open_diag (stat->orig_file_name);
|
||||
open_diag (st->orig_file_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
fd = -1;
|
||||
|
||||
if (sparse_option && sparse_file_p (stat))
|
||||
|
||||
if (sparse_option && sparse_file_p (st))
|
||||
{
|
||||
status = sparse_dump_file (fd, stat);
|
||||
status = sparse_dump_file (fd, st);
|
||||
if (status == dump_status_not_implemented)
|
||||
status = dump_regular_file (fd, stat);
|
||||
status = dump_regular_file (fd, st);
|
||||
}
|
||||
else
|
||||
status = dump_regular_file (fd, stat);
|
||||
status = dump_regular_file (fd, st);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case dump_status_ok:
|
||||
if (multi_volume_option)
|
||||
assign_string (&save_name, 0);
|
||||
dump_regular_finish (fd, stat, original_ctime);
|
||||
dump_regular_finish (fd, st, original_ctime);
|
||||
break;
|
||||
|
||||
case dump_status_short:
|
||||
@@ -1381,7 +1459,7 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
assign_string (&save_name, 0);
|
||||
close (fd);
|
||||
break;
|
||||
|
||||
|
||||
case dump_status_fail:
|
||||
close (fd);
|
||||
return;
|
||||
@@ -1391,17 +1469,17 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
}
|
||||
|
||||
if (atime_preserve_option)
|
||||
utime (stat->orig_file_name, &restore_times);
|
||||
file_count_links (stat);
|
||||
utime (st->orig_file_name, &restore_times);
|
||||
file_count_links (st);
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_READLINK
|
||||
else if (S_ISLNK (stat->stat.st_mode))
|
||||
else if (S_ISLNK (st->stat.st_mode))
|
||||
{
|
||||
char *buffer;
|
||||
int size;
|
||||
size_t linklen = stat->stat.st_size;
|
||||
if (linklen != stat->stat.st_size || linklen + 1 == 0)
|
||||
size_t linklen = st->stat.st_size;
|
||||
if (linklen != st->stat.st_size || linklen + 1 == 0)
|
||||
xalloc_die ();
|
||||
buffer = (char *) alloca (linklen + 1);
|
||||
size = readlink (p, buffer, linklen + 1);
|
||||
@@ -1411,18 +1489,18 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
return;
|
||||
}
|
||||
buffer[size] = '\0';
|
||||
assign_string (&stat->link_name, buffer);
|
||||
assign_string (&st->link_name, buffer);
|
||||
if (size > NAME_FIELD_SIZE)
|
||||
write_long_link (stat);
|
||||
write_long_link (st);
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
stat->stat.st_size = 0; /* force 0 size on symlink */
|
||||
header = start_header (stat);
|
||||
st->stat.st_size = 0; /* force 0 size on symlink */
|
||||
header = start_header (st);
|
||||
if (!header)
|
||||
return;
|
||||
tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE);
|
||||
header->header.typeflag = SYMTYPE;
|
||||
finish_header (stat, header, block_ordinal);
|
||||
finish_header (st, header, block_ordinal);
|
||||
/* nothing more to do to it */
|
||||
|
||||
if (remove_files_option)
|
||||
@@ -1430,22 +1508,22 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
if (unlink (p) == -1)
|
||||
unlink_error (p);
|
||||
}
|
||||
file_count_links (stat);
|
||||
file_count_links (st);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
else if (S_ISCHR (stat->stat.st_mode))
|
||||
else if (S_ISCHR (st->stat.st_mode))
|
||||
type = CHRTYPE;
|
||||
else if (S_ISBLK (stat->stat.st_mode))
|
||||
else if (S_ISBLK (st->stat.st_mode))
|
||||
type = BLKTYPE;
|
||||
else if (S_ISFIFO (stat->stat.st_mode))
|
||||
else if (S_ISFIFO (st->stat.st_mode))
|
||||
type = FIFOTYPE;
|
||||
else if (S_ISSOCK (stat->stat.st_mode))
|
||||
else if (S_ISSOCK (st->stat.st_mode))
|
||||
{
|
||||
WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
|
||||
return;
|
||||
}
|
||||
else if (S_ISDOOR (stat->stat.st_mode))
|
||||
else if (S_ISDOOR (st->stat.st_mode))
|
||||
{
|
||||
WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
|
||||
return;
|
||||
@@ -1464,21 +1542,21 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
}
|
||||
|
||||
block_ordinal = current_block_ordinal ();
|
||||
stat->stat.st_size = 0; /* force 0 size */
|
||||
header = start_header (stat);
|
||||
st->stat.st_size = 0; /* force 0 size */
|
||||
header = start_header (st);
|
||||
if (!header)
|
||||
return;
|
||||
header->header.typeflag = type;
|
||||
|
||||
if (type != FIFOTYPE)
|
||||
{
|
||||
MAJOR_TO_CHARS (major (stat->stat.st_rdev),
|
||||
MAJOR_TO_CHARS (major (st->stat.st_rdev),
|
||||
header->header.devmajor);
|
||||
MINOR_TO_CHARS (minor (stat->stat.st_rdev),
|
||||
MINOR_TO_CHARS (minor (st->stat.st_rdev),
|
||||
header->header.devminor);
|
||||
}
|
||||
|
||||
finish_header (stat, header, block_ordinal);
|
||||
finish_header (st, header, block_ordinal);
|
||||
if (remove_files_option)
|
||||
{
|
||||
if (unlink (p) == -1)
|
||||
@@ -1489,8 +1567,8 @@ dump_file0 (struct tar_stat_info *stat, char *p,
|
||||
void
|
||||
dump_file (char *p, int top_level, dev_t parent_device)
|
||||
{
|
||||
struct tar_stat_info stat;
|
||||
tar_stat_init (&stat);
|
||||
dump_file0 (&stat, p, top_level, parent_device);
|
||||
tar_stat_destroy (&stat);
|
||||
struct tar_stat_info st;
|
||||
tar_stat_init (&st);
|
||||
dump_file0 (&st, p, top_level, parent_device);
|
||||
tar_stat_destroy (&st);
|
||||
}
|
||||
|
||||
45
src/delete.c
45
src/delete.c
@@ -17,10 +17,10 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "rmt.h"
|
||||
#include <rmt.h>
|
||||
|
||||
static union block *new_record;
|
||||
static int new_blocks;
|
||||
@@ -359,33 +359,32 @@ delete_archive_members (void)
|
||||
write_record (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (logical_status == HEADER_END_OF_FILE)
|
||||
{
|
||||
/* Write the end of tape. FIXME: we can't use write_eot here,
|
||||
as it gets confused when the input is at end of file. */
|
||||
|
||||
int total_zero_blocks = 0;
|
||||
|
||||
do
|
||||
if (logical_status == HEADER_END_OF_FILE)
|
||||
{
|
||||
int zero_blocks = blocking_factor - new_blocks;
|
||||
memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
|
||||
total_zero_blocks += zero_blocks;
|
||||
write_record (total_zero_blocks < 2);
|
||||
/* Write the end of tape. FIXME: we can't use write_eot here,
|
||||
as it gets confused when the input is at end of file. */
|
||||
|
||||
int total_zero_blocks = 0;
|
||||
|
||||
do
|
||||
{
|
||||
int zero_blocks = blocking_factor - new_blocks;
|
||||
memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
|
||||
total_zero_blocks += zero_blocks;
|
||||
write_record (total_zero_blocks < 2);
|
||||
}
|
||||
while (total_zero_blocks < 2);
|
||||
}
|
||||
while (total_zero_blocks < 2);
|
||||
}
|
||||
|
||||
if (! acting_as_filter && ! _isrmt (archive))
|
||||
{
|
||||
if (sys_truncate (archive))
|
||||
truncate_warn (archive_name_array[0]);
|
||||
}
|
||||
}
|
||||
free (new_record);
|
||||
|
||||
if (! acting_as_filter && ! _isrmt (archive))
|
||||
{
|
||||
if (sys_truncate (archive))
|
||||
truncate_warn (archive_name_array[0]);
|
||||
}
|
||||
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
}
|
||||
|
||||
166
src/extract.c
166
src/extract.c
@@ -1,7 +1,7 @@
|
||||
/* Extract files from a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2003 Free Software Foundation, Inc.
|
||||
2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-11-19.
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
#include <errno.h>
|
||||
#include <xgetcwd.h>
|
||||
|
||||
#if HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
@@ -113,8 +114,20 @@ extr_init (void)
|
||||
we_are_root = geteuid () == 0;
|
||||
same_permissions_option += we_are_root;
|
||||
same_owner_option += we_are_root;
|
||||
xalloc_fail_func = extract_finish;
|
||||
|
||||
/* Save 'root device' to avoid purging mount points.
|
||||
FIXME: Should the same be done after handling -C option ? */
|
||||
if (one_file_system_option)
|
||||
{
|
||||
struct stat st;
|
||||
char *dir = xgetcwd ();
|
||||
|
||||
if (deref_stat (true, dir, &st))
|
||||
stat_diag (dir);
|
||||
else
|
||||
root_device = st.st_dev;
|
||||
}
|
||||
|
||||
/* Option -p clears the kernel umask, so it does not affect proper
|
||||
restoration of file permissions. New intermediate directories will
|
||||
comply with umask at start of program. */
|
||||
@@ -315,11 +328,11 @@ delay_set_stat (char const *file_name, struct stat const *stat_info,
|
||||
}
|
||||
|
||||
/* Update the delayed_set_stat info for an intermediate directory
|
||||
created on the path to DIR_NAME. The intermediate directory turned
|
||||
created within the file name of DIR. The intermediate directory turned
|
||||
out to be the same as this directory, e.g. due to ".." or symbolic
|
||||
links. *DIR_STAT_INFO is the status of the directory. */
|
||||
static void
|
||||
repair_delayed_set_stat (char const *dir_name,
|
||||
repair_delayed_set_stat (char const *dir,
|
||||
struct stat const *dir_stat_info)
|
||||
{
|
||||
struct delayed_set_stat *data;
|
||||
@@ -344,7 +357,7 @@ repair_delayed_set_stat (char const *dir_name,
|
||||
}
|
||||
|
||||
ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"),
|
||||
quotearg_colon (dir_name)));
|
||||
quotearg_colon (dir)));
|
||||
}
|
||||
|
||||
/* After a file/link/symlink/directory creation has failed, see if
|
||||
@@ -354,14 +367,14 @@ repair_delayed_set_stat (char const *dir_name,
|
||||
static int
|
||||
make_directories (char *file_name)
|
||||
{
|
||||
char *cursor0 = file_name + FILESYSTEM_PREFIX_LEN (file_name);
|
||||
char *cursor; /* points into path */
|
||||
char *cursor0 = file_name + FILE_SYSTEM_PREFIX_LEN (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))
|
||||
@@ -372,7 +385,7 @@ make_directories (char *file_name)
|
||||
if (cursor == cursor0 || ISSLASH (cursor[-1]))
|
||||
continue;
|
||||
|
||||
/* Avoid mkdir where last part of path is "." or "..". */
|
||||
/* Avoid mkdir where last part of file name is "." or "..". */
|
||||
|
||||
if (cursor[-1] == '.'
|
||||
&& (cursor == cursor0 + 1 || ISSLASH (cursor[-2])
|
||||
@@ -380,7 +393,7 @@ make_directories (char *file_name)
|
||||
&& (cursor == cursor0 + 2 || ISSLASH (cursor[-3])))))
|
||||
continue;
|
||||
|
||||
*cursor = '\0'; /* truncate the path there */
|
||||
*cursor = '\0'; /* truncate the name there */
|
||||
mode = MODE_RWX & ~ newdir_umask;
|
||||
invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ mode;
|
||||
status = mkdir (file_name, mode ^ invert_permissions);
|
||||
@@ -419,21 +432,56 @@ make_directories (char *file_name)
|
||||
return did_something; /* tell them to retry if we made one */
|
||||
}
|
||||
|
||||
static bool
|
||||
file_newer_p (const char *file_name, struct tar_stat_info *tar_stat)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat (file_name, &st))
|
||||
{
|
||||
stat_warn (file_name);
|
||||
return true; /* Be on the safe side */
|
||||
}
|
||||
if (!S_ISDIR (st.st_mode)
|
||||
&& st.st_mtime >= tar_stat->stat.st_mtime)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prepare to extract a file.
|
||||
Return zero if extraction should not proceed. */
|
||||
|
||||
static int
|
||||
prepare_to_extract (char const *file_name, bool directory)
|
||||
prepare_to_extract (char const *file_name)
|
||||
{
|
||||
if (to_stdout_option)
|
||||
return 0;
|
||||
|
||||
if (old_files_option == UNLINK_FIRST_OLD_FILES
|
||||
&& !remove_any_file (file_name, recursive_unlink_option)
|
||||
&& errno && errno != ENOENT)
|
||||
switch (old_files_option)
|
||||
{
|
||||
unlink_error (file_name);
|
||||
return 0;
|
||||
case UNLINK_FIRST_OLD_FILES:
|
||||
if (!remove_any_file (file_name,
|
||||
recursive_unlink_option ? RECURSIVE_REMOVE_OPTION
|
||||
: ORDINARY_REMOVE_OPTION)
|
||||
&& errno && errno != ENOENT)
|
||||
{
|
||||
unlink_error (file_name);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEEP_NEWER_FILES:
|
||||
if (file_newer_p (file_name, ¤t_stat_info))
|
||||
{
|
||||
WARN ((0, 0, _("Current `%s' is newer"), file_name));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -446,6 +494,8 @@ prepare_to_extract (char const *file_name, bool directory)
|
||||
static int
|
||||
maybe_recoverable (char *file_name, int *interdir_made)
|
||||
{
|
||||
int e = errno;
|
||||
|
||||
if (*interdir_made)
|
||||
return 0;
|
||||
|
||||
@@ -456,17 +506,28 @@ maybe_recoverable (char *file_name, int *interdir_made)
|
||||
|
||||
switch (old_files_option)
|
||||
{
|
||||
default:
|
||||
case KEEP_OLD_FILES:
|
||||
return 0;
|
||||
|
||||
case KEEP_NEWER_FILES:
|
||||
if (file_newer_p (file_name, ¤t_stat_info))
|
||||
{
|
||||
errno = e;
|
||||
return 0;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
|
||||
case DEFAULT_OLD_FILES:
|
||||
case NO_OVERWRITE_DIR_OLD_FILES:
|
||||
case OVERWRITE_OLD_FILES:
|
||||
{
|
||||
int r = remove_any_file (file_name, 0);
|
||||
int r = remove_any_file (file_name, ORDINARY_REMOVE_OPTION);
|
||||
errno = EEXIST;
|
||||
return r;
|
||||
}
|
||||
|
||||
case UNLINK_FIRST_OLD_FILES:
|
||||
break;
|
||||
}
|
||||
|
||||
case ENOENT:
|
||||
@@ -553,7 +614,6 @@ extract_archive (void)
|
||||
int openflag;
|
||||
mode_t mode;
|
||||
off_t size;
|
||||
off_t file_size;
|
||||
int interdir_made = 0;
|
||||
char typeflag;
|
||||
char *file_name;
|
||||
@@ -573,9 +633,9 @@ extract_archive (void)
|
||||
print_header (¤t_stat_info, -1);
|
||||
|
||||
file_name = safer_name_suffix (current_stat_info.file_name, false);
|
||||
if (strip_path_elements)
|
||||
if (strip_name_components)
|
||||
{
|
||||
size_t prefix_len = stripped_prefix_len (file_name, strip_path_elements);
|
||||
size_t prefix_len = stripped_prefix_len (file_name, strip_name_components);
|
||||
if (prefix_len == (size_t) -1)
|
||||
{
|
||||
skip_member ();
|
||||
@@ -583,7 +643,7 @@ extract_archive (void)
|
||||
}
|
||||
file_name += prefix_len;
|
||||
}
|
||||
|
||||
|
||||
apply_nonancestor_delayed_set_stat (file_name, 0);
|
||||
|
||||
/* Take a safety backup of a previously existing file. */
|
||||
@@ -600,12 +660,10 @@ extract_archive (void)
|
||||
|
||||
/* Extract the archive entry according to its type. */
|
||||
|
||||
typeflag = current_header->header.typeflag;
|
||||
/*KLUDGE */
|
||||
if (current_format == POSIX_FORMAT
|
||||
&& current_stat_info.archive_file_size != current_stat_info.stat.st_size)
|
||||
typeflag = GNUTYPE_SPARSE;
|
||||
|
||||
/* KLUDGE */
|
||||
typeflag = sparse_member_p (¤t_stat_info) ?
|
||||
GNUTYPE_SPARSE : current_header->header.typeflag;
|
||||
|
||||
switch (typeflag)
|
||||
{
|
||||
case GNUTYPE_SPARSE:
|
||||
@@ -636,7 +694,7 @@ extract_archive (void)
|
||||
goto extract_file;
|
||||
}
|
||||
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
if (! prepare_to_extract (file_name))
|
||||
{
|
||||
skip_member ();
|
||||
if (backup_option)
|
||||
@@ -681,7 +739,7 @@ extract_archive (void)
|
||||
}
|
||||
|
||||
extract_file:
|
||||
if (typeflag == GNUTYPE_SPARSE)
|
||||
if (current_stat_info.is_sparse)
|
||||
{
|
||||
sparse_extract_file (fd, ¤t_stat_info, &size);
|
||||
}
|
||||
@@ -751,12 +809,11 @@ extract_archive (void)
|
||||
|
||||
case SYMTYPE:
|
||||
#ifdef HAVE_SYMLINK
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
if (! prepare_to_extract (file_name))
|
||||
break;
|
||||
|
||||
if (absolute_names_option
|
||||
|| ! (ISSLASH (current_stat_info.link_name
|
||||
[FILESYSTEM_PREFIX_LEN (current_stat_info.link_name)])
|
||||
|| ! (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name)
|
||||
|| contains_dot_dot (current_stat_info.link_name)))
|
||||
{
|
||||
while (status = symlink (current_stat_info.link_name, file_name),
|
||||
@@ -835,7 +892,7 @@ extract_archive (void)
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (status != 0 && backup_option)
|
||||
undo_last_backup ();
|
||||
break;
|
||||
@@ -856,7 +913,7 @@ extract_archive (void)
|
||||
#endif
|
||||
|
||||
case LNKTYPE:
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
if (! prepare_to_extract (file_name))
|
||||
break;
|
||||
|
||||
again_link:
|
||||
@@ -869,17 +926,18 @@ extract_archive (void)
|
||||
/* MSDOS does not implement links. However, djgpp's link() actually
|
||||
copies the file. */
|
||||
status = link (link_name, file_name);
|
||||
e = errno;
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
struct delayed_symlink *ds = delayed_symlink_head;
|
||||
if (ds && stat (link_name, &st1) == 0)
|
||||
if (ds && lstat (link_name, &st1) == 0)
|
||||
for (; ds; ds = ds->next)
|
||||
if (ds->dev == st1.st_dev
|
||||
&& ds->ino == st1.st_ino
|
||||
&& ds->mtime == st1.st_mtime)
|
||||
{
|
||||
struct string_list *p =
|
||||
struct string_list *p =
|
||||
xmalloc (offsetof (struct string_list, string)
|
||||
+ strlen (file_name) + 1);
|
||||
strcpy (p->string, file_name);
|
||||
@@ -889,17 +947,20 @@ extract_archive (void)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((e == EEXIST && strcmp (link_name, file_name) == 0)
|
||||
|| (lstat (link_name, &st1) == 0
|
||||
&& lstat (file_name, &st2) == 0
|
||||
&& st1.st_dev == st2.st_dev
|
||||
&& st1.st_ino == st2.st_ino))
|
||||
break;
|
||||
|
||||
errno = e;
|
||||
if (maybe_recoverable (file_name, &interdir_made))
|
||||
goto again_link;
|
||||
|
||||
if (incremental_option && errno == EEXIST)
|
||||
break;
|
||||
e = errno;
|
||||
if (stat (link_name, &st1) == 0
|
||||
&& stat (file_name, &st2) == 0
|
||||
&& st1.st_dev == st2.st_dev
|
||||
&& st1.st_ino == st2.st_ino)
|
||||
break;
|
||||
|
||||
link_error (link_name, file_name);
|
||||
if (backup_option)
|
||||
@@ -920,7 +981,7 @@ extract_archive (void)
|
||||
|
||||
#if S_IFCHR || S_IFBLK
|
||||
make_node:
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
if (! prepare_to_extract (file_name))
|
||||
break;
|
||||
|
||||
status = mknod (file_name, current_stat_info.stat.st_mode,
|
||||
@@ -941,7 +1002,7 @@ extract_archive (void)
|
||||
|
||||
#if HAVE_MKFIFO || defined mkfifo
|
||||
case FIFOTYPE:
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
if (! prepare_to_extract (file_name))
|
||||
break;
|
||||
|
||||
while (status = mkfifo (file_name, current_stat_info.stat.st_mode),
|
||||
@@ -969,7 +1030,7 @@ extract_archive (void)
|
||||
/* Read the entry and delete files that aren't listed in the
|
||||
archive. */
|
||||
|
||||
gnu_restore (file_name);
|
||||
purge_directory (file_name);
|
||||
}
|
||||
else if (typeflag == GNUTYPE_DUMPDIR)
|
||||
skip_member ();
|
||||
@@ -978,7 +1039,7 @@ extract_archive (void)
|
||||
| (we_are_root ? 0 : MODE_WXUSR))
|
||||
& MODE_RWX);
|
||||
|
||||
status = prepare_to_extract (file_name, 1);
|
||||
status = prepare_to_extract (file_name);
|
||||
if (status == 0)
|
||||
break;
|
||||
if (status < 0)
|
||||
@@ -1010,7 +1071,7 @@ extract_archive (void)
|
||||
}
|
||||
errno = EEXIST;
|
||||
}
|
||||
|
||||
|
||||
if (maybe_recoverable (file_name, &interdir_made))
|
||||
goto again_dir;
|
||||
|
||||
@@ -1150,3 +1211,10 @@ fatal_exit (void)
|
||||
error (TAREXIT_FAILURE, 0, _("Error is not recoverable: exiting now"));
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
xalloc_die (void)
|
||||
{
|
||||
error (0, 0, "%s", _("memory exhausted"));
|
||||
fatal_exit ();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include <getline.h>
|
||||
#include <hash.h>
|
||||
#include <quotearg.h>
|
||||
@@ -39,7 +39,7 @@ struct directory
|
||||
enum children children;
|
||||
bool nfs;
|
||||
bool found;
|
||||
char name[1]; /* path name of directory */
|
||||
char name[1]; /* file name of directory */
|
||||
};
|
||||
|
||||
static Hash_table *directory_table;
|
||||
@@ -95,7 +95,7 @@ note_directory (char const *name, dev_t dev, ino_t ino, bool nfs, bool found)
|
||||
return directory;
|
||||
}
|
||||
|
||||
/* Return a directory entry for a given path NAME, or zero if none found. */
|
||||
/* Return a directory entry for a given file NAME, or zero if none found. */
|
||||
static struct directory *
|
||||
find_directory (char *name)
|
||||
{
|
||||
@@ -117,11 +117,11 @@ compare_dirents (const void *first, const void *second)
|
||||
(*(char *const *) second) + 1);
|
||||
}
|
||||
|
||||
/* Recursively scan the given PATH. */
|
||||
/* Recursively scan the given directory. */
|
||||
static void
|
||||
scan_path (struct obstack *stk, char *path, dev_t device)
|
||||
scan_directory (struct obstack *stk, char *dir_name, dev_t device)
|
||||
{
|
||||
char *dirp = savedir (path); /* for scanning directory */
|
||||
char *dirp = savedir (dir_name); /* for scanning directory */
|
||||
char const *entry; /* directory entry being scanned */
|
||||
size_t entrylen; /* length of directory entry */
|
||||
char *name_buffer; /* directory, `/', and directory member */
|
||||
@@ -132,20 +132,20 @@ scan_path (struct obstack *stk, char *path, dev_t device)
|
||||
|
||||
if (! dirp)
|
||||
{
|
||||
savedir_error (path);
|
||||
savedir_error (dir_name);
|
||||
}
|
||||
errno = 0;
|
||||
|
||||
name_buffer_size = strlen (path) + NAME_FIELD_SIZE;
|
||||
name_buffer_size = strlen (dir_name) + NAME_FIELD_SIZE;
|
||||
name_buffer = xmalloc (name_buffer_size + 2);
|
||||
strcpy (name_buffer, path);
|
||||
if (! ISSLASH (path[strlen (path) - 1]))
|
||||
strcpy (name_buffer, dir_name);
|
||||
if (! ISSLASH (dir_name[strlen (dir_name) - 1]))
|
||||
strcat (name_buffer, "/");
|
||||
name_length = strlen (name_buffer);
|
||||
|
||||
directory = find_directory (path);
|
||||
directory = find_directory (dir_name);
|
||||
children = directory ? directory->children : CHANGED_CHILDREN;
|
||||
|
||||
|
||||
if (dirp && children != NO_CHILDREN)
|
||||
for (entry = dirp;
|
||||
(entrylen = strlen (entry)) != 0;
|
||||
@@ -159,23 +159,23 @@ scan_path (struct obstack *stk, char *path, dev_t device)
|
||||
name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
|
||||
}
|
||||
strcpy (name_buffer + name_length, entry);
|
||||
|
||||
|
||||
if (excluded_name (name_buffer))
|
||||
obstack_1grow (stk, 'N');
|
||||
else
|
||||
{
|
||||
struct stat stat_data;
|
||||
|
||||
|
||||
if (deref_stat (dereference_option, name_buffer, &stat_data))
|
||||
{
|
||||
stat_diag (name_buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (S_ISDIR (stat_data.st_mode))
|
||||
{
|
||||
bool nfs = NFS_FILE_STAT (stat_data);
|
||||
|
||||
|
||||
if ((directory = find_directory (name_buffer)) != NULL)
|
||||
{
|
||||
/* With NFS, the same file can have two different devices
|
||||
@@ -184,7 +184,7 @@ scan_path (struct obstack *stk, char *path, dev_t device)
|
||||
To avoid spurious incremental redumping of
|
||||
directories, consider all NFS devices as equal,
|
||||
relying on the i-node to establish differences. */
|
||||
|
||||
|
||||
if (! (((directory->nfs & nfs)
|
||||
|| directory->device_number == stat_data.st_dev)
|
||||
&& directory->inode_number == stat_data.st_ino))
|
||||
@@ -209,13 +209,13 @@ scan_path (struct obstack *stk, char *path, dev_t device)
|
||||
stat_data.st_ino, nfs, 1);
|
||||
directory->children =
|
||||
((listed_incremental_option
|
||||
|| newer_mtime_option <= stat_data.st_mtime
|
||||
|| (after_date_option &&
|
||||
newer_ctime_option <= stat_data.st_ctime))
|
||||
|| OLDER_STAT_TIME (stat_data, m)
|
||||
|| (after_date_option
|
||||
&& OLDER_STAT_TIME (stat_data, c)))
|
||||
? ALL_CHILDREN
|
||||
: CHANGED_CHILDREN);
|
||||
}
|
||||
|
||||
|
||||
if (one_file_system_option && device != stat_data.st_dev)
|
||||
directory->children = NO_CHILDREN;
|
||||
else if (children == ALL_CHILDREN)
|
||||
@@ -239,19 +239,18 @@ scan_path (struct obstack *stk, char *path, dev_t device)
|
||||
|
||||
else
|
||||
if (children == CHANGED_CHILDREN
|
||||
&& stat_data.st_mtime < newer_mtime_option
|
||||
&& (!after_date_option
|
||||
|| stat_data.st_ctime < newer_ctime_option))
|
||||
&& OLDER_STAT_TIME (stat_data, m)
|
||||
&& (!after_date_option || OLDER_STAT_TIME (stat_data, c)))
|
||||
obstack_1grow (stk, 'N');
|
||||
else
|
||||
obstack_1grow (stk, 'Y');
|
||||
}
|
||||
|
||||
|
||||
obstack_grow (stk, entry, entrylen + 1);
|
||||
}
|
||||
|
||||
obstack_grow (stk, "\000\000", 2);
|
||||
|
||||
|
||||
free (name_buffer);
|
||||
if (dirp)
|
||||
free (dirp);
|
||||
@@ -267,16 +266,16 @@ sort_obstack (struct obstack *stk)
|
||||
char *buffer;
|
||||
char **array;
|
||||
char **array_cursor;
|
||||
|
||||
|
||||
counter = 0;
|
||||
for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
|
||||
counter++;
|
||||
|
||||
|
||||
if (!counter)
|
||||
return NULL;
|
||||
|
||||
array = obstack_alloc (stk, sizeof (char *) * (counter + 1));
|
||||
|
||||
|
||||
array_cursor = array;
|
||||
for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
|
||||
*array_cursor++ = cursor;
|
||||
@@ -290,7 +289,7 @@ sort_obstack (struct obstack *stk)
|
||||
for (array_cursor = array; *array_cursor; array_cursor++)
|
||||
{
|
||||
char *string = *array_cursor;
|
||||
|
||||
|
||||
while ((*cursor++ = *string++))
|
||||
continue;
|
||||
}
|
||||
@@ -299,13 +298,13 @@ sort_obstack (struct obstack *stk)
|
||||
}
|
||||
|
||||
char *
|
||||
get_directory_contents (char *path, dev_t device)
|
||||
get_directory_contents (char *dir_name, dev_t device)
|
||||
{
|
||||
struct obstack stk;
|
||||
char *buffer;
|
||||
|
||||
obstack_init (&stk);
|
||||
scan_path (&stk, path, device);
|
||||
scan_directory (&stk, dir_name, device);
|
||||
buffer = sort_obstack (&stk);
|
||||
obstack_free (&stk, NULL);
|
||||
return buffer;
|
||||
@@ -357,7 +356,10 @@ read_directory_file (void)
|
||||
ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
|
||||
_("Time stamp out of range")));
|
||||
else
|
||||
newer_mtime_option = t;
|
||||
{
|
||||
newer_mtime_option.tv_sec = t;
|
||||
newer_mtime_option.tv_nsec = 0;
|
||||
}
|
||||
|
||||
while (0 < (n = getline (&buf, &bufsize, fp)))
|
||||
{
|
||||
@@ -458,10 +460,9 @@ write_directory_file (void)
|
||||
/* Restoration of incremental dumps. */
|
||||
|
||||
/* Examine the directories under directory_name and delete any
|
||||
files that were not there at the time of the back-up.
|
||||
FIXME: The function name is obviously a misnomer */
|
||||
files that were not there at the time of the back-up. */
|
||||
void
|
||||
gnu_restore (char const *directory_name)
|
||||
purge_directory (char const *directory_name)
|
||||
{
|
||||
char *archive_dir;
|
||||
char *current_dir;
|
||||
@@ -514,13 +515,30 @@ gnu_restore (char const *directory_name)
|
||||
}
|
||||
if (*arc == '\0')
|
||||
{
|
||||
struct stat st;
|
||||
char *p = new_name (directory_name, cur);
|
||||
|
||||
if (deref_stat (true, p, &st))
|
||||
{
|
||||
stat_diag (p);
|
||||
WARN((0, 0, _("%s: Not purging directory: unable to stat"),
|
||||
quotearg_colon (p)));
|
||||
continue;
|
||||
}
|
||||
else if (one_file_system_option && st.st_dev != root_device)
|
||||
{
|
||||
WARN((0, 0,
|
||||
_("%s: directory is on a different device: not purging"),
|
||||
quotearg_colon (p)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! interactive_option || confirm ("delete", p))
|
||||
{
|
||||
if (verbose_option)
|
||||
fprintf (stdlis, _("%s: Deleting %s\n"),
|
||||
program_name, quote (p));
|
||||
if (! remove_any_file (p, 1))
|
||||
if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
|
||||
{
|
||||
int e = errno;
|
||||
ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
|
||||
|
||||
220
src/list.c
220
src/list.c
@@ -1,7 +1,7 @@
|
||||
/* List a tar archive, with support routines for reading a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2003 Free Software Foundation, Inc.
|
||||
2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-08-26.
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/* Define to non-zero for forcing old ctime format instead of ISO format. */
|
||||
#undef USE_OLD_CTIME
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -78,7 +78,7 @@ read_and (void (*do_something) (void))
|
||||
prev_status = status;
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
xheader_destroy (&extended_header);
|
||||
|
||||
|
||||
status = read_header (false);
|
||||
switch (status)
|
||||
{
|
||||
@@ -92,12 +92,17 @@ read_and (void (*do_something) (void))
|
||||
Ensure incoming names are null terminated. */
|
||||
|
||||
if (! name_match (current_stat_info.file_name)
|
||||
|| (newer_mtime_option != TYPE_MINIMUM (time_t)
|
||||
|| (NEWER_OPTION_INITIALIZED (newer_mtime_option)
|
||||
/* FIXME: We get mtime now, and again later; this causes
|
||||
duplicate diagnostics if header.mtime is bogus. */
|
||||
&& ((current_stat_info.stat.st_mtime
|
||||
= TIME_FROM_HEADER (current_header->header.mtime))
|
||||
< newer_mtime_option))
|
||||
= TIME_FROM_HEADER (current_header->header.mtime)),
|
||||
#ifdef ST_MTIM_NSEC
|
||||
/* FIXME: Grab fractional time stamps from
|
||||
extended header. */
|
||||
current_stat_info.stat.st_mtim.ST_MTIM_NSEC = 0,
|
||||
#endif
|
||||
OLDER_STAT_TIME (current_stat_info.stat, m)))
|
||||
|| excluded_name (current_stat_info.file_name))
|
||||
{
|
||||
switch (current_header->header.typeflag)
|
||||
@@ -113,6 +118,8 @@ read_and (void (*do_something) (void))
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
/* Fall through. */
|
||||
default:
|
||||
decode_header (current_header,
|
||||
¤t_stat_info, ¤t_format, 0);
|
||||
skip_member ();
|
||||
continue;
|
||||
}
|
||||
@@ -140,6 +147,7 @@ read_and (void (*do_something) (void))
|
||||
break;
|
||||
WARN ((0, 0, _("A lone zero block at %s"),
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
|
||||
break;
|
||||
}
|
||||
status = prev_status;
|
||||
continue;
|
||||
@@ -165,6 +173,15 @@ read_and (void (*do_something) (void))
|
||||
|
||||
case HEADER_ZERO_BLOCK:
|
||||
case HEADER_SUCCESS:
|
||||
if (block_number_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
block_ordinal -= recent_long_name_blocks;
|
||||
block_ordinal -= recent_long_link_blocks;
|
||||
fprintf (stdlis, _("block %s: "),
|
||||
STRINGIFY_BIGINT (block_ordinal, buf));
|
||||
}
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
break;
|
||||
|
||||
@@ -249,6 +266,61 @@ list_archive (void)
|
||||
assign_string (&save_name, 0);
|
||||
}
|
||||
|
||||
/* Check header checksum */
|
||||
/* The standard BSD tar sources create the checksum by adding up the
|
||||
bytes in the header as type char. I think the type char was unsigned
|
||||
on the PDP-11, but it's signed on the Next and Sun. It looks like the
|
||||
sources to BSD tar were never changed to compute the checksum
|
||||
correctly, so both the Sun and Next add the bytes of the header as
|
||||
signed chars. This doesn't cause a problem until you get a file with
|
||||
a name containing characters with the high bit set. So tar_checksum
|
||||
computes two checksums -- signed and unsigned. */
|
||||
|
||||
enum read_header
|
||||
tar_checksum (union block *header)
|
||||
{
|
||||
size_t i;
|
||||
int unsigned_sum = 0; /* the POSIX one :-) */
|
||||
int signed_sum = 0; /* the Sun one :-( */
|
||||
int recorded_sum;
|
||||
uintmax_t parsed_sum;
|
||||
char *p;
|
||||
|
||||
p = header->buffer;
|
||||
for (i = sizeof *header; i-- != 0;)
|
||||
{
|
||||
unsigned_sum += (unsigned char) *p;
|
||||
signed_sum += (signed char) (*p++);
|
||||
}
|
||||
|
||||
if (unsigned_sum == 0)
|
||||
return HEADER_ZERO_BLOCK;
|
||||
|
||||
/* Adjust checksum to count the "chksum" field as blanks. */
|
||||
|
||||
for (i = sizeof header->header.chksum; i-- != 0;)
|
||||
{
|
||||
unsigned_sum -= (unsigned char) header->header.chksum[i];
|
||||
signed_sum -= (signed char) (header->header.chksum[i]);
|
||||
}
|
||||
unsigned_sum += ' ' * sizeof header->header.chksum;
|
||||
signed_sum += ' ' * sizeof header->header.chksum;
|
||||
|
||||
parsed_sum = from_header (header->header.chksum,
|
||||
sizeof header->header.chksum, 0,
|
||||
(uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (int));
|
||||
if (parsed_sum == (uintmax_t) -1)
|
||||
return HEADER_FAILURE;
|
||||
|
||||
recorded_sum = parsed_sum;
|
||||
|
||||
if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
|
||||
return HEADER_FAILURE;
|
||||
|
||||
return HEADER_SUCCESS;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -262,23 +334,9 @@ list_archive (void)
|
||||
You must always set_next_block_after(current_header) to skip past
|
||||
the header which this routine reads. */
|
||||
|
||||
/* The standard BSD tar sources create the checksum by adding up the
|
||||
bytes in the header as type char. I think the type char was unsigned
|
||||
on the PDP-11, but it's signed on the Next and Sun. It looks like the
|
||||
sources to BSD tar were never changed to compute the checksum
|
||||
correctly, so both the Sun and Next add the bytes of the header as
|
||||
signed chars. This doesn't cause a problem until you get a file with
|
||||
a name containing characters with the high bit set. So read_header
|
||||
computes two checksums -- signed and unsigned. */
|
||||
|
||||
enum read_header
|
||||
read_header (bool raw_extended_headers)
|
||||
{
|
||||
size_t i;
|
||||
int unsigned_sum; /* the POSIX one :-) */
|
||||
int signed_sum; /* the Sun one :-( */
|
||||
int recorded_sum;
|
||||
uintmax_t parsed_sum;
|
||||
char *p;
|
||||
union block *header;
|
||||
union block *header_copy;
|
||||
@@ -292,44 +350,15 @@ read_header (bool raw_extended_headers)
|
||||
|
||||
while (1)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
header = find_next_block ();
|
||||
current_header = header;
|
||||
if (!header)
|
||||
return HEADER_END_OF_FILE;
|
||||
|
||||
unsigned_sum = 0;
|
||||
signed_sum = 0;
|
||||
p = header->buffer;
|
||||
for (i = sizeof *header; i-- != 0;)
|
||||
{
|
||||
unsigned_sum += (unsigned char) *p;
|
||||
signed_sum += (signed char) (*p++);
|
||||
}
|
||||
|
||||
if (unsigned_sum == 0)
|
||||
return HEADER_ZERO_BLOCK;
|
||||
|
||||
/* Adjust checksum to count the "chksum" field as blanks. */
|
||||
|
||||
for (i = sizeof header->header.chksum; i-- != 0;)
|
||||
{
|
||||
unsigned_sum -= (unsigned char) header->header.chksum[i];
|
||||
signed_sum -= (signed char) (header->header.chksum[i]);
|
||||
}
|
||||
unsigned_sum += ' ' * sizeof header->header.chksum;
|
||||
signed_sum += ' ' * sizeof header->header.chksum;
|
||||
|
||||
parsed_sum = from_header (header->header.chksum,
|
||||
sizeof header->header.chksum, 0,
|
||||
(uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (int));
|
||||
if (parsed_sum == (uintmax_t) -1)
|
||||
return HEADER_FAILURE;
|
||||
|
||||
recorded_sum = parsed_sum;
|
||||
|
||||
if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
|
||||
return HEADER_FAILURE;
|
||||
if ((status = tar_checksum (header)) != HEADER_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Good block. Decode file size and return. */
|
||||
|
||||
@@ -355,7 +384,7 @@ read_header (bool raw_extended_headers)
|
||||
xalloc_die ();
|
||||
|
||||
header_copy = xmalloc (size + 1);
|
||||
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME)
|
||||
{
|
||||
if (next_long_name)
|
||||
@@ -370,7 +399,7 @@ read_header (bool raw_extended_headers)
|
||||
next_long_link = header_copy;
|
||||
next_long_link_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
|
||||
|
||||
set_next_block_after (header);
|
||||
*header_copy = *header;
|
||||
bp = header_copy->buffer + BLOCKSIZE;
|
||||
@@ -386,7 +415,7 @@ read_header (bool raw_extended_headers)
|
||||
written = available_space_after (data_block);
|
||||
if (written > size)
|
||||
written = size;
|
||||
|
||||
|
||||
memcpy (bp, data_block->buffer, written);
|
||||
bp += written;
|
||||
set_next_block_after ((union block *)
|
||||
@@ -402,7 +431,7 @@ read_header (bool raw_extended_headers)
|
||||
xheader_read (header, OFF_FROM_HEADER (header->header.size));
|
||||
xheader_decode_global ();
|
||||
}
|
||||
|
||||
|
||||
/* Loop! */
|
||||
|
||||
}
|
||||
@@ -515,11 +544,13 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
|
||||
stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
|
||||
stat_info->stat.st_mtime = TIME_FROM_HEADER (header->header.mtime);
|
||||
assign_string (&stat_info->uname, header->header.uname);
|
||||
assign_string (&stat_info->gname, header->header.gname);
|
||||
assign_string (&stat_info->uname,
|
||||
header->header.uname[0] ? header->header.uname : NULL);
|
||||
assign_string (&stat_info->gname,
|
||||
header->header.gname[0] ? header->header.gname : NULL);
|
||||
stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor);
|
||||
stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor);
|
||||
|
||||
|
||||
stat_info->stat.st_atime = start_time;
|
||||
stat_info->stat.st_ctime = start_time;
|
||||
|
||||
@@ -558,12 +589,13 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
|| !gname_to_gid (header->header.gname, &stat_info->stat.st_gid))
|
||||
stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
|
||||
}
|
||||
|
||||
|
||||
switch (header->header.typeflag)
|
||||
{
|
||||
case BLKTYPE:
|
||||
case CHRTYPE:
|
||||
stat_info->stat.st_rdev = makedev (stat_info->devmajor, stat_info->devminor);
|
||||
stat_info->stat.st_rdev = makedev (stat_info->devmajor,
|
||||
stat_info->devminor);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -571,8 +603,16 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
}
|
||||
}
|
||||
|
||||
current_stat_info.archive_file_size = current_stat_info.stat.st_size;
|
||||
stat_info->archive_file_size = stat_info->stat.st_size;
|
||||
xheader_decode (stat_info);
|
||||
|
||||
if (sparse_member_p (stat_info))
|
||||
{
|
||||
sparse_fixup_header (stat_info);
|
||||
stat_info->is_sparse = true;
|
||||
}
|
||||
else
|
||||
stat_info->is_sparse = false;
|
||||
}
|
||||
|
||||
/* Convert buffer at WHERE0 of size DIGS from external format to
|
||||
@@ -899,7 +939,7 @@ tartime (time_t t)
|
||||
#else
|
||||
/* Use ISO 8610 format. See:
|
||||
http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
|
||||
struct tm *tm = localtime (&t);
|
||||
struct tm *tm = utc_option ? gmtime (&t) : localtime (&t);
|
||||
if (tm)
|
||||
{
|
||||
sprintf (buffer, "%04ld-%02d-%02d %02d:%02d:%02d",
|
||||
@@ -953,7 +993,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
char modes[11];
|
||||
char const *time_stamp;
|
||||
char *temp_name = st->orig_file_name ? st->orig_file_name : st->file_name;
|
||||
|
||||
|
||||
/* These hold formatted ints. */
|
||||
char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
|
||||
char *user, *group;
|
||||
@@ -1100,16 +1140,10 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
strcat (size,
|
||||
STRINGIFY_BIGINT (minor (st->stat.st_rdev), uintbuf));
|
||||
break;
|
||||
case GNUTYPE_SPARSE:
|
||||
strcpy (size,
|
||||
STRINGIFY_BIGINT
|
||||
(UINTMAX_FROM_HEADER (current_header
|
||||
->oldgnu_header.realsize),
|
||||
uintbuf));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* st->stat.st_size keeps stored file size */
|
||||
strcpy (size, STRINGIFY_BIGINT (st->archive_file_size, uintbuf));
|
||||
strcpy (size, STRINGIFY_BIGINT (st->stat.st_size, uintbuf));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1186,7 +1220,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
|
||||
/* Print a similar line when we make a directory automatically. */
|
||||
void
|
||||
print_for_mkdir (char *pathname, int length, mode_t mode)
|
||||
print_for_mkdir (char *dirname, int length, mode_t mode)
|
||||
{
|
||||
char modes[11];
|
||||
|
||||
@@ -1205,7 +1239,7 @@ print_for_mkdir (char *pathname, int length, mode_t mode)
|
||||
}
|
||||
|
||||
fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
|
||||
_("Creating directory:"), length, quotearg (pathname));
|
||||
_("Creating directory:"), length, quotearg (dirname));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1221,6 +1255,19 @@ skip_file (off_t size)
|
||||
save_sizeleft = size;
|
||||
}
|
||||
|
||||
if (seekable_archive)
|
||||
{
|
||||
off_t nblk = seek_archive (size);
|
||||
if (nblk >= 0)
|
||||
{
|
||||
size -= nblk * BLOCKSIZE;
|
||||
if (multi_volume_option) /* Argh.. */
|
||||
save_sizeleft -= nblk * BLOCKSIZE;
|
||||
}
|
||||
else
|
||||
seekable_archive = false;
|
||||
}
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
x = find_next_block ();
|
||||
@@ -1234,27 +1281,18 @@ skip_file (off_t size)
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip the current member in the archive. */
|
||||
/* Skip the current member in the archive.
|
||||
NOTE: Current header must be decoded before calling this function. */
|
||||
void
|
||||
skip_member (void)
|
||||
{
|
||||
char save_typeflag = current_header->header.typeflag;
|
||||
set_next_block_after (current_header);
|
||||
|
||||
assign_string (&save_name, current_stat_info.file_name);
|
||||
|
||||
if (current_format == OLDGNU_FORMAT
|
||||
&& current_header->oldgnu_header.isextended)
|
||||
{
|
||||
union block *exhdr;
|
||||
do
|
||||
{
|
||||
exhdr = find_next_block ();
|
||||
if (!exhdr)
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
set_next_block_after (exhdr);
|
||||
}
|
||||
while (exhdr->sparse_header.isextended);
|
||||
}
|
||||
|
||||
if (save_typeflag != DIRTYPE)
|
||||
if (current_stat_info.is_sparse)
|
||||
sparse_skip_file (¤t_stat_info);
|
||||
else if (save_typeflag != DIRTYPE)
|
||||
skip_file (current_stat_info.stat.st_size);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
#include <quotearg.h>
|
||||
|
||||
|
||||
159
src/misc.c
159
src/misc.c
@@ -1,7 +1,7 @@
|
||||
/* Miscellaneous functions, not really specific to GNU tar.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
2003 Free Software Foundation, Inc.
|
||||
2003, 2004 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
|
||||
@@ -17,8 +17,8 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include "rmt.h"
|
||||
#include <system.h>
|
||||
#include <rmt.h>
|
||||
#include "common.h"
|
||||
#include <quotearg.h>
|
||||
#include <save-cwd.h>
|
||||
@@ -123,13 +123,13 @@ unquote_string (char *string)
|
||||
source++;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
*destination++ = '\n';
|
||||
case 'a':
|
||||
*destination++ = '\a';
|
||||
source++;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
*destination++ = '\t';
|
||||
|
||||
case 'b':
|
||||
*destination++ = '\b';
|
||||
source++;
|
||||
break;
|
||||
|
||||
@@ -138,8 +138,8 @@ unquote_string (char *string)
|
||||
source++;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
*destination++ = '\b';
|
||||
case 'n':
|
||||
*destination++ = '\n';
|
||||
source++;
|
||||
break;
|
||||
|
||||
@@ -148,6 +148,16 @@ unquote_string (char *string)
|
||||
source++;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
*destination++ = '\t';
|
||||
source++;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
*destination++ = '\v';
|
||||
source++;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
*destination++ = 0177;
|
||||
source++;
|
||||
@@ -203,32 +213,33 @@ unquote_string (char *string)
|
||||
static char *before_backup_name;
|
||||
static char *after_backup_name;
|
||||
|
||||
/* Return 1 if PATH is obviously "." or "/". */
|
||||
/* Return 1 if FILE_NAME is obviously "." or "/". */
|
||||
static bool
|
||||
must_be_dot_or_slash (char const *path)
|
||||
must_be_dot_or_slash (char const *file_name)
|
||||
{
|
||||
path += FILESYSTEM_PREFIX_LEN (path);
|
||||
file_name += FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
|
||||
if (ISSLASH (path[0]))
|
||||
if (ISSLASH (file_name[0]))
|
||||
{
|
||||
for (;;)
|
||||
if (ISSLASH (path[1]))
|
||||
path++;
|
||||
else if (path[1] == '.' && ISSLASH (path[2 + (path[2] == '.')]))
|
||||
path += 2 + (path[2] == '.');
|
||||
if (ISSLASH (file_name[1]))
|
||||
file_name++;
|
||||
else if (file_name[1] == '.'
|
||||
&& ISSLASH (file_name[2 + (file_name[2] == '.')]))
|
||||
file_name += 2 + (file_name[2] == '.');
|
||||
else
|
||||
return ! path[1];
|
||||
return ! file_name[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
while (path[0] == '.' && ISSLASH (path[1]))
|
||||
while (file_name[0] == '.' && ISSLASH (file_name[1]))
|
||||
{
|
||||
path += 2;
|
||||
while (ISSLASH (*path))
|
||||
path++;
|
||||
file_name += 2;
|
||||
while (ISSLASH (*file_name))
|
||||
file_name++;
|
||||
}
|
||||
|
||||
return ! path[0] || (path[0] == '.' && ! path[1]);
|
||||
return ! file_name[0] || (file_name[0] == '.' && ! file_name[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,32 +247,32 @@ must_be_dot_or_slash (char const *path)
|
||||
Report an error with errno set to zero for obvious cases of this;
|
||||
otherwise call rmdir. */
|
||||
static int
|
||||
safer_rmdir (const char *path)
|
||||
safer_rmdir (const char *file_name)
|
||||
{
|
||||
if (must_be_dot_or_slash (path))
|
||||
if (must_be_dot_or_slash (file_name))
|
||||
{
|
||||
errno = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rmdir (path);
|
||||
return rmdir (file_name);
|
||||
}
|
||||
|
||||
/* Remove PATH, returning 1 on success. If PATH is a directory, then
|
||||
if OPTION is RECURSIVE_REMOVE_OPTION is set remove PATH
|
||||
recursively; otherwise, remove it only if it is empty. If PATH is
|
||||
/* Remove FILE_NAME, returning 1 on success. If FILE_NAME is a directory,
|
||||
then if OPTION is RECURSIVE_REMOVE_OPTION is set remove FILE_NAME
|
||||
recursively; otherwise, remove it only if it is empty. If FILE_NAME is
|
||||
a directory that cannot be removed (e.g., because it is nonempty)
|
||||
and if OPTION is WANT_DIRECTORY_REMOVE_OPTION, then return -1.
|
||||
Return 0 on error, with errno set; if PATH is obviously the working
|
||||
Return 0 on error, with errno set; if FILE_NAME is obviously the working
|
||||
directory return zero with errno set to zero. */
|
||||
int
|
||||
remove_any_file (const char *path, enum remove_option option)
|
||||
remove_any_file (const char *file_name, enum remove_option option)
|
||||
{
|
||||
/* Try unlink first if we are not root, as this saves us a system
|
||||
call in the common case where we're removing a non-directory. */
|
||||
if (! we_are_root)
|
||||
{
|
||||
if (unlink (path) == 0)
|
||||
if (unlink (file_name) == 0)
|
||||
return 1;
|
||||
|
||||
/* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
|
||||
@@ -271,13 +282,13 @@ remove_any_file (const char *path, enum remove_option option)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (safer_rmdir (path) == 0)
|
||||
if (safer_rmdir (file_name) == 0)
|
||||
return 1;
|
||||
|
||||
switch (errno)
|
||||
{
|
||||
case ENOTDIR:
|
||||
return we_are_root && unlink (path) == 0;
|
||||
return we_are_root && unlink (file_name) == 0;
|
||||
|
||||
case 0:
|
||||
case EEXIST:
|
||||
@@ -294,7 +305,7 @@ remove_any_file (const char *path, enum remove_option option)
|
||||
|
||||
case RECURSIVE_REMOVE_OPTION:
|
||||
{
|
||||
char *directory = savedir (path);
|
||||
char *directory = savedir (file_name);
|
||||
char const *entry;
|
||||
size_t entrylen;
|
||||
|
||||
@@ -305,10 +316,11 @@ remove_any_file (const char *path, enum remove_option option)
|
||||
(entrylen = strlen (entry)) != 0;
|
||||
entry += entrylen + 1)
|
||||
{
|
||||
char *path_buffer = new_name (path, entry);
|
||||
int r = remove_any_file (path_buffer, 1);
|
||||
char *file_name_buffer = new_name (file_name, entry);
|
||||
int r = remove_any_file (file_name_buffer,
|
||||
RECURSIVE_REMOVE_OPTION);
|
||||
int e = errno;
|
||||
free (path_buffer);
|
||||
free (file_name_buffer);
|
||||
|
||||
if (! r)
|
||||
{
|
||||
@@ -319,7 +331,7 @@ remove_any_file (const char *path, enum remove_option option)
|
||||
}
|
||||
|
||||
free (directory);
|
||||
return safer_rmdir (path) == 0;
|
||||
return safer_rmdir (file_name) == 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -328,37 +340,39 @@ remove_any_file (const char *path, enum remove_option option)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if PATH already exists and make a backup of it right now.
|
||||
/* Check if FILE_NAME already exists and make a backup of it right now.
|
||||
Return success (nonzero) only if the backup is either unneeded, or
|
||||
successful. For now, directories are considered to never need
|
||||
backup. If ARCHIVE is nonzero, this is the archive and so, we do
|
||||
not have to backup block or character devices, nor remote entities. */
|
||||
backup. If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and
|
||||
so, we do not have to backup block or character devices, nor remote
|
||||
entities. */
|
||||
bool
|
||||
maybe_backup_file (const char *path, int archive)
|
||||
maybe_backup_file (const char *file_name, int this_is_the_archive)
|
||||
{
|
||||
struct stat file_stat;
|
||||
|
||||
/* Check if we really need to backup the file. */
|
||||
|
||||
if (archive && _remdev (path))
|
||||
if (this_is_the_archive && _remdev (file_name))
|
||||
return true;
|
||||
|
||||
if (stat (path, &file_stat))
|
||||
if (stat (file_name, &file_stat))
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
return true;
|
||||
|
||||
stat_error (path);
|
||||
stat_error (file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (S_ISDIR (file_stat.st_mode))
|
||||
return true;
|
||||
|
||||
if (archive && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
|
||||
if (this_is_the_archive
|
||||
&& (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
|
||||
return true;
|
||||
|
||||
assign_string (&before_backup_name, path);
|
||||
assign_string (&before_backup_name, file_name);
|
||||
|
||||
/* A run situation may exist between Emacs or other GNU programs trying to
|
||||
make a backup for the same file simultaneously. If theoretically
|
||||
@@ -366,7 +380,7 @@ maybe_backup_file (const char *path, int archive)
|
||||
convention, GNU-wide, for all programs doing backups. */
|
||||
|
||||
assign_string (&after_backup_name, 0);
|
||||
after_backup_name = find_backup_file_name (path, backup_type);
|
||||
after_backup_name = find_backup_file_name (file_name, backup_type);
|
||||
if (! after_backup_name)
|
||||
xalloc_die ();
|
||||
|
||||
@@ -586,12 +600,6 @@ close_error (char const *name)
|
||||
call_arg_error ("close", name);
|
||||
}
|
||||
|
||||
void
|
||||
close_fatal (char const *name)
|
||||
{
|
||||
call_arg_fatal ("close", name);
|
||||
}
|
||||
|
||||
void
|
||||
close_warn (char const *name)
|
||||
{
|
||||
@@ -875,16 +883,16 @@ write_error (char const *name)
|
||||
}
|
||||
|
||||
void
|
||||
write_error_details (char const *name, ssize_t status, size_t size)
|
||||
write_error_details (char const *name, size_t status, size_t size)
|
||||
{
|
||||
if (status < 0)
|
||||
if (status == 0)
|
||||
write_error (name);
|
||||
else
|
||||
ERROR ((0, 0,
|
||||
ngettext ("%s: Wrote only %lu of %lu byte",
|
||||
"%s: Wrote only %lu of %lu bytes",
|
||||
record_size),
|
||||
name, (unsigned long) status, (unsigned long) record_size));
|
||||
size),
|
||||
name, (unsigned long int) status, (unsigned long int) size));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -919,18 +927,29 @@ xpipe (int fd[2])
|
||||
call_arg_fatal ("pipe", _("interprocess channel"));
|
||||
}
|
||||
|
||||
/* Return an unambiguous printable representation, allocated in slot N,
|
||||
for NAME, suitable for diagnostics. */
|
||||
char const *
|
||||
quote_n (int n, char const *name)
|
||||
/* Return PTR, aligned upward to the next multiple of ALIGNMENT.
|
||||
ALIGNMENT must be nonzero. The caller must arrange for ((char *)
|
||||
PTR) through ((char *) PTR + ALIGNMENT - 1) to be addressable
|
||||
locations. */
|
||||
|
||||
static inline void *
|
||||
ptr_align (void *ptr, size_t alignment)
|
||||
{
|
||||
return quotearg_n_style (n, locale_quoting_style, name);
|
||||
char *p0 = ptr;
|
||||
char *p1 = p0 + alignment - 1;
|
||||
return p1 - (size_t) p1 % alignment;
|
||||
}
|
||||
|
||||
/* Return an unambiguous printable representation of NAME, suitable
|
||||
for diagnostics. */
|
||||
char const *
|
||||
quote (char const *name)
|
||||
/* Return the address of a page-aligned buffer of at least SIZE bytes.
|
||||
The caller should free *PTR when done with the buffer. */
|
||||
|
||||
void *
|
||||
page_aligned_alloc (void **ptr, size_t size)
|
||||
{
|
||||
return quote_n (0, name);
|
||||
size_t alignment = getpagesize ();
|
||||
size_t size1 = size + alignment;
|
||||
if (size1 < size)
|
||||
xalloc_die ();
|
||||
*ptr = xmalloc (size1);
|
||||
return ptr_align (*ptr, alignment);
|
||||
}
|
||||
|
||||
146
src/names.c
146
src/names.c
@@ -1,7 +1,7 @@
|
||||
/* Various processing of names.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2003 Free Software Foundation, Inc.
|
||||
2003, 2004 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
|
||||
@@ -17,7 +17,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <hash.h>
|
||||
@@ -56,6 +56,8 @@ static char *cached_no_such_gname;
|
||||
static uid_t cached_no_such_uid;
|
||||
static gid_t cached_no_such_gid;
|
||||
|
||||
static void register_individual_file (char const *name);
|
||||
|
||||
/* Given UID, find the corresponding UNAME. */
|
||||
void
|
||||
uid_to_uname (uid_t uid, char **uname)
|
||||
@@ -118,7 +120,7 @@ gid_to_gname (gid_t gid, char **gname)
|
||||
|
||||
/* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
|
||||
int
|
||||
uname_to_uid (char *uname, uid_t *uidp)
|
||||
uname_to_uid (char const *uname, uid_t *uidp)
|
||||
{
|
||||
struct passwd *passwd;
|
||||
|
||||
@@ -148,7 +150,7 @@ uname_to_uid (char *uname, uid_t *uidp)
|
||||
|
||||
/* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
|
||||
int
|
||||
gname_to_gid (char *gname, gid_t *gidp)
|
||||
gname_to_gid (char const *gname, gid_t *gidp)
|
||||
{
|
||||
struct group *group;
|
||||
|
||||
@@ -227,7 +229,7 @@ is_pattern (const char *string)
|
||||
/* Set up to gather file names for tar. They can either come from a
|
||||
file or were saved from decoding arguments. */
|
||||
void
|
||||
name_init (int argc, char *const *argv)
|
||||
name_init (void)
|
||||
{
|
||||
name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
|
||||
name_buffer_length = NAME_FIELD_SIZE;
|
||||
@@ -358,6 +360,8 @@ name_next (int change_dirs)
|
||||
else
|
||||
{
|
||||
unquote_string (name_buffer);
|
||||
if (incremental_option)
|
||||
register_individual_file (name_buffer);
|
||||
return name_buffer;
|
||||
}
|
||||
}
|
||||
@@ -443,6 +447,8 @@ name_gather (void)
|
||||
namelist = buffer;
|
||||
nametail = &namelist->next;
|
||||
}
|
||||
else if (change_dir)
|
||||
addname (0, change_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -513,10 +519,10 @@ addname (char const *string, int change_dir)
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Find a match for PATH (whose string length is LENGTH) in the name
|
||||
/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
|
||||
list. */
|
||||
static struct name *
|
||||
namelist_match (char const *path, size_t length)
|
||||
namelist_match (char const *file_name, size_t length)
|
||||
{
|
||||
struct name *p;
|
||||
|
||||
@@ -524,27 +530,27 @@ namelist_match (char const *path, size_t length)
|
||||
{
|
||||
/* If first chars don't match, quick skip. */
|
||||
|
||||
if (p->firstch && p->name[0] != path[0])
|
||||
if (p->firstch && p->name[0] != file_name[0])
|
||||
continue;
|
||||
|
||||
if (p->regexp
|
||||
? fnmatch (p->name, path, recursion_option) == 0
|
||||
? fnmatch (p->name, file_name, recursion_option) == 0
|
||||
: (p->length <= length
|
||||
&& (path[p->length] == '\0'
|
||||
|| (ISSLASH (path[p->length]) && recursion_option))
|
||||
&& memcmp (path, p->name, p->length) == 0))
|
||||
&& (file_name[p->length] == '\0'
|
||||
|| (ISSLASH (file_name[p->length]) && recursion_option))
|
||||
&& memcmp (file_name, p->name, p->length) == 0))
|
||||
return p;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return true if and only if name PATH (from an archive) matches any
|
||||
/* Return true if and only if name FILE_NAME (from an archive) matches any
|
||||
name from the namelist. */
|
||||
int
|
||||
name_match (const char *path)
|
||||
name_match (const char *file_name)
|
||||
{
|
||||
size_t length = strlen (path);
|
||||
size_t length = strlen (file_name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -561,10 +567,10 @@ name_match (const char *path)
|
||||
return ! files_from_option;
|
||||
}
|
||||
|
||||
cursor = namelist_match (path, length);
|
||||
cursor = namelist_match (file_name, length);
|
||||
if (cursor)
|
||||
{
|
||||
if (!(ISSLASH (path[cursor->length]) && recursion_option)
|
||||
if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
|
||||
|| cursor->found_count == 0)
|
||||
cursor->found_count++; /* remember it matched */
|
||||
if (starting_file_option)
|
||||
@@ -639,7 +645,7 @@ names_notfound (void)
|
||||
ERROR ((0, 0, _("%s: Required occurrence not found in archive"),
|
||||
quotearg_colon (cursor->name)));
|
||||
}
|
||||
|
||||
|
||||
/* Don't bother freeing the name list; we're about to exit. */
|
||||
namelist = 0;
|
||||
nametail = &namelist;
|
||||
@@ -748,8 +754,8 @@ compare_names (struct name const *n1, struct name const *n2)
|
||||
static void
|
||||
add_hierarchy_to_namelist (struct name *name, dev_t device)
|
||||
{
|
||||
char *path = name->name;
|
||||
char *buffer = get_directory_contents (path, device);
|
||||
char *file_name = name->name;
|
||||
char *buffer = get_directory_contents (file_name, device);
|
||||
|
||||
if (! buffer)
|
||||
name->dir_contents = "\0\0\0\0";
|
||||
@@ -759,18 +765,18 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
|
||||
size_t allocated_length = (name_length >= NAME_FIELD_SIZE
|
||||
? name_length + NAME_FIELD_SIZE
|
||||
: NAME_FIELD_SIZE);
|
||||
char *name_buffer = xmalloc (allocated_length + 1);
|
||||
char *namebuf = xmalloc (allocated_length + 1);
|
||||
/* FIXME: + 2 above? */
|
||||
char *string;
|
||||
size_t string_length;
|
||||
int change_dir = name->change_dir;
|
||||
|
||||
name->dir_contents = buffer;
|
||||
strcpy (name_buffer, path);
|
||||
if (! ISSLASH (name_buffer[name_length - 1]))
|
||||
strcpy (namebuf, file_name);
|
||||
if (! ISSLASH (namebuf[name_length - 1]))
|
||||
{
|
||||
name_buffer[name_length++] = '/';
|
||||
name_buffer[name_length] = '\0';
|
||||
namebuf[name_length++] = '/';
|
||||
namebuf[name_length] = '\0';
|
||||
}
|
||||
|
||||
for (string = buffer; *string; string += string_length + 1)
|
||||
@@ -788,15 +794,15 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
|
||||
}
|
||||
while (allocated_length <= name_length + string_length);
|
||||
|
||||
name_buffer = xrealloc (name_buffer, allocated_length + 1);
|
||||
namebuf = xrealloc (namebuf, allocated_length + 1);
|
||||
}
|
||||
strcpy (name_buffer + name_length, string + 1);
|
||||
add_hierarchy_to_namelist (addname (name_buffer, change_dir),
|
||||
strcpy (namebuf + name_length, string + 1);
|
||||
add_hierarchy_to_namelist (addname (namebuf, change_dir),
|
||||
device);
|
||||
}
|
||||
}
|
||||
|
||||
free (name_buffer);
|
||||
free (namebuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,13 +863,13 @@ collect_and_sort_names (void)
|
||||
will have to do that if it wants to. Oh, and if the namelist is
|
||||
empty, it returns null, unlike name_match, which returns TRUE. */
|
||||
struct name *
|
||||
name_scan (const char *path)
|
||||
name_scan (const char *file_name)
|
||||
{
|
||||
size_t length = strlen (path);
|
||||
size_t length = strlen (file_name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct name *cursor = namelist_match (path, length);
|
||||
struct name *cursor = namelist_match (file_name, length);
|
||||
if (cursor)
|
||||
return cursor;
|
||||
|
||||
@@ -914,18 +920,18 @@ blank_name_list (void)
|
||||
name->found_count = 0;
|
||||
}
|
||||
|
||||
/* Yield a newly allocated file name consisting of PATH concatenated to
|
||||
NAME, with an intervening slash if PATH does not already end in one. */
|
||||
/* 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. */
|
||||
char *
|
||||
new_name (const char *path, const char *name)
|
||||
new_name (const char *file_name, const char *name)
|
||||
{
|
||||
size_t pathlen = strlen (path);
|
||||
size_t file_name_len = strlen (file_name);
|
||||
size_t namesize = strlen (name) + 1;
|
||||
int slash = pathlen && ! ISSLASH (path[pathlen - 1]);
|
||||
char *buffer = xmalloc (pathlen + slash + namesize);
|
||||
memcpy (buffer, path, pathlen);
|
||||
buffer[pathlen] = '/';
|
||||
memcpy (buffer + pathlen + slash, name, namesize);
|
||||
int slash = file_name_len && ! ISSLASH (file_name[file_name_len - 1]);
|
||||
char *buffer = xmalloc (file_name_len + slash + namesize);
|
||||
memcpy (buffer, file_name, file_name_len);
|
||||
buffer[file_name_len] = '/';
|
||||
memcpy (buffer + file_name_len + slash, name, namesize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -933,7 +939,7 @@ new_name (const char *path, const char *name)
|
||||
bool
|
||||
excluded_name (char const *name)
|
||||
{
|
||||
return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
|
||||
return excluded_filename (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
|
||||
}
|
||||
|
||||
/* Hash tables of strings. */
|
||||
@@ -999,7 +1005,44 @@ is_avoided_name (char const *name)
|
||||
{
|
||||
return hash_string_lookup (avoided_name_table, name);
|
||||
}
|
||||
|
||||
|
||||
static Hash_table *individual_file_table;
|
||||
|
||||
static void
|
||||
register_individual_file (char const *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (deref_stat (dereference_option, name, &st) != 0)
|
||||
return; /* Will be complained about later */
|
||||
if (S_ISDIR (st.st_mode))
|
||||
return;
|
||||
|
||||
hash_string_insert (&individual_file_table, name);
|
||||
}
|
||||
|
||||
bool
|
||||
is_individual_file (char const *name)
|
||||
{
|
||||
return hash_string_lookup (individual_file_table, name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Hash_table *prefix_table[2];
|
||||
|
||||
/* Return true if file names of some members in the archive were stripped off
|
||||
their leading components. We could have used
|
||||
return prefix_table[0] || prefix_table[1]
|
||||
but the following seems to be safer: */
|
||||
bool
|
||||
removed_prefixes_p (void)
|
||||
{
|
||||
return (prefix_table[0] && hash_get_n_entries (prefix_table[0]) != 0)
|
||||
|| (prefix_table[1] && hash_get_n_entries (prefix_table[1]) != 0);
|
||||
}
|
||||
|
||||
/* Return a safer suffix of FILE_NAME, or "." if it has no safer
|
||||
suffix. Check for fully specified file names and other atrocities.
|
||||
Warn the user if we do not return NAME. If LINK_TARGET is 1,
|
||||
@@ -1014,16 +1057,16 @@ safer_name_suffix (char const *file_name, bool link_target)
|
||||
p = file_name;
|
||||
else
|
||||
{
|
||||
/* Skip file system prefixes, leading pathnames that contain
|
||||
/* Skip file system prefixes, leading file name components that contain
|
||||
"..", and leading slashes. */
|
||||
|
||||
size_t prefix_len = FILESYSTEM_PREFIX_LEN (file_name);
|
||||
size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
|
||||
for (p = file_name + prefix_len; *p; )
|
||||
{
|
||||
if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
|
||||
prefix_len = p + 2 - file_name;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
char c = *p++;
|
||||
@@ -1039,7 +1082,6 @@ safer_name_suffix (char const *file_name, bool link_target)
|
||||
|
||||
if (prefix_len)
|
||||
{
|
||||
static Hash_table *prefix_table[2];
|
||||
char *prefix = alloca (prefix_len + 1);
|
||||
memcpy (prefix, file_name, prefix_len);
|
||||
prefix[prefix_len] = '\0';
|
||||
@@ -1065,9 +1107,9 @@ safer_name_suffix (char const *file_name, bool link_target)
|
||||
N_("Substituting `.' for empty member name"),
|
||||
N_("Substituting `.' for empty hard link target")
|
||||
};
|
||||
WARN ((0, 0, _(diagnostic[link_target])));
|
||||
WARN ((0, 0, "%s", _(diagnostic[link_target])));
|
||||
}
|
||||
|
||||
|
||||
p = ".";
|
||||
}
|
||||
|
||||
@@ -1075,13 +1117,13 @@ safer_name_suffix (char const *file_name, bool link_target)
|
||||
}
|
||||
|
||||
/* Return the size of the prefix of FILE_NAME that is removed after
|
||||
stripping NUM leading path name components. NUM must be
|
||||
stripping NUM leading file name components. NUM must be
|
||||
positive. */
|
||||
|
||||
size_t
|
||||
stripped_prefix_len (char const *file_name, size_t num)
|
||||
{
|
||||
char const *p = file_name + FILESYSTEM_PREFIX_LEN (file_name);
|
||||
char const *p = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
while (ISSLASH (*p))
|
||||
p++;
|
||||
while (*p)
|
||||
@@ -1099,11 +1141,11 @@ stripped_prefix_len (char const *file_name, size_t num)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return nonzero if NAME contains ".." as a path name component. */
|
||||
/* Return nonzero if NAME contains ".." as a file name component. */
|
||||
bool
|
||||
contains_dot_dot (char const *name)
|
||||
{
|
||||
char const *p = name + FILESYSTEM_PREFIX_LEN (name);
|
||||
char const *p = name + FILE_SYSTEM_PREFIX_LEN (name);
|
||||
|
||||
for (;; p++)
|
||||
{
|
||||
|
||||
575
src/rmt.c
575
src/rmt.c
@@ -1,575 +0,0 @@
|
||||
/* Remote connection server.
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 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.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Copyright (C) 1983 Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms are permitted provided
|
||||
that the above copyright notice and this paragraph are duplicated in all
|
||||
such forms and that any documentation, advertising materials, and other
|
||||
materials related to such distribution and use acknowledge that the
|
||||
software was developed by the University of California, Berkeley. The
|
||||
name of the University may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
|
||||
|
||||
#include "system.h"
|
||||
#include <localedir.h>
|
||||
#include <safe-read.h>
|
||||
#include <full-write.h>
|
||||
|
||||
#include <getopt.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
# define EXIT_FAILURE 1
|
||||
#endif
|
||||
#ifndef EXIT_SUCCESS
|
||||
# define EXIT_SUCCESS 0
|
||||
#endif
|
||||
|
||||
/* Maximum size of a string from the requesting program. */
|
||||
#define STRING_SIZE 64
|
||||
|
||||
/* Name of executing program. */
|
||||
const char *program_name;
|
||||
|
||||
/* File descriptor of the tape device, or negative if none open. */
|
||||
static int tape = -1;
|
||||
|
||||
/* Buffer containing transferred data, and its allocated size. */
|
||||
static char *record_buffer;
|
||||
static size_t allocated_size;
|
||||
|
||||
/* Buffer for constructing the reply. */
|
||||
static char reply_buffer[BUFSIZ];
|
||||
|
||||
/* Debugging tools. */
|
||||
|
||||
static FILE *debug_file;
|
||||
|
||||
#define DEBUG(File) \
|
||||
if (debug_file) fprintf(debug_file, File)
|
||||
|
||||
#define DEBUG1(File, Arg) \
|
||||
if (debug_file) fprintf(debug_file, File, Arg)
|
||||
|
||||
#define DEBUG2(File, Arg1, Arg2) \
|
||||
if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
|
||||
|
||||
/* Return an error string, given an error number. */
|
||||
#if HAVE_STRERROR
|
||||
# ifndef strerror
|
||||
char *strerror ();
|
||||
# endif
|
||||
#else
|
||||
static char *
|
||||
private_strerror (int errnum)
|
||||
{
|
||||
extern char *sys_errlist[];
|
||||
extern int sys_nerr;
|
||||
|
||||
if (errnum > 0 && errnum <= sys_nerr)
|
||||
return _(sys_errlist[errnum]);
|
||||
return _("Unknown system error");
|
||||
}
|
||||
# define strerror private_strerror
|
||||
#endif
|
||||
|
||||
static void
|
||||
report_error_message (const char *string)
|
||||
{
|
||||
DEBUG1 ("rmtd: E 0 (%s)\n", string);
|
||||
|
||||
sprintf (reply_buffer, "E0\n%s\n", string);
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
}
|
||||
|
||||
static void
|
||||
report_numbered_error (int num)
|
||||
{
|
||||
DEBUG2 ("rmtd: E %d (%s)\n", num, strerror (num));
|
||||
|
||||
sprintf (reply_buffer, "E%d\n%s\n", num, strerror (num));
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
}
|
||||
|
||||
static void
|
||||
get_string (char *string)
|
||||
{
|
||||
int counter;
|
||||
|
||||
for (counter = 0; counter < STRING_SIZE; counter++)
|
||||
{
|
||||
if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
if (string[counter] == '\n')
|
||||
break;
|
||||
}
|
||||
string[counter] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_input_buffer (int fd, size_t size)
|
||||
{
|
||||
if (size <= allocated_size)
|
||||
return;
|
||||
|
||||
if (record_buffer)
|
||||
free (record_buffer);
|
||||
|
||||
record_buffer = malloc (size);
|
||||
|
||||
if (! record_buffer)
|
||||
{
|
||||
DEBUG (_("rmtd: Cannot allocate buffer space\n"));
|
||||
|
||||
report_error_message (N_("Cannot allocate buffer space"));
|
||||
exit (EXIT_FAILURE); /* exit status used to be 4 */
|
||||
}
|
||||
|
||||
allocated_size = size;
|
||||
|
||||
#ifdef SO_RCVBUF
|
||||
if (0 <= fd)
|
||||
{
|
||||
int isize = size < INT_MAX ? size : INT_MAX;
|
||||
while (setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
|
||||
(char *) &isize, sizeof isize)
|
||||
&& 1024 < isize)
|
||||
isize >>= 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
|
||||
OFLAG_STRING should contain an optional integer, followed by an optional
|
||||
symbolic representation of an open flag using only '|' to separate its
|
||||
components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
|
||||
representation if available, falling back on the numeric
|
||||
representation, or to zero if both formats are absent.
|
||||
|
||||
This function should be the inverse of encode_oflag. The numeric
|
||||
representation is not portable from one host to another, but it is
|
||||
for backward compatibility with old-fashioned clients that do not
|
||||
emit symbolic open flags. */
|
||||
|
||||
static int
|
||||
decode_oflag (char const *oflag_string)
|
||||
{
|
||||
char *oflag_num_end;
|
||||
int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
|
||||
int symbolic_oflag = 0;
|
||||
|
||||
oflag_string = oflag_num_end;
|
||||
while (ISSPACE ((unsigned char) *oflag_string))
|
||||
oflag_string++;
|
||||
|
||||
do
|
||||
{
|
||||
struct name_value_pair { char const *name; int value; };
|
||||
static struct name_value_pair const table[] =
|
||||
{
|
||||
#ifdef O_APPEND
|
||||
{"APPEND", O_APPEND},
|
||||
#endif
|
||||
{"CREAT", O_CREAT},
|
||||
#ifdef O_DSYNC
|
||||
{"DSYNC", O_DSYNC},
|
||||
#endif
|
||||
{"EXCL", O_EXCL},
|
||||
#ifdef O_LARGEFILE
|
||||
{"LARGEFILE", O_LARGEFILE}, /* LFS extension for opening large files */
|
||||
#endif
|
||||
#ifdef O_NOCTTY
|
||||
{"NOCTTY", O_NOCTTY},
|
||||
#endif
|
||||
#ifdef O_NONBLOCK
|
||||
{"NONBLOCK", O_NONBLOCK},
|
||||
#endif
|
||||
{"RDONLY", O_RDONLY},
|
||||
{"RDWR", O_RDWR},
|
||||
#ifdef O_RSYNC
|
||||
{"RSYNC", O_RSYNC},
|
||||
#endif
|
||||
#ifdef O_SYNC
|
||||
{"SYNC", O_SYNC},
|
||||
#endif
|
||||
{"TRUNC", O_TRUNC},
|
||||
{"WRONLY", O_WRONLY}
|
||||
};
|
||||
struct name_value_pair const *t;
|
||||
size_t s;
|
||||
|
||||
if (*oflag_string++ != 'O' || *oflag_string++ != '_')
|
||||
return numeric_oflag;
|
||||
|
||||
for (t = table;
|
||||
(strncmp (oflag_string, t->name, s = strlen (t->name)) != 0
|
||||
|| (oflag_string[s]
|
||||
&& strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
|
||||
oflag_string[s])));
|
||||
t++)
|
||||
if (t == table + sizeof table / sizeof *table - 1)
|
||||
return numeric_oflag;
|
||||
|
||||
symbolic_oflag |= t->value;
|
||||
oflag_string += s;
|
||||
}
|
||||
while (*oflag_string++ == '|');
|
||||
|
||||
return symbolic_oflag;
|
||||
}
|
||||
|
||||
static struct option const long_opts[] =
|
||||
{
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]\n\
|
||||
Manipulate a tape drive, accepting commands from a remote process.\n\
|
||||
\n\
|
||||
--version Output version info.\n\
|
||||
--help Output this help.\n"),
|
||||
program_name);
|
||||
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
exit (status);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
char command;
|
||||
ssize_t status;
|
||||
|
||||
/* FIXME: Localization is meaningless, unless --help and --version are
|
||||
locally used. Localization would be best accomplished by the calling
|
||||
tar, on messages found within error packets. */
|
||||
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
switch (getopt_long (argc, argv, "", long_opts, NULL))
|
||||
{
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
case 'h':
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
case 'v':
|
||||
{
|
||||
printf ("rmt (%s) %s\n%s\n", PACKAGE_NAME, PACKAGE_VERSION,
|
||||
"Copyright (C) 2003 Free Software Foundation, Inc.");
|
||||
puts (_("\
|
||||
This program comes with NO WARRANTY, to the extent permitted by law.\n\
|
||||
You may redistribute it under the terms of the GNU General Public License;\n\
|
||||
see the file named COPYING for details."));
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case -1:
|
||||
break;
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
if (optind != argc - 1)
|
||||
usage (EXIT_FAILURE);
|
||||
debug_file = fopen (argv[optind], "w");
|
||||
if (debug_file == 0)
|
||||
{
|
||||
report_numbered_error (errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
setbuf (debug_file, 0);
|
||||
}
|
||||
|
||||
top:
|
||||
errno = 0;
|
||||
status = 0;
|
||||
if (safe_read (STDIN_FILENO, &command, 1) != 1)
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
/* FIXME: Maybe 'H' and 'V' for --help and --version output? */
|
||||
|
||||
case 'O':
|
||||
{
|
||||
char device_string[STRING_SIZE];
|
||||
char oflag_string[STRING_SIZE];
|
||||
|
||||
get_string (device_string);
|
||||
get_string (oflag_string);
|
||||
DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string);
|
||||
|
||||
if (tape >= 0)
|
||||
close (tape);
|
||||
|
||||
tape = open (device_string, decode_oflag (oflag_string), MODE_RW);
|
||||
if (tape < 0)
|
||||
goto ioerror;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
case 'C':
|
||||
{
|
||||
char device_string[STRING_SIZE];
|
||||
|
||||
get_string (device_string); /* discard */
|
||||
DEBUG ("rmtd: C\n");
|
||||
|
||||
if (close (tape) < 0)
|
||||
goto ioerror;
|
||||
tape = -1;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
case 'L':
|
||||
{
|
||||
char count_string[STRING_SIZE];
|
||||
char position_string[STRING_SIZE];
|
||||
off_t count = 0;
|
||||
int negative;
|
||||
int whence;
|
||||
char *p;
|
||||
|
||||
get_string (count_string);
|
||||
get_string (position_string);
|
||||
DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
|
||||
|
||||
/* Parse count_string, taking care to check for overflow.
|
||||
We can't use standard functions,
|
||||
since off_t might be longer than long. */
|
||||
|
||||
for (p = count_string; *p == ' ' || *p == '\t'; p++)
|
||||
continue;
|
||||
|
||||
negative = *p == '-';
|
||||
p += negative || *p == '+';
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int digit = *p++ - '0';
|
||||
if (9 < (unsigned) digit)
|
||||
break;
|
||||
else
|
||||
{
|
||||
off_t c10 = 10 * count;
|
||||
off_t nc = negative ? c10 - digit : c10 + digit;
|
||||
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
|
||||
{
|
||||
report_error_message (N_("Seek offset out of range"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
count = nc;
|
||||
}
|
||||
}
|
||||
|
||||
switch (atoi (position_string))
|
||||
{
|
||||
case 0: whence = SEEK_SET; break;
|
||||
case 1: whence = SEEK_CUR; break;
|
||||
case 2: whence = SEEK_END; break;
|
||||
default:
|
||||
report_error_message (N_("Seek direction out of range"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
count = lseek (tape, count, whence);
|
||||
if (count < 0)
|
||||
goto ioerror;
|
||||
|
||||
/* Convert count back to string for reply.
|
||||
We can't use sprintf, since off_t might be longer than long. */
|
||||
p = count_string + sizeof count_string;
|
||||
*--p = '\0';
|
||||
do
|
||||
*--p = '0' + (int) (count % 10);
|
||||
while ((count /= 10) != 0);
|
||||
|
||||
DEBUG1 ("rmtd: A %s\n", p);
|
||||
|
||||
sprintf (reply_buffer, "A%s\n", p);
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
goto top;
|
||||
}
|
||||
|
||||
case 'W':
|
||||
{
|
||||
char count_string[STRING_SIZE];
|
||||
size_t size;
|
||||
size_t counter;
|
||||
|
||||
get_string (count_string);
|
||||
size = atol (count_string);
|
||||
DEBUG1 ("rmtd: W %s\n", count_string);
|
||||
|
||||
prepare_input_buffer (STDIN_FILENO, size);
|
||||
for (counter = 0; counter < size; counter += status)
|
||||
{
|
||||
status = safe_read (STDIN_FILENO, &record_buffer[counter],
|
||||
size - counter);
|
||||
if (status <= 0)
|
||||
{
|
||||
DEBUG (_("rmtd: Premature eof\n"));
|
||||
|
||||
report_error_message (N_("Premature end of file"));
|
||||
return EXIT_FAILURE; /* exit status used to be 2 */
|
||||
}
|
||||
}
|
||||
status = full_write (tape, record_buffer, size);
|
||||
if (status < 0)
|
||||
goto ioerror;
|
||||
goto respond;
|
||||
}
|
||||
|
||||
case 'R':
|
||||
{
|
||||
char count_string[STRING_SIZE];
|
||||
size_t size;
|
||||
|
||||
get_string (count_string);
|
||||
DEBUG1 ("rmtd: R %s\n", count_string);
|
||||
|
||||
size = atol (count_string);
|
||||
prepare_input_buffer (-1, size);
|
||||
status = safe_read (tape, record_buffer, size);
|
||||
if (status < 0)
|
||||
goto ioerror;
|
||||
sprintf (reply_buffer, "A%ld\n", (long) status);
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
full_write (STDOUT_FILENO, record_buffer, status);
|
||||
goto top;
|
||||
}
|
||||
|
||||
case 'I':
|
||||
{
|
||||
char operation_string[STRING_SIZE];
|
||||
char count_string[STRING_SIZE];
|
||||
|
||||
get_string (operation_string);
|
||||
get_string (count_string);
|
||||
DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop mtop;
|
||||
const char *p;
|
||||
off_t count = 0;
|
||||
int negative;
|
||||
|
||||
/* Parse count_string, taking care to check for overflow.
|
||||
We can't use standard functions,
|
||||
since off_t might be longer than long. */
|
||||
|
||||
for (p = count_string; *p == ' ' || *p == '\t'; p++)
|
||||
continue;
|
||||
|
||||
negative = *p == '-';
|
||||
p += negative || *p == '+';
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int digit = *p++ - '0';
|
||||
if (9 < (unsigned) digit)
|
||||
break;
|
||||
else
|
||||
{
|
||||
off_t c10 = 10 * count;
|
||||
off_t nc = negative ? c10 - digit : c10 + digit;
|
||||
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
|
||||
{
|
||||
report_error_message (N_("Seek offset out of range"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
count = nc;
|
||||
}
|
||||
}
|
||||
|
||||
mtop.mt_count = count;
|
||||
if (mtop.mt_count != count)
|
||||
{
|
||||
report_error_message (N_("Seek offset out of range"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
mtop.mt_op = atoi (operation_string);
|
||||
|
||||
if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
|
||||
goto ioerror;
|
||||
}
|
||||
#endif
|
||||
goto respond;
|
||||
}
|
||||
|
||||
case 'S': /* status */
|
||||
{
|
||||
DEBUG ("rmtd: S\n");
|
||||
|
||||
#ifdef MTIOCGET
|
||||
{
|
||||
struct mtget operation;
|
||||
|
||||
if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
|
||||
goto ioerror;
|
||||
status = sizeof operation;
|
||||
sprintf (reply_buffer, "A%ld\n", (long) status);
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
full_write (STDOUT_FILENO, (char *) &operation, sizeof operation);
|
||||
}
|
||||
#endif
|
||||
goto top;
|
||||
}
|
||||
|
||||
default:
|
||||
DEBUG1 (_("rmtd: Garbage command %c\n"), command);
|
||||
|
||||
report_error_message (N_("Garbage command"));
|
||||
return EXIT_FAILURE; /* exit status used to be 3 */
|
||||
}
|
||||
|
||||
respond:
|
||||
DEBUG1 ("rmtd: A %ld\n", (long) status);
|
||||
|
||||
sprintf (reply_buffer, "A%ld\n", (long) status);
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
goto top;
|
||||
|
||||
ioerror:
|
||||
report_numbered_error (errno);
|
||||
goto top;
|
||||
}
|
||||
95
src/rmt.h
95
src/rmt.h
@@ -1,95 +0,0 @@
|
||||
/* Definitions for communicating with a remote tape drive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1996, 1997, 2001, 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
extern char *rmt_path__;
|
||||
|
||||
int rmt_open__ (const char *, int, int, const char *);
|
||||
int rmt_close__ (int);
|
||||
ssize_t rmt_read__ (int, char *, size_t);
|
||||
ssize_t rmt_write__ (int, char *, size_t);
|
||||
off_t rmt_lseek__ (int, off_t, int);
|
||||
int rmt_ioctl__ (int, int, char *);
|
||||
|
||||
/* A filename is remote if it contains a colon not preceded by a slash,
|
||||
to take care of `/:/' which is a shorthand for `/.../<CELL-NAME>/fs'
|
||||
on machines running OSF's Distributing Computing Environment (DCE) and
|
||||
Distributed File System (DFS). However, when --force-local, a
|
||||
filename is never remote. */
|
||||
|
||||
#define _remdev(Path) \
|
||||
(!force_local_option && (rmt_path__ = strchr (Path, ':')) \
|
||||
&& rmt_path__ > (Path) && ! memchr (Path, rmt_path__ - (Path), '/'))
|
||||
|
||||
#define _isrmt(Fd) \
|
||||
((Fd) >= __REM_BIAS)
|
||||
|
||||
#define __REM_BIAS (1 << 30)
|
||||
|
||||
#ifndef O_CREAT
|
||||
# define O_CREAT 01000
|
||||
#endif
|
||||
|
||||
#define rmtopen(Path, Oflag, Mode, Command) \
|
||||
(_remdev (Path) ? rmt_open__ (Path, Oflag, __REM_BIAS, Command) \
|
||||
: open (Path, Oflag, Mode))
|
||||
|
||||
#define rmtaccess(Path, Amode) \
|
||||
(_remdev (Path) ? 0 : access (Path, Amode))
|
||||
|
||||
#define rmtstat(Path, Buffer) \
|
||||
(_remdev (Path) ? (errno = EOPNOTSUPP), -1 : stat (Path, Buffer))
|
||||
|
||||
#define rmtcreat(Path, Mode, Command) \
|
||||
(_remdev (Path) \
|
||||
? rmt_open__ (Path, 1 | O_CREAT, __REM_BIAS, Command) \
|
||||
: creat (Path, Mode))
|
||||
|
||||
#define rmtlstat(Path, Buffer) \
|
||||
(_remdev (Path) ? (errno = EOPNOTSUPP), -1 : lstat (Path, Buffer))
|
||||
|
||||
#define rmtread(Fd, Buffer, Length) \
|
||||
(_isrmt (Fd) ? rmt_read__ (Fd - __REM_BIAS, Buffer, Length) \
|
||||
: safe_read (Fd, Buffer, Length))
|
||||
|
||||
#define rmtwrite(Fd, Buffer, Length) \
|
||||
(_isrmt (Fd) ? rmt_write__ (Fd - __REM_BIAS, Buffer, Length) \
|
||||
: full_write (Fd, Buffer, Length))
|
||||
|
||||
#define rmtlseek(Fd, Offset, Where) \
|
||||
(_isrmt (Fd) ? rmt_lseek__ (Fd - __REM_BIAS, Offset, Where) \
|
||||
: lseek (Fd, Offset, Where))
|
||||
|
||||
#define rmtclose(Fd) \
|
||||
(_isrmt (Fd) ? rmt_close__ (Fd - __REM_BIAS) : close (Fd))
|
||||
|
||||
#define rmtioctl(Fd, Request, Argument) \
|
||||
(_isrmt (Fd) ? rmt_ioctl__ (Fd - __REM_BIAS, Request, Argument) \
|
||||
: ioctl (Fd, Request, Argument))
|
||||
|
||||
#define rmtdup(Fd) \
|
||||
(_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : dup (Fd))
|
||||
|
||||
#define rmtfstat(Fd, Buffer) \
|
||||
(_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : fstat (Fd, Buffer))
|
||||
|
||||
#define rmtfcntl(Fd, Command, Argument) \
|
||||
(_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : fcntl (Fd, Command, Argument))
|
||||
|
||||
#define rmtisatty(Fd) \
|
||||
(_isrmt (Fd) ? 0 : isatty (Fd))
|
||||
715
src/rtapelib.c
715
src/rtapelib.c
@@ -1,715 +0,0 @@
|
||||
/* Functions for communicating with a remote tape drive.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
|
||||
which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
|
||||
The author of the routines I'm including originally wrote his code just
|
||||
based on the man page, and it didn't work, so he went to the rdump source
|
||||
to figure out why. The only thing he had to change was to check for the
|
||||
'F' return code in addition to the 'E', and to separate the various
|
||||
arguments with \n instead of a space. I personally don't think that this
|
||||
is much of a problem, but I wanted to point it out. -- Arnold Robbins
|
||||
|
||||
Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
|
||||
as a library that can replace open, read, write, etc., by Fred Fish, with
|
||||
some additional work by Arnold Robbins. Modified to make all rmt* calls
|
||||
into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec
|
||||
code, courtesy of Dan Kegel. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <safe-read.h>
|
||||
#include <full-write.h>
|
||||
|
||||
/* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
|
||||
3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */
|
||||
|
||||
#ifndef EOPNOTSUPP
|
||||
# if HAVE_NET_ERRNO_H
|
||||
# include <net/errno.h>
|
||||
# endif
|
||||
# if HAVE_SYS_INET_H
|
||||
# include <sys/inet.h>
|
||||
# endif
|
||||
# ifndef EOPNOTSUPP
|
||||
# define EOPNOTSUPP EINVAL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#if HAVE_NETDB_H
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "rmt.h"
|
||||
|
||||
/* Exit status if exec errors. */
|
||||
#define EXIT_ON_EXEC_ERROR 128
|
||||
|
||||
/* FIXME: Size of buffers for reading and writing commands to rmt. */
|
||||
#define COMMAND_BUFFER_SIZE 64
|
||||
|
||||
#ifndef RETSIGTYPE
|
||||
# define RETSIGTYPE void
|
||||
#endif
|
||||
|
||||
/* FIXME: Maximum number of simultaneous remote tape connections. */
|
||||
#define MAXUNIT 4
|
||||
|
||||
#define PREAD 0 /* read file descriptor from pipe() */
|
||||
#define PWRITE 1 /* write file descriptor from pipe() */
|
||||
|
||||
/* Return the parent's read side of remote tape connection Fd. */
|
||||
#define READ_SIDE(Fd) (from_remote[Fd][PREAD])
|
||||
|
||||
/* Return the parent's write side of remote tape connection Fd. */
|
||||
#define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
|
||||
|
||||
/* The pipes for receiving data from remote tape drives. */
|
||||
static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
|
||||
|
||||
/* The pipes for sending data to remote tape drives. */
|
||||
static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
|
||||
|
||||
/* Temporary variable used by macros in rmt.h. */
|
||||
char *rmt_path__;
|
||||
|
||||
|
||||
/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */
|
||||
static void
|
||||
_rmt_shutdown (int handle, int errno_value)
|
||||
{
|
||||
close (READ_SIDE (handle));
|
||||
close (WRITE_SIDE (handle));
|
||||
READ_SIDE (handle) = -1;
|
||||
WRITE_SIDE (handle) = -1;
|
||||
errno = errno_value;
|
||||
}
|
||||
|
||||
/* Attempt to perform the remote tape command specified in BUFFER on
|
||||
remote tape connection HANDLE. Return 0 if successful, -1 on
|
||||
error. */
|
||||
static int
|
||||
do_command (int handle, const char *buffer)
|
||||
{
|
||||
/* Save the current pipe handler and try to make the request. */
|
||||
|
||||
size_t length = strlen (buffer);
|
||||
RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN);
|
||||
ssize_t written = full_write (WRITE_SIDE (handle), buffer, length);
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
|
||||
if (written == length)
|
||||
return 0;
|
||||
|
||||
/* Something went wrong. Close down and go home. */
|
||||
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_status_string (int handle, char *command_buffer)
|
||||
{
|
||||
char *cursor;
|
||||
int counter;
|
||||
|
||||
/* Read the reply command line. */
|
||||
|
||||
for (counter = 0, cursor = command_buffer;
|
||||
counter < COMMAND_BUFFER_SIZE;
|
||||
counter++, cursor++)
|
||||
{
|
||||
if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return 0;
|
||||
}
|
||||
if (*cursor == '\n')
|
||||
{
|
||||
*cursor = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == COMMAND_BUFFER_SIZE)
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the return status. */
|
||||
|
||||
for (cursor = command_buffer; *cursor; cursor++)
|
||||
if (*cursor != ' ')
|
||||
break;
|
||||
|
||||
if (*cursor == 'E' || *cursor == 'F')
|
||||
{
|
||||
errno = atoi (cursor + 1);
|
||||
|
||||
/* Skip the error message line. */
|
||||
|
||||
/* FIXME: there is better to do than merely ignoring error messages
|
||||
coming from the remote end. Translate them, too... */
|
||||
|
||||
{
|
||||
char character;
|
||||
|
||||
while (safe_read (READ_SIDE (handle), &character, 1) == 1)
|
||||
if (character == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
if (*cursor == 'F')
|
||||
_rmt_shutdown (handle, errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for mis-synced pipes. */
|
||||
|
||||
if (*cursor != 'A')
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Got an `A' (success) response. */
|
||||
|
||||
return cursor + 1;
|
||||
}
|
||||
|
||||
/* Read and return the status from remote tape connection HANDLE. If
|
||||
an error occurred, return -1 and set errno. */
|
||||
static long
|
||||
get_status (int handle)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
const char *status = get_status_string (handle, command_buffer);
|
||||
return status ? atol (status) : -1L;
|
||||
}
|
||||
|
||||
static off_t
|
||||
get_status_off (int handle)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
const char *status = get_status_string (handle, command_buffer);
|
||||
|
||||
if (! status)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
/* Parse status, taking care to check for overflow.
|
||||
We can't use standard functions,
|
||||
since off_t might be longer than long. */
|
||||
|
||||
off_t count = 0;
|
||||
int negative;
|
||||
|
||||
for (; *status == ' ' || *status == '\t'; status++)
|
||||
continue;
|
||||
|
||||
negative = *status == '-';
|
||||
status += negative || *status == '+';
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int digit = *status++ - '0';
|
||||
if (9 < (unsigned) digit)
|
||||
break;
|
||||
else
|
||||
{
|
||||
off_t c10 = 10 * count;
|
||||
off_t nc = negative ? c10 - digit : c10 + digit;
|
||||
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
|
||||
return -1;
|
||||
count = nc;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_REXEC
|
||||
|
||||
/* Execute /etc/rmt as user USER on remote system HOST using rexec.
|
||||
Return a file descriptor of a bidirectional socket for stdin and
|
||||
stdout. If USER is zero, use the current username.
|
||||
|
||||
By default, this code is not used, since it requires that the user
|
||||
have a .netrc file in his/her home directory, or that the
|
||||
application designer be willing to have rexec prompt for login and
|
||||
password info. This may be unacceptable, and .rhosts files for use
|
||||
with rsh are much more common on BSD systems. */
|
||||
static int
|
||||
_rmt_rexec (char *host, char *user)
|
||||
{
|
||||
int saved_stdin = dup (STDIN_FILENO);
|
||||
int saved_stdout = dup (STDOUT_FILENO);
|
||||
struct servent *rexecserv;
|
||||
int result;
|
||||
|
||||
/* When using cpio -o < filename, stdin is no longer the tty. But the
|
||||
rexec subroutine reads the login and the passwd on stdin, to allow
|
||||
remote execution of the command. So, reopen stdin and stdout on
|
||||
/dev/tty before the rexec and give them back their original value
|
||||
after. */
|
||||
|
||||
if (! freopen ("/dev/tty", "r", stdin))
|
||||
freopen ("/dev/null", "r", stdin);
|
||||
if (! freopen ("/dev/tty", "w", stdout))
|
||||
freopen ("/dev/null", "w", stdout);
|
||||
|
||||
if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
|
||||
error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
|
||||
|
||||
result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
|
||||
if (fclose (stdin) == EOF)
|
||||
error (0, errno, _("stdin"));
|
||||
fdopen (saved_stdin, "r");
|
||||
if (fclose (stdout) == EOF)
|
||||
error (0, errno, _("stdout"));
|
||||
fdopen (saved_stdout, "w");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* WITH_REXEC */
|
||||
|
||||
/* Place into BUF a string representing OFLAG, which must be suitable
|
||||
as argument 2 of `open'. BUF must be large enough to hold the
|
||||
result. This function should generate a string that decode_oflag
|
||||
can parse. */
|
||||
static void
|
||||
encode_oflag (char *buf, int oflag)
|
||||
{
|
||||
sprintf (buf, "%d ", oflag);
|
||||
|
||||
switch (oflag & O_ACCMODE)
|
||||
{
|
||||
case O_RDONLY: strcat (buf, "O_RDONLY"); break;
|
||||
case O_RDWR: strcat (buf, "O_RDWR"); break;
|
||||
case O_WRONLY: strcat (buf, "O_WRONLY"); break;
|
||||
default: abort ();
|
||||
}
|
||||
|
||||
#ifdef O_APPEND
|
||||
if (oflag & O_APPEND) strcat (buf, "|O_APPEND");
|
||||
#endif
|
||||
if (oflag & O_CREAT) strcat (buf, "|O_CREAT");
|
||||
#ifdef O_DSYNC
|
||||
if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC");
|
||||
#endif
|
||||
if (oflag & O_EXCL) strcat (buf, "|O_EXCL");
|
||||
#ifdef O_LARGEFILE
|
||||
if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE");
|
||||
#endif
|
||||
#ifdef O_NOCTTY
|
||||
if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY");
|
||||
#endif
|
||||
#ifdef O_NONBLOCK
|
||||
if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
|
||||
#endif
|
||||
#ifdef O_RSYNC
|
||||
if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC");
|
||||
#endif
|
||||
#ifdef O_SYNC
|
||||
if (oflag & O_SYNC) strcat (buf, "|O_SYNC");
|
||||
#endif
|
||||
if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC");
|
||||
}
|
||||
|
||||
/* Open a file (a magnetic tape device?) on the system specified in
|
||||
PATH, as the given user. PATH has the form `[USER@]HOST:FILE'.
|
||||
OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the
|
||||
remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On
|
||||
error, return -1. */
|
||||
int
|
||||
rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
|
||||
{
|
||||
int remote_pipe_number; /* pseudo, biased file descriptor */
|
||||
char *path_copy ; /* copy of path string */
|
||||
char *remote_host; /* remote host name */
|
||||
char *remote_file; /* remote file name (often a device) */
|
||||
char *remote_user; /* remote user name */
|
||||
|
||||
/* Find an unused pair of file descriptors. */
|
||||
|
||||
for (remote_pipe_number = 0;
|
||||
remote_pipe_number < MAXUNIT;
|
||||
remote_pipe_number++)
|
||||
if (READ_SIDE (remote_pipe_number) == -1
|
||||
&& WRITE_SIDE (remote_pipe_number) == -1)
|
||||
break;
|
||||
|
||||
if (remote_pipe_number == MAXUNIT)
|
||||
{
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pull apart the system and device, and optional user. */
|
||||
|
||||
{
|
||||
char *cursor;
|
||||
|
||||
path_copy = xstrdup (path);
|
||||
remote_host = path_copy;
|
||||
remote_user = 0;
|
||||
remote_file = 0;
|
||||
|
||||
for (cursor = path_copy; *cursor; cursor++)
|
||||
switch (*cursor)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
/* Do not allow newlines in the path, since the protocol
|
||||
uses newline delimiters. */
|
||||
free (path_copy);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
|
||||
case '@':
|
||||
if (!remote_user)
|
||||
{
|
||||
remote_user = remote_host;
|
||||
*cursor = '\0';
|
||||
remote_host = cursor + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (!remote_file)
|
||||
{
|
||||
*cursor = '\0';
|
||||
remote_file = cursor + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: Should somewhat validate the decoding, here. */
|
||||
|
||||
if (remote_user && *remote_user == '\0')
|
||||
remote_user = 0;
|
||||
|
||||
#if WITH_REXEC
|
||||
|
||||
/* Execute the remote command using rexec. */
|
||||
|
||||
READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
|
||||
if (READ_SIDE (remote_pipe_number) < 0)
|
||||
{
|
||||
int e = errno;
|
||||
free (path_copy);
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
|
||||
|
||||
#else /* not WITH_REXEC */
|
||||
{
|
||||
const char *remote_shell_basename;
|
||||
pid_t status;
|
||||
|
||||
/* Identify the remote command to be executed. */
|
||||
|
||||
if (!remote_shell)
|
||||
{
|
||||
#ifdef REMOTE_SHELL
|
||||
remote_shell = REMOTE_SHELL;
|
||||
#else
|
||||
free (path_copy);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
remote_shell_basename = base_name (remote_shell);
|
||||
|
||||
/* Set up the pipes for the `rsh' command, and fork. */
|
||||
|
||||
if (pipe (to_remote[remote_pipe_number]) == -1
|
||||
|| pipe (from_remote[remote_pipe_number]) == -1)
|
||||
{
|
||||
int e = errno;
|
||||
free (path_copy);
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = fork ();
|
||||
if (status == -1)
|
||||
{
|
||||
int e = errno;
|
||||
free (path_copy);
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
/* Child. */
|
||||
|
||||
close (STDIN_FILENO);
|
||||
dup (to_remote[remote_pipe_number][PREAD]);
|
||||
close (to_remote[remote_pipe_number][PREAD]);
|
||||
close (to_remote[remote_pipe_number][PWRITE]);
|
||||
|
||||
close (STDOUT_FILENO);
|
||||
dup (from_remote[remote_pipe_number][PWRITE]);
|
||||
close (from_remote[remote_pipe_number][PREAD]);
|
||||
close (from_remote[remote_pipe_number][PWRITE]);
|
||||
|
||||
sys_reset_uid_gid ();
|
||||
|
||||
if (remote_user)
|
||||
execl (remote_shell, remote_shell_basename, remote_host,
|
||||
"-l", remote_user, "/etc/rmt", (char *) 0);
|
||||
else
|
||||
execl (remote_shell, remote_shell_basename, remote_host,
|
||||
"/etc/rmt", (char *) 0);
|
||||
|
||||
/* Bad problems if we get here. */
|
||||
|
||||
/* In a previous version, _exit was used here instead of exit. */
|
||||
error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
|
||||
}
|
||||
|
||||
/* Parent. */
|
||||
|
||||
close (from_remote[remote_pipe_number][PWRITE]);
|
||||
close (to_remote[remote_pipe_number][PREAD]);
|
||||
}
|
||||
#endif /* not WITH_REXEC */
|
||||
|
||||
/* Attempt to open the tape device. */
|
||||
|
||||
{
|
||||
size_t remote_file_len = strlen (remote_file);
|
||||
char *command_buffer = xmalloc (remote_file_len + 1000);
|
||||
sprintf (command_buffer, "O%s\n", remote_file);
|
||||
encode_oflag (command_buffer + remote_file_len + 2, open_mode);
|
||||
strcat (command_buffer, "\n");
|
||||
if (do_command (remote_pipe_number, command_buffer) == -1
|
||||
|| get_status (remote_pipe_number) == -1)
|
||||
{
|
||||
int e = errno;
|
||||
free (command_buffer);
|
||||
free (path_copy);
|
||||
_rmt_shutdown (remote_pipe_number, e);
|
||||
return -1;
|
||||
}
|
||||
free (command_buffer);
|
||||
}
|
||||
|
||||
free (path_copy);
|
||||
return remote_pipe_number + bias;
|
||||
}
|
||||
|
||||
/* Close remote tape connection HANDLE and shut down. Return 0 if
|
||||
successful, -1 on error. */
|
||||
int
|
||||
rmt_close__ (int handle)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (do_command (handle, "C\n") == -1)
|
||||
return -1;
|
||||
|
||||
status = get_status (handle);
|
||||
_rmt_shutdown (handle, errno);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
|
||||
Return the number of bytes read on success, -1 on error. */
|
||||
ssize_t
|
||||
rmt_read__ (int handle, char *buffer, size_t length)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
ssize_t status, rlen;
|
||||
size_t counter;
|
||||
|
||||
sprintf (command_buffer, "R%lu\n", (unsigned long) length);
|
||||
if (do_command (handle, command_buffer) == -1
|
||||
|| (status = get_status (handle)) == -1)
|
||||
return -1;
|
||||
|
||||
for (counter = 0; counter < status; counter += rlen, buffer += rlen)
|
||||
{
|
||||
rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
|
||||
if (rlen <= 0)
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
|
||||
Return the number of bytes written on success, -1 on error. */
|
||||
ssize_t
|
||||
rmt_write__ (int handle, char *buffer, size_t length)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
RETSIGTYPE (*pipe_handler) ();
|
||||
size_t written;
|
||||
|
||||
sprintf (command_buffer, "W%lu\n", (unsigned long) length);
|
||||
if (do_command (handle, command_buffer) == -1)
|
||||
return -1;
|
||||
|
||||
pipe_handler = signal (SIGPIPE, SIG_IGN);
|
||||
written = full_write (WRITE_SIDE (handle), buffer, length);
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
if (written == length)
|
||||
return get_status (handle);
|
||||
|
||||
/* Write error. */
|
||||
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Perform an imitation lseek operation on remote tape connection
|
||||
HANDLE. Return the new file offset if successful, -1 if on error. */
|
||||
off_t
|
||||
rmt_lseek__ (int handle, off_t offset, int whence)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
char operand_buffer[UINTMAX_STRSIZE_BOUND];
|
||||
uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
|
||||
char *p = operand_buffer + sizeof operand_buffer;
|
||||
|
||||
do
|
||||
*--p = '0' + (int) (u % 10);
|
||||
while ((u /= 10) != 0);
|
||||
if (offset < 0)
|
||||
*--p = '-';
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET: whence = 0; break;
|
||||
case SEEK_CUR: whence = 1; break;
|
||||
case SEEK_END: whence = 2; break;
|
||||
default: abort ();
|
||||
}
|
||||
|
||||
sprintf (command_buffer, "L%s\n%d\n", p, whence);
|
||||
|
||||
if (do_command (handle, command_buffer) == -1)
|
||||
return -1;
|
||||
|
||||
return get_status_off (handle);
|
||||
}
|
||||
|
||||
/* Perform a raw tape operation on remote tape connection HANDLE.
|
||||
Return the results of the ioctl, or -1 on error. */
|
||||
int
|
||||
rmt_ioctl__ (int handle, int operation, char *argument)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
default:
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
case MTIOCTOP:
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
char operand_buffer[UINTMAX_STRSIZE_BOUND];
|
||||
uintmax_t u = (((struct mtop *) argument)->mt_count < 0
|
||||
? - (uintmax_t) ((struct mtop *) argument)->mt_count
|
||||
: (uintmax_t) ((struct mtop *) argument)->mt_count);
|
||||
char *p = operand_buffer + sizeof operand_buffer;
|
||||
|
||||
do
|
||||
*--p = '0' + (int) (u % 10);
|
||||
while ((u /= 10) != 0);
|
||||
if (((struct mtop *) argument)->mt_count < 0)
|
||||
*--p = '-';
|
||||
|
||||
/* MTIOCTOP is the easy one. Nothing is transferred in binary. */
|
||||
|
||||
sprintf (command_buffer, "I%d\n%s\n",
|
||||
((struct mtop *) argument)->mt_op, p);
|
||||
if (do_command (handle, command_buffer) == -1)
|
||||
return -1;
|
||||
|
||||
return get_status (handle);
|
||||
}
|
||||
#endif /* MTIOCTOP */
|
||||
|
||||
#ifdef MTIOCGET
|
||||
case MTIOCGET:
|
||||
{
|
||||
ssize_t status;
|
||||
ssize_t counter;
|
||||
|
||||
/* Grab the status and read it directly into the structure. This
|
||||
assumes that the status buffer is not padded and that 2 shorts
|
||||
fit in a long without any word alignment problems; i.e., the
|
||||
whole struct is contiguous. NOTE - this is probably NOT a good
|
||||
assumption. */
|
||||
|
||||
if (do_command (handle, "S") == -1
|
||||
|| (status = get_status (handle), status == -1))
|
||||
return -1;
|
||||
|
||||
for (; status > 0; status -= counter, argument += counter)
|
||||
{
|
||||
counter = safe_read (READ_SIDE (handle), argument, status);
|
||||
if (counter <= 0)
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for byte position. mt_type (or mt_model) is a small integer
|
||||
field (normally) so we will check its magnitude. If it is larger
|
||||
than 256, we will assume that the bytes are swapped and go through
|
||||
and reverse all the bytes. */
|
||||
|
||||
if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
|
||||
return 0;
|
||||
|
||||
for (counter = 0; counter < status; counter += 2)
|
||||
{
|
||||
char copy = argument[counter];
|
||||
|
||||
argument[counter] = argument[counter + 1];
|
||||
argument[counter + 1] = copy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* MTIOCGET */
|
||||
|
||||
}
|
||||
}
|
||||
263
src/sparse.c
263
src/sparse.c
@@ -1,6 +1,6 @@
|
||||
/* Functions for dealing with sparse files
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -16,7 +16,7 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
#include "common.h"
|
||||
|
||||
@@ -33,12 +33,14 @@ struct tar_sparse_optab
|
||||
{
|
||||
bool (*init) (struct tar_sparse_file *);
|
||||
bool (*done) (struct tar_sparse_file *);
|
||||
bool (*sparse_member_p) (struct tar_sparse_file *);
|
||||
bool (*dump_header) (struct tar_sparse_file *);
|
||||
bool (*fixup_header) (struct tar_sparse_file *);
|
||||
bool (*decode_header) (struct tar_sparse_file *);
|
||||
bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,
|
||||
void *);
|
||||
bool (*dump_region) (struct tar_sparse_file *, size_t index);
|
||||
bool (*extract_region) (struct tar_sparse_file *, size_t index);
|
||||
bool (*dump_region) (struct tar_sparse_file *, size_t);
|
||||
bool (*extract_region) (struct tar_sparse_file *, size_t);
|
||||
};
|
||||
|
||||
struct tar_sparse_file
|
||||
@@ -52,6 +54,14 @@ struct tar_sparse_file
|
||||
reqiure */
|
||||
};
|
||||
|
||||
static bool
|
||||
tar_sparse_member_p (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->sparse_member_p)
|
||||
return file->optab->sparse_member_p (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_init (struct tar_sparse_file *file)
|
||||
{
|
||||
@@ -79,18 +89,18 @@ tar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_dump_region (struct tar_sparse_file *file, size_t index)
|
||||
tar_sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
if (file->optab->dump_region)
|
||||
return file->optab->dump_region (file, index);
|
||||
return file->optab->dump_region (file, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_extract_region (struct tar_sparse_file *file, size_t index)
|
||||
tar_sparse_extract_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
if (file->optab->extract_region)
|
||||
return file->optab->extract_region (file, index);
|
||||
return file->optab->extract_region (file, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -107,7 +117,15 @@ tar_sparse_decode_header (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->decode_header)
|
||||
return file->optab->decode_header (file);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->fixup_header)
|
||||
return file->optab->fixup_header (file);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -171,13 +189,14 @@ sparse_scan_file (struct tar_sparse_file *file)
|
||||
return false;
|
||||
clear_block (buffer);
|
||||
|
||||
file->stat_info->sparse_map_size = 0;
|
||||
file->stat_info->sparse_map_avail = 0;
|
||||
file->stat_info->archive_file_size = 0;
|
||||
|
||||
|
||||
if (!tar_sparse_scan (file, scan_begin, NULL))
|
||||
return false;
|
||||
|
||||
while ((count = safe_read (file->fd, buffer, sizeof buffer)) > 0)
|
||||
while ((count = safe_read (file->fd, buffer, sizeof buffer)) != 0
|
||||
&& count != SAFE_READ_ERROR)
|
||||
{
|
||||
/* Analize the block */
|
||||
if (zero_block_p (buffer, count))
|
||||
@@ -199,11 +218,11 @@ sparse_scan_file (struct tar_sparse_file *file)
|
||||
if (!tar_sparse_scan (file, scan_block, buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
offset += count;
|
||||
clear_block (buffer);
|
||||
}
|
||||
|
||||
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
|
||||
@@ -237,7 +256,7 @@ sparse_select_optab (struct tar_sparse_file *file)
|
||||
case STAR_FORMAT:
|
||||
file->optab = &star_optab;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -245,28 +264,28 @@ sparse_select_optab (struct tar_sparse_file *file)
|
||||
}
|
||||
|
||||
static bool
|
||||
sparse_dump_region (struct tar_sparse_file *file, size_t index)
|
||||
sparse_dump_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
union block *blk;
|
||||
off_t bytes_left = file->stat_info->sparse_map[index].numbytes;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[index].offset,
|
||||
off_t bytes_left = file->stat_info->sparse_map[i].numbytes;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
|
||||
off_t bytes_read;
|
||||
|
||||
size_t bytes_read;
|
||||
|
||||
blk = find_next_block ();
|
||||
memset (blk->buffer, 0, BLOCKSIZE);
|
||||
bytes_read = safe_read (file->fd, blk->buffer, bufsize);
|
||||
if (bytes_read < 0)
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
file->stat_info->sparse_map[index].offset
|
||||
+ file->stat_info->sparse_map[index].numbytes
|
||||
file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].numbytes
|
||||
- bytes_left,
|
||||
bufsize);
|
||||
return false;
|
||||
@@ -281,15 +300,15 @@ sparse_dump_region (struct tar_sparse_file *file, size_t index)
|
||||
}
|
||||
|
||||
static bool
|
||||
sparse_extract_region (struct tar_sparse_file *file, size_t index)
|
||||
sparse_extract_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
size_t write_size;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[index].offset,
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
|
||||
write_size = file->stat_info->sparse_map[index].numbytes;
|
||||
write_size = file->stat_info->sparse_map[i].numbytes;
|
||||
|
||||
if (write_size == 0)
|
||||
{
|
||||
@@ -325,12 +344,12 @@ sparse_extract_region (struct tar_sparse_file *file, size_t index)
|
||||
|
||||
/* Interface functions */
|
||||
enum dump_status
|
||||
sparse_dump_file (int fd, struct tar_stat_info *stat)
|
||||
sparse_dump_file (int fd, struct tar_stat_info *st)
|
||||
{
|
||||
bool rc;
|
||||
struct tar_sparse_file file;
|
||||
|
||||
file.stat_info = stat;
|
||||
file.stat_info = st;
|
||||
file.fd = fd;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
@@ -357,21 +376,43 @@ sparse_dump_file (int fd, struct tar_stat_info *stat)
|
||||
|
||||
/* Returns true if the file represented by stat is a sparse one */
|
||||
bool
|
||||
sparse_file_p (struct tar_stat_info *stat)
|
||||
sparse_file_p (struct tar_stat_info *st)
|
||||
{
|
||||
return (ST_NBLOCKS (stat->stat)
|
||||
< (stat->stat.st_size / ST_NBLOCKSIZE
|
||||
+ (stat->stat.st_size % ST_NBLOCKSIZE != 0)));
|
||||
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)
|
||||
{
|
||||
struct tar_sparse_file file;
|
||||
|
||||
if (!sparse_select_optab (&file))
|
||||
return false;
|
||||
file.stat_info = st;
|
||||
return tar_sparse_member_p (&file);
|
||||
}
|
||||
|
||||
bool
|
||||
sparse_fixup_header (struct tar_stat_info *st)
|
||||
{
|
||||
struct tar_sparse_file file;
|
||||
|
||||
if (!sparse_select_optab (&file))
|
||||
return false;
|
||||
file.stat_info = st;
|
||||
return tar_sparse_fixup_header (&file);
|
||||
}
|
||||
|
||||
enum dump_status
|
||||
sparse_extract_file (int fd, struct tar_stat_info *stat, off_t *size)
|
||||
sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
size_t i;
|
||||
|
||||
file.stat_info = stat;
|
||||
|
||||
file.stat_info = st;
|
||||
file.fd = fd;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
@@ -385,25 +426,43 @@ sparse_extract_file (int fd, struct tar_stat_info *stat, off_t *size)
|
||||
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
|
||||
}
|
||||
|
||||
enum dump_status
|
||||
sparse_skip_file (struct tar_stat_info *st)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
|
||||
file.stat_info = st;
|
||||
file.fd = -1;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
|| !tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
|
||||
rc = tar_sparse_decode_header (&file);
|
||||
skip_file (file.stat_info->archive_file_size);
|
||||
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
|
||||
}
|
||||
|
||||
|
||||
static char diff_buffer[BLOCKSIZE];
|
||||
|
||||
|
||||
static bool
|
||||
check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
{
|
||||
if (!lseek_or_error (file, beg, SEEK_SET))
|
||||
return false;
|
||||
|
||||
|
||||
while (beg < end)
|
||||
{
|
||||
size_t bytes_read;
|
||||
size_t rdsize = end - beg;
|
||||
|
||||
|
||||
if (rdsize > BLOCKSIZE)
|
||||
rdsize = BLOCKSIZE;
|
||||
clear_block (diff_buffer);
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read < 0)
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
beg,
|
||||
@@ -423,19 +482,19 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
}
|
||||
|
||||
static bool
|
||||
check_data_region (struct tar_sparse_file *file, size_t index)
|
||||
check_data_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
size_t size_left;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[index].offset,
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
size_left = file->stat_info->sparse_map[index].numbytes;
|
||||
size_left = file->stat_info->sparse_map[i].numbytes;
|
||||
while (size_left > 0)
|
||||
{
|
||||
size_t bytes_read;
|
||||
size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left;
|
||||
|
||||
|
||||
union block *blk = find_next_block ();
|
||||
if (!blk)
|
||||
{
|
||||
@@ -444,11 +503,11 @@ check_data_region (struct tar_sparse_file *file, size_t index)
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read < 0)
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
file->stat_info->sparse_map[index].offset
|
||||
+ file->stat_info->sparse_map[index].numbytes
|
||||
file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].numbytes
|
||||
- size_left,
|
||||
rdsize);
|
||||
return false;
|
||||
@@ -465,14 +524,14 @@ check_data_region (struct tar_sparse_file *file, size_t index)
|
||||
}
|
||||
|
||||
bool
|
||||
sparse_diff_file (int fd, struct tar_stat_info *stat)
|
||||
sparse_diff_file (int fd, struct tar_stat_info *st)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
size_t i;
|
||||
off_t offset = 0;
|
||||
|
||||
file.stat_info = stat;
|
||||
|
||||
file.stat_info = st;
|
||||
file.fd = fd;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
@@ -496,14 +555,14 @@ sparse_diff_file (int fd, struct tar_stat_info *stat)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Old GNU Format. The sparse file information is stored in the
|
||||
oldgnu_header in the following manner:
|
||||
|
||||
The header is marked with type 'S'. Its `size' field contains
|
||||
the cumulative size of all non-empty blocks of the file. The
|
||||
actual file size is stored in `realsize' member of oldgnu_header.
|
||||
|
||||
|
||||
The map of the file is stored in a list of `struct sparse'.
|
||||
Each struct contains offset to the block of data and its
|
||||
size (both as octal numbers). The first file header contains
|
||||
@@ -522,8 +581,14 @@ enum oldgnu_add_status
|
||||
add_fail
|
||||
};
|
||||
|
||||
static bool
|
||||
oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
|
||||
{
|
||||
return current_header->header.typeflag == GNUTYPE_SPARSE;
|
||||
}
|
||||
|
||||
/* Add a sparse item to the sparse file and its obstack */
|
||||
static enum oldgnu_add_status
|
||||
static enum oldgnu_add_status
|
||||
oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
|
||||
{
|
||||
struct sp_array sp;
|
||||
@@ -541,8 +606,18 @@ oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
|
||||
return add_ok;
|
||||
}
|
||||
|
||||
/* Convert old GNU format sparse data to internal representation
|
||||
FIXME: Clubbers current_header! */
|
||||
static bool
|
||||
oldgnu_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* NOTE! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert old GNU format sparse data to internal representation */
|
||||
static bool
|
||||
oldgnu_get_sparse_info (struct tar_sparse_file *file)
|
||||
{
|
||||
@@ -550,14 +625,8 @@ oldgnu_get_sparse_info (struct tar_sparse_file *file)
|
||||
union block *h = current_header;
|
||||
int ext_p;
|
||||
static enum oldgnu_add_status rc;
|
||||
|
||||
/* FIXME: note this! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
|
||||
|
||||
file->stat_info->sparse_map_size = 0;
|
||||
|
||||
file->stat_info->sparse_map_avail = 0;
|
||||
for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
|
||||
{
|
||||
rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
|
||||
@@ -608,7 +677,7 @@ oldgnu_dump_header (struct tar_sparse_file *file)
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
union block *blk;
|
||||
size_t i;
|
||||
|
||||
|
||||
blk = start_header (file->stat_info);
|
||||
blk->header.typeflag = GNUTYPE_SPARSE;
|
||||
if (file->stat_info->sparse_map_avail > SPARSES_IN_OLDGNU_HEADER)
|
||||
@@ -625,7 +694,7 @@ oldgnu_dump_header (struct tar_sparse_file *file)
|
||||
SPARSES_IN_OLDGNU_HEADER);
|
||||
blk->oldgnu_header.isextended = i < file->stat_info->sparse_map_avail;
|
||||
finish_header (file->stat_info, blk, block_ordinal);
|
||||
|
||||
|
||||
while (i < file->stat_info->sparse_map_avail)
|
||||
{
|
||||
blk = find_next_block ();
|
||||
@@ -645,7 +714,9 @@ oldgnu_dump_header (struct tar_sparse_file *file)
|
||||
static struct tar_sparse_optab oldgnu_optab = {
|
||||
NULL, /* No init function */
|
||||
NULL, /* No done function */
|
||||
oldgnu_sparse_member_p,
|
||||
oldgnu_dump_header,
|
||||
oldgnu_fixup_header,
|
||||
oldgnu_get_sparse_info,
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
@@ -655,8 +726,24 @@ static struct tar_sparse_optab oldgnu_optab = {
|
||||
|
||||
/* Star */
|
||||
|
||||
/* Convert STAR format sparse data to internal representation
|
||||
FIXME: Clubbers current_header! */
|
||||
static bool
|
||||
star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
|
||||
{
|
||||
return current_header->header.typeflag == GNUTYPE_SPARSE;
|
||||
}
|
||||
|
||||
static bool
|
||||
star_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* NOTE! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->star_in_header.realsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert STAR format sparse data to internal representation */
|
||||
static bool
|
||||
star_get_sparse_info (struct tar_sparse_file *file)
|
||||
{
|
||||
@@ -664,14 +751,8 @@ star_get_sparse_info (struct tar_sparse_file *file)
|
||||
union block *h = current_header;
|
||||
int ext_p;
|
||||
static enum oldgnu_add_status rc;
|
||||
|
||||
/* FIXME: note this! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->star_in_header.realsize);
|
||||
|
||||
file->stat_info->sparse_map_size = 0;
|
||||
|
||||
file->stat_info->sparse_map_avail = 0;
|
||||
|
||||
if (h->star_in_header.prefix[0] == '\0'
|
||||
&& h->star_in_header.sp[0].offset[10] != '\0')
|
||||
@@ -714,10 +795,12 @@ star_get_sparse_info (struct tar_sparse_file *file)
|
||||
static struct tar_sparse_optab star_optab = {
|
||||
NULL, /* No init function */
|
||||
NULL, /* No done function */
|
||||
star_sparse_member_p,
|
||||
NULL,
|
||||
star_fixup_header,
|
||||
star_get_sparse_info,
|
||||
NULL, /* No scan_block function */
|
||||
NULL, /* No dump region function */
|
||||
NULL, /* No dump region function */
|
||||
sparse_extract_region,
|
||||
};
|
||||
|
||||
@@ -733,6 +816,12 @@ static struct tar_sparse_optab star_optab = {
|
||||
end repeat
|
||||
*/
|
||||
|
||||
static bool
|
||||
pax_sparse_member_p (struct tar_sparse_file *file)
|
||||
{
|
||||
return file->stat_info->archive_file_size != file->stat_info->stat.st_size;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_dump_header (struct tar_sparse_file *file)
|
||||
{
|
||||
@@ -748,7 +837,7 @@ pax_dump_header (struct tar_sparse_file *file)
|
||||
xheader_store ("GNU.sparse.offset", file->stat_info, &i);
|
||||
xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
|
||||
}
|
||||
|
||||
|
||||
blk = start_header (file->stat_info);
|
||||
/* Store the effective (shrunken) file size */
|
||||
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
|
||||
@@ -756,21 +845,13 @@ pax_dump_header (struct tar_sparse_file *file)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_decode_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* Restore actual size */
|
||||
size_t s = file->stat_info->archive_file_size;
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct tar_sparse_optab pax_optab = {
|
||||
NULL, /* No init function */
|
||||
NULL, /* No done function */
|
||||
pax_sparse_member_p,
|
||||
pax_dump_header,
|
||||
pax_decode_header,
|
||||
NULL, /* No decode_header function */
|
||||
NULL, /* No fixup_header function */
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
|
||||
133
src/system.c
133
src/system.c
@@ -1,6 +1,6 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@@ -16,53 +16,40 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "rmt.h"
|
||||
#include <rmt.h>
|
||||
#include <signal.h>
|
||||
|
||||
void
|
||||
sys_stat_nanoseconds(struct tar_stat_info *stat)
|
||||
sys_stat_nanoseconds (struct tar_stat_info *st)
|
||||
{
|
||||
#if defined(HAVE_STRUCT_STAT_ST_SPARE1)
|
||||
stat->atime_nsec = stat->stat.st_spare1 * 1000;
|
||||
stat->mtime_nsec = stat->stat.st_spare2 * 1000;
|
||||
stat->ctime_nsec = stat->stat.st_spare3 * 1000;
|
||||
st->atime_nsec = st->stat.st_spare1 * 1000;
|
||||
st->mtime_nsec = st->stat.st_spare2 * 1000;
|
||||
st->ctime_nsec = st->stat.st_spare3 * 1000;
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
|
||||
stat->atime_nsec = stat->stat.st_atim.tv_nsec;
|
||||
stat->mtime_nsec = stat->stat.st_mtim.tv_nsec;
|
||||
stat->ctime_nsec = stat->stat.st_ctim.tv_nsec;
|
||||
st->atime_nsec = st->stat.st_atim.tv_nsec;
|
||||
st->mtime_nsec = st->stat.st_mtim.tv_nsec;
|
||||
st->ctime_nsec = st->stat.st_ctim.tv_nsec;
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
|
||||
stat->atime_nsec = stat->stat.st_atimespec.tv_nsec;
|
||||
stat->mtime_nsec = stat->stat.st_mtimespec.tv_nsec;
|
||||
stat->ctime_nsec = stat->stat.st_ctimespec.tv_nsec;
|
||||
st->atime_nsec = st->stat.st_atimespec.tv_nsec;
|
||||
st->mtime_nsec = st->stat.st_mtimespec.tv_nsec;
|
||||
st->ctime_nsec = st->stat.st_ctimespec.tv_nsec;
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
|
||||
stat->atime_nsec = stat->stat.st_atimensec;
|
||||
stat->mtime_nsec = stat->stat.st_mtimensec;
|
||||
stat->ctime_nsec = stat->stat.st_ctimensec;
|
||||
st->atime_nsec = st->stat.st_atimensec;
|
||||
st->mtime_nsec = st->stat.st_mtimensec;
|
||||
st->ctime_nsec = st->stat.st_ctimensec;
|
||||
#else
|
||||
stat->atime_nsec = stat->mtime_nsec = stat->ctime_nsec = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
sys_utimes(char *file_name, struct timeval tvp[3])
|
||||
{
|
||||
#ifdef HAVE_UTIMES
|
||||
return utimes (file_name, tvp);
|
||||
#else
|
||||
struct utimbuf utimbuf;
|
||||
utimbuf.actime = tvp[0].tv_sec;
|
||||
utimbuf.modtime = tvp[1].tv_sec;
|
||||
return utime (file_name, &utimbuf);
|
||||
st->atime_nsec = st->mtime_nsec = st->ctime_nsec = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MSDOS
|
||||
|
||||
bool
|
||||
sys_get_archive_stat ()
|
||||
sys_get_archive_stat (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -74,12 +61,12 @@ sys_file_is_archive (struct tar_stat_info *p)
|
||||
}
|
||||
|
||||
void
|
||||
sys_save_archive_dev_ino ()
|
||||
sys_save_archive_dev_ino (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_detect_dev_null_output ()
|
||||
sys_detect_dev_null_output (void)
|
||||
{
|
||||
static char const dev_null[] = "nul";
|
||||
|
||||
@@ -88,7 +75,7 @@ sys_detect_dev_null_output ()
|
||||
}
|
||||
|
||||
void
|
||||
sys_drain_input_pipe ()
|
||||
sys_drain_input_pipe (void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -98,7 +85,7 @@ sys_wait_for_child (pid_t child_pid)
|
||||
}
|
||||
|
||||
void
|
||||
sys_spawn_shell ()
|
||||
sys_spawn_shell (void)
|
||||
{
|
||||
spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
|
||||
}
|
||||
@@ -131,26 +118,10 @@ sys_truncate (int fd)
|
||||
return write (fd, "", 0);
|
||||
}
|
||||
|
||||
void
|
||||
sys_reset_uid_gid ()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t
|
||||
size_t
|
||||
sys_write_archive_buffer (void)
|
||||
{
|
||||
ssize_t status;
|
||||
ssize_t written = 0;
|
||||
|
||||
while (0 <= (status = full_write (archive, record_start->buffer + written,
|
||||
record_size - written)))
|
||||
{
|
||||
written += status;
|
||||
if (written == record_size)
|
||||
break;
|
||||
}
|
||||
|
||||
return written ? written : status;
|
||||
return full_write (archive, record_start->buffer, record_size);
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for writing, then compressing an archive. */
|
||||
@@ -174,11 +145,11 @@ extern union block *record_start; /* FIXME */
|
||||
static struct stat archive_stat; /* stat block for archive file */
|
||||
|
||||
bool
|
||||
sys_get_archive_stat ()
|
||||
sys_get_archive_stat (void)
|
||||
{
|
||||
return fstat (archive, &archive_stat) == 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
sys_file_is_archive (struct tar_stat_info *p)
|
||||
{
|
||||
@@ -187,7 +158,7 @@ sys_file_is_archive (struct tar_stat_info *p)
|
||||
|
||||
/* Save archive file inode and device numbers */
|
||||
void
|
||||
sys_save_archive_dev_ino ()
|
||||
sys_save_archive_dev_ino (void)
|
||||
{
|
||||
if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
|
||||
{
|
||||
@@ -200,7 +171,7 @@ sys_save_archive_dev_ino ()
|
||||
|
||||
/* Detect if outputting to "/dev/null". */
|
||||
void
|
||||
sys_detect_dev_null_output ()
|
||||
sys_detect_dev_null_output (void)
|
||||
{
|
||||
static char const dev_null[] = "/dev/null";
|
||||
struct stat dev_null_stat;
|
||||
@@ -219,12 +190,15 @@ sys_detect_dev_null_output ()
|
||||
work to do, we might have to revise this area in such time. */
|
||||
|
||||
void
|
||||
sys_drain_input_pipe ()
|
||||
sys_drain_input_pipe (void)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
if (access_mode == ACCESS_READ
|
||||
&& ! _isrmt (archive)
|
||||
&& (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
|
||||
while (rmtread (archive, record_start->buffer, record_size) > 0)
|
||||
while ((r = rmtread (archive, record_start->buffer, record_size)) != 0
|
||||
&& r != SAFE_READ_ERROR)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -252,7 +226,7 @@ sys_wait_for_child (pid_t child_pid)
|
||||
}
|
||||
|
||||
void
|
||||
sys_spawn_shell ()
|
||||
sys_spawn_shell (void)
|
||||
{
|
||||
pid_t child;
|
||||
const char *shell = getenv ("SHELL");
|
||||
@@ -302,13 +276,6 @@ sys_truncate (int fd)
|
||||
return pos < 0 ? -1 : ftruncate (fd, pos);
|
||||
}
|
||||
|
||||
void
|
||||
sys_reset_uid_gid ()
|
||||
{
|
||||
setuid (getuid ());
|
||||
setgid (getgid ());
|
||||
}
|
||||
|
||||
/* Return nonzero if NAME is the name of a regular file, or if the file
|
||||
does not exist (so it would be created as a regular file). */
|
||||
static int
|
||||
@@ -322,24 +289,10 @@ is_regular_file (const char *name)
|
||||
return errno == ENOENT;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
size_t
|
||||
sys_write_archive_buffer (void)
|
||||
{
|
||||
ssize_t status;
|
||||
ssize_t written = 0;
|
||||
|
||||
while (0 <= (status = rmtwrite (archive, record_start->buffer + written,
|
||||
record_size - written)))
|
||||
{
|
||||
written += status;
|
||||
if (written == record_size
|
||||
|| _isrmt (archive)
|
||||
|| ! (S_ISFIFO (archive_stat.st_mode)
|
||||
|| S_ISSOCK (archive_stat.st_mode)))
|
||||
break;
|
||||
}
|
||||
|
||||
return written ? written : status;
|
||||
return rmtwrite (archive, record_start->buffer, record_size);
|
||||
}
|
||||
|
||||
#define PREAD 0 /* read file descriptor from pipe() */
|
||||
@@ -471,7 +424,7 @@ sys_child_open_for_compress (void)
|
||||
|
||||
while (1)
|
||||
{
|
||||
ssize_t status = 0;
|
||||
size_t status = 0;
|
||||
char *cursor;
|
||||
size_t length;
|
||||
|
||||
@@ -484,13 +437,12 @@ sys_child_open_for_compress (void)
|
||||
size_t size = record_size - length;
|
||||
|
||||
status = safe_read (STDIN_FILENO, cursor, size);
|
||||
if (status <= 0)
|
||||
if (status == SAFE_READ_ERROR)
|
||||
read_fatal (use_compress_program_option);
|
||||
if (status == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
read_fatal (use_compress_program_option);
|
||||
|
||||
/* Copy the record. */
|
||||
|
||||
if (status == 0)
|
||||
@@ -553,7 +505,6 @@ sys_child_open_for_uncompress (void)
|
||||
{
|
||||
/* The parent tar is still here! Just clean up. */
|
||||
|
||||
read_full_records_option = 1;
|
||||
archive = parent_pipe[PREAD];
|
||||
xclose (parent_pipe[PWRITE]);
|
||||
return child_pid;
|
||||
@@ -628,13 +579,13 @@ sys_child_open_for_uncompress (void)
|
||||
char *cursor;
|
||||
size_t maximum;
|
||||
size_t count;
|
||||
ssize_t status;
|
||||
size_t status;
|
||||
|
||||
clear_read_error_count ();
|
||||
|
||||
error_loop:
|
||||
status = rmtread (archive, record_start->buffer, record_size);
|
||||
if (status < 0)
|
||||
if (status == SAFE_READ_ERROR)
|
||||
{
|
||||
archive_read_error ();
|
||||
goto error_loop;
|
||||
|
||||
513
src/system.h
513
src/system.h
@@ -1,513 +0,0 @@
|
||||
/* System dependent definitions for GNU tar.
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
#ifndef __attribute__
|
||||
/* This feature is available in gcc versions 2.5 and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
|
||||
# define __attribute__(Spec) /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
|
||||
as an argument to <ctype.h> macros like `isspace'. */
|
||||
#if STDC_HEADERS
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# define IN_CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
|
||||
#endif
|
||||
|
||||
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
|
||||
#define ISODIGIT(c) ((unsigned) (c) - '0' <= 7)
|
||||
#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
|
||||
#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
|
||||
|
||||
/* Declare string and memory handling routines. Take care that an ANSI
|
||||
string.h and pre-ANSI memory.h might conflict, and that memory.h and
|
||||
strings.h conflict on some systems. */
|
||||
|
||||
#if STDC_HEADERS || HAVE_STRING_H
|
||||
# include <string.h>
|
||||
# if !STDC_HEADERS && HAVE_MEMORY_H
|
||||
# include <memory.h>
|
||||
# endif
|
||||
#else
|
||||
# include <strings.h>
|
||||
# ifndef strchr
|
||||
# define strchr index
|
||||
# endif
|
||||
# ifndef strrchr
|
||||
# define strrchr rindex
|
||||
# endif
|
||||
# ifndef memcpy
|
||||
# define memcpy(d, s, n) bcopy ((char const *) (s), (char *) (d), n)
|
||||
# endif
|
||||
# ifndef memcmp
|
||||
# define memcmp(a, b, n) bcmp ((char const *) (a), (char const *) (b), n)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Declare errno. */
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* Declare open parameters. */
|
||||
|
||||
#if HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#else
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
/* Pick only one of the next three: */
|
||||
#ifndef O_RDONLY
|
||||
# define O_RDONLY 0 /* only allow read */
|
||||
#endif
|
||||
#ifndef O_WRONLY
|
||||
# define O_WRONLY 1 /* only allow write */
|
||||
#endif
|
||||
#ifndef O_RDWR
|
||||
# define O_RDWR 2 /* both are allowed */
|
||||
#endif
|
||||
#ifndef O_ACCMODE
|
||||
# define O_ACCMODE (O_RDONLY | O_RDWR | O_WRONLY)
|
||||
#endif
|
||||
/* The rest can be OR-ed in to the above: */
|
||||
#ifndef O_CREAT
|
||||
# define O_CREAT 8 /* create file if needed */
|
||||
#endif
|
||||
#ifndef O_EXCL
|
||||
# define O_EXCL 16 /* file cannot already exist */
|
||||
#endif
|
||||
#ifndef O_TRUNC
|
||||
# define O_TRUNC 32 /* truncate file on open */
|
||||
#endif
|
||||
/* MS-DOG forever, with my love! */
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
/* Declare file status routines and bits. */
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if !HAVE_LSTAT && !defined lstat
|
||||
# define lstat stat
|
||||
#endif
|
||||
|
||||
#if STX_HIDDEN && !_LARGE_FILES /* AIX */
|
||||
# ifdef stat
|
||||
# undef stat
|
||||
# endif
|
||||
# define stat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN)
|
||||
# ifdef lstat
|
||||
# undef lstat
|
||||
# endif
|
||||
# define lstat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN | STX_LINK)
|
||||
#endif
|
||||
|
||||
#if STAT_MACROS_BROKEN
|
||||
# undef S_ISBLK
|
||||
# undef S_ISCHR
|
||||
# undef S_ISCTG
|
||||
# undef S_ISDIR
|
||||
# undef S_ISFIFO
|
||||
# undef S_ISLNK
|
||||
# undef S_ISREG
|
||||
# undef S_ISSOCK
|
||||
#endif
|
||||
|
||||
/* On MSDOS, there are missing things from <sys/stat.h>. */
|
||||
#if MSDOS
|
||||
# define S_ISUID 0
|
||||
# define S_ISGID 0
|
||||
# define S_ISVTX 0
|
||||
#endif
|
||||
|
||||
#ifndef S_ISDIR
|
||||
# define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
#ifndef S_ISBLK
|
||||
# ifdef S_IFBLK
|
||||
# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
|
||||
# else
|
||||
# define S_ISBLK(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_ISCHR
|
||||
# ifdef S_IFCHR
|
||||
# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
|
||||
# else
|
||||
# define S_ISCHR(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_ISCTG
|
||||
# ifdef S_IFCTG
|
||||
# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
|
||||
# else
|
||||
# define S_ISCTG(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_ISDOOR
|
||||
# define S_ISDOOR(Mode) 0
|
||||
#endif
|
||||
#ifndef S_ISFIFO
|
||||
# ifdef S_IFIFO
|
||||
# define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
|
||||
# else
|
||||
# define S_ISFIFO(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_ISLNK
|
||||
# ifdef S_IFLNK
|
||||
# define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
|
||||
# else
|
||||
# define S_ISLNK(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef S_ISSOCK
|
||||
# ifdef S_IFSOCK
|
||||
# define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
|
||||
# else
|
||||
# define S_ISSOCK(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !HAVE_MKFIFO && !defined mkfifo && defined S_IFIFO
|
||||
# define mkfifo(Path, Mode) (mknod (Path, (Mode) | S_IFIFO, 0))
|
||||
#endif
|
||||
|
||||
#ifndef S_ISUID
|
||||
# define S_ISUID 0004000
|
||||
#endif
|
||||
#ifndef S_ISGID
|
||||
# define S_ISGID 0002000
|
||||
#endif
|
||||
#ifndef S_ISVTX
|
||||
# define S_ISVTX 0001000
|
||||
#endif
|
||||
#ifndef S_IRUSR
|
||||
# define S_IRUSR 0000400
|
||||
#endif
|
||||
#ifndef S_IWUSR
|
||||
# define S_IWUSR 0000200
|
||||
#endif
|
||||
#ifndef S_IXUSR
|
||||
# define S_IXUSR 0000100
|
||||
#endif
|
||||
#ifndef S_IRGRP
|
||||
# define S_IRGRP 0000040
|
||||
#endif
|
||||
#ifndef S_IWGRP
|
||||
# define S_IWGRP 0000020
|
||||
#endif
|
||||
#ifndef S_IXGRP
|
||||
# define S_IXGRP 0000010
|
||||
#endif
|
||||
#ifndef S_IROTH
|
||||
# define S_IROTH 0000004
|
||||
#endif
|
||||
#ifndef S_IWOTH
|
||||
# define S_IWOTH 0000002
|
||||
#endif
|
||||
#ifndef S_IXOTH
|
||||
# define S_IXOTH 0000001
|
||||
#endif
|
||||
|
||||
#define MODE_WXUSR (S_IWUSR | S_IXUSR)
|
||||
#define MODE_R (S_IRUSR | S_IRGRP | S_IROTH)
|
||||
#define MODE_RW (S_IWUSR | S_IWGRP | S_IWOTH | MODE_R)
|
||||
#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
|
||||
#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)
|
||||
|
||||
/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION. */
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
# define SEEK_SET 0
|
||||
#endif
|
||||
#ifndef SEEK_CUR
|
||||
# define SEEK_CUR 1
|
||||
#endif
|
||||
#ifndef SEEK_END
|
||||
# define SEEK_END 2
|
||||
#endif
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
# define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
# define STDOUT_FILENO 1
|
||||
#endif
|
||||
#ifndef STDERR_FILENO
|
||||
# define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
/* Declare make device, major and minor. Since major is a function on
|
||||
SVR4, we have to resort to GOT_MAJOR instead of just testing if
|
||||
major is #define'd. */
|
||||
|
||||
#if MAJOR_IN_MKDEV
|
||||
# include <sys/mkdev.h>
|
||||
# define GOT_MAJOR
|
||||
#endif
|
||||
|
||||
#if MAJOR_IN_SYSMACROS
|
||||
# include <sys/sysmacros.h>
|
||||
# define GOT_MAJOR
|
||||
#endif
|
||||
|
||||
/* Some <sys/types.h> defines the macros. */
|
||||
#ifdef major
|
||||
# define GOT_MAJOR
|
||||
#endif
|
||||
|
||||
#ifndef GOT_MAJOR
|
||||
# if MSDOS
|
||||
# define major(Device) (Device)
|
||||
# define minor(Device) (Device)
|
||||
# define makedev(Major, Minor) (((Major) << 8) | (Minor))
|
||||
# define GOT_MAJOR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* For HP-UX before HP-UX 8, major/minor are not in <sys/sysmacros.h>. */
|
||||
#ifndef GOT_MAJOR
|
||||
# if defined(hpux) || defined(__hpux__) || defined(__hpux)
|
||||
# include <sys/mknod.h>
|
||||
# define GOT_MAJOR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef GOT_MAJOR
|
||||
# define major(Device) (((Device) >> 8) & 0xff)
|
||||
# define minor(Device) ((Device) & 0xff)
|
||||
# define makedev(Major, Minor) (((Major) << 8) | (Minor))
|
||||
#endif
|
||||
|
||||
#undef GOT_MAJOR
|
||||
|
||||
/* Declare wait status. */
|
||||
|
||||
#if HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
#ifndef WEXITSTATUS
|
||||
# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
|
||||
#endif
|
||||
#ifndef WIFSIGNALED
|
||||
# define WIFSIGNALED(s) (((s) & 0xffff) - 1 < (unsigned) 0xff)
|
||||
#endif
|
||||
#ifndef WTERMSIG
|
||||
# define WTERMSIG(s) ((s) & 0x7f)
|
||||
#endif
|
||||
|
||||
/* FIXME: It is wrong to use BLOCKSIZE for buffers when the logical block
|
||||
size is greater than 512 bytes; so ST_BLKSIZE code below, in preparation
|
||||
for some cleanup in this area, later. */
|
||||
|
||||
/* Extract or fake data from a `struct stat'. ST_BLKSIZE gives the
|
||||
optimal I/O blocksize for the file, in bytes. Some systems, like
|
||||
Sequents, return st_blksize of 0 on pipes. */
|
||||
|
||||
#define DEFAULT_ST_BLKSIZE 512
|
||||
|
||||
#if !HAVE_ST_BLKSIZE
|
||||
# define ST_BLKSIZE(Statbuf) DEFAULT_ST_BLKSIZE
|
||||
#else
|
||||
# define ST_BLKSIZE(Statbuf) \
|
||||
((Statbuf).st_blksize > 0 ? (Statbuf).st_blksize : DEFAULT_ST_BLKSIZE)
|
||||
#endif
|
||||
|
||||
/* Extract or fake data from a `struct stat'. ST_NBLOCKS gives the
|
||||
number of ST_NBLOCKSIZE-byte blocks in the file (including indirect blocks).
|
||||
HP-UX counts st_blocks in 1024-byte units,
|
||||
this loses when mixing HP-UX and BSD filesystems with NFS. AIX PS/2
|
||||
counts st_blocks in 4K units. */
|
||||
|
||||
#if !HAVE_ST_BLOCKS
|
||||
# if defined(_POSIX_SOURCE) || !defined(BSIZE)
|
||||
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_size / ST_NBLOCKSIZE + ((Statbuf).st_size % ST_NBLOCKSIZE != 0))
|
||||
# else
|
||||
off_t st_blocks ();
|
||||
# define ST_NBLOCKS(Statbuf) (st_blocks ((Statbuf).st_size))
|
||||
# endif
|
||||
#else
|
||||
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks)
|
||||
# if defined(hpux) || defined(__hpux__) || defined(__hpux)
|
||||
# define ST_NBLOCKSIZE 1024
|
||||
# else
|
||||
# if defined(_AIX) && defined(_I386)
|
||||
# define ST_NBLOCKSIZE (4 * 1024)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ST_NBLOCKSIZE
|
||||
#define ST_NBLOCKSIZE 512
|
||||
#endif
|
||||
|
||||
/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses
|
||||
<sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires
|
||||
<sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It
|
||||
seems that the rest use <sys/mtio.h>, which itself requires other files,
|
||||
depending on systems. Pyramid defines _IOW in <sgtty.h>, for example. */
|
||||
|
||||
#if HAVE_SYS_GENTAPE_H
|
||||
# include <sys/gentape.h>
|
||||
#else
|
||||
# if HAVE_SYS_TAPE_H
|
||||
# if HAVE_SYS_DEVICE_H
|
||||
# include <sys/device.h>
|
||||
# endif
|
||||
# if HAVE_SYS_BUF_H
|
||||
# include <sys/buf.h>
|
||||
# endif
|
||||
# if HAVE_SYS_TPRINTF_H
|
||||
# include <sys/tprintf.h>
|
||||
# endif
|
||||
# include <sys/tape.h>
|
||||
# else
|
||||
# if HAVE_SYS_MTIO_H
|
||||
# include <sys/ioctl.h>
|
||||
# if HAVE_SGTTY_H
|
||||
# include <sgtty.h>
|
||||
# endif
|
||||
# if HAVE_SYS_IO_TRIOCTL_H
|
||||
# include <sys/io/trioctl.h>
|
||||
# endif
|
||||
# include <sys/mtio.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Declare standard functions. */
|
||||
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
void *malloc ();
|
||||
char *getenv ();
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#if !defined _POSIX_VERSION && MSDOS
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#if WITH_DMALLOC
|
||||
# undef HAVE_DECL_VALLOC
|
||||
# define DMALLOC_FUNC_CHECK
|
||||
# include <dmalloc.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef MB_LEN_MAX
|
||||
# define MB_LEN_MAX 1
|
||||
#endif
|
||||
|
||||
#if HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
/* These macros work even on ones'-complement hosts (!).
|
||||
The extra casts work around common compiler bugs. */
|
||||
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
||||
#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) \
|
||||
? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
|
||||
: (t) 0)
|
||||
#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
|
||||
|
||||
/* Bound on length of the string representing an integer value of type t.
|
||||
Subtract one for the sign bit if t is signed;
|
||||
302 / 1000 is log10 (2) rounded up;
|
||||
add one for integer division truncation;
|
||||
add one more for a minus sign if t is signed. */
|
||||
#define INT_STRLEN_BOUND(t) \
|
||||
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
|
||||
+ 1 + TYPE_SIGNED (t))
|
||||
|
||||
#define UINTMAX_STRSIZE_BOUND (INT_STRLEN_BOUND (uintmax_t) + 1)
|
||||
|
||||
/* Prototypes for external functions. */
|
||||
|
||||
#if HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#if !HAVE_SETLOCALE
|
||||
# define setlocale(Category, Locale) /* empty */
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#ifndef time
|
||||
time_t time ();
|
||||
#endif
|
||||
|
||||
/* Library modules. */
|
||||
|
||||
#include <dirname.h>
|
||||
#include <error.h>
|
||||
#include <savedir.h>
|
||||
#include <unlocked-io.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include <gettext.h>
|
||||
#define _(msgid) gettext (msgid)
|
||||
#define N_(msgid) msgid
|
||||
|
||||
#if ! defined valloc && ! HAVE_DECL_VALLOC
|
||||
# define valloc(Size) malloc (Size)
|
||||
#endif
|
||||
|
||||
#if MSDOS
|
||||
# include <process.h>
|
||||
# define SET_BINARY_MODE(arc) setmode(arc, O_BINARY)
|
||||
# define ERRNO_IS_EACCES errno == EACCES
|
||||
# define mkdir(file, mode) (mkdir) (file)
|
||||
#else
|
||||
# include <pwd.h>
|
||||
# include <grp.h>
|
||||
# define SET_BINARY_MODE(arc)
|
||||
# define ERRNO_IS_EACCES 0
|
||||
#endif
|
||||
|
||||
#if XENIX
|
||||
# include <sys/inode.h>
|
||||
#endif
|
||||
@@ -288,6 +288,8 @@ struct tar_stat_info
|
||||
off_t archive_file_size; /* Size of file as stored in the archive.
|
||||
Equals stat.st_size for non-sparse files */
|
||||
|
||||
bool is_sparse; /* Is the file sparse */
|
||||
|
||||
size_t sparse_map_avail; /* Index to the first unused element in
|
||||
sparse_map array. Zero if the file is
|
||||
not sparse */
|
||||
|
||||
57
src/update.c
57
src/update.c
@@ -1,7 +1,7 @@
|
||||
/* Update a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003
|
||||
Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003,
|
||||
2004 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
|
||||
@@ -22,7 +22,7 @@
|
||||
of the archive. No attempt is made to record the reads from the args; if
|
||||
they're on raw tape or something like that, it'll probably lose... */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
#include "common.h"
|
||||
|
||||
@@ -33,7 +33,7 @@ extern union block *current_block;
|
||||
/* We've hit the end of the old stuff, and its time to start writing new
|
||||
stuff to the tape. This involves seeking back one record and
|
||||
re-writing the current record (which has been changed).
|
||||
FIXME: Either eliminate it or move it to common.h.
|
||||
FIXME: Either eliminate it or move it to common.h.
|
||||
*/
|
||||
bool time_to_start_writing;
|
||||
|
||||
@@ -42,22 +42,22 @@ bool time_to_start_writing;
|
||||
first part of the record. */
|
||||
char *output_start;
|
||||
|
||||
/* Catenate file PATH to the archive without creating a header for it.
|
||||
/* Catenate file FILE_NAME to the archive without creating a header for it.
|
||||
It had better be a tar file or the archive is screwed. */
|
||||
static void
|
||||
append_file (char *path)
|
||||
append_file (char *file_name)
|
||||
{
|
||||
int handle = open (path, O_RDONLY | O_BINARY);
|
||||
int handle = open (file_name, O_RDONLY | O_BINARY);
|
||||
struct stat stat_data;
|
||||
|
||||
if (handle < 0)
|
||||
{
|
||||
open_error (path);
|
||||
open_error (file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fstat (handle, &stat_data) != 0)
|
||||
stat_error (path);
|
||||
stat_error (file_name);
|
||||
else
|
||||
{
|
||||
off_t bytes_left = stat_data.st_size;
|
||||
@@ -66,7 +66,7 @@ append_file (char *path)
|
||||
{
|
||||
union block *start = find_next_block ();
|
||||
size_t buffer_size = available_space_after (start);
|
||||
ssize_t status;
|
||||
size_t status;
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
if (bytes_left < buffer_size)
|
||||
@@ -78,15 +78,15 @@ append_file (char *path)
|
||||
}
|
||||
|
||||
status = safe_read (handle, start->buffer, buffer_size);
|
||||
if (status < 0)
|
||||
read_fatal_details (path, stat_data.st_size - bytes_left,
|
||||
if (status == SAFE_READ_ERROR)
|
||||
read_fatal_details (file_name, stat_data.st_size - bytes_left,
|
||||
buffer_size);
|
||||
if (status == 0)
|
||||
FATAL_ERROR ((0, 0,
|
||||
ngettext ("%s: File shrank by %s byte",
|
||||
"%s: File shrank by %s bytes",
|
||||
bytes_left),
|
||||
quotearg_colon (path),
|
||||
quotearg_colon (file_name),
|
||||
STRINGIFY_BIGINT (bytes_left, buf)));
|
||||
|
||||
bytes_left -= status;
|
||||
@@ -96,7 +96,7 @@ append_file (char *path)
|
||||
}
|
||||
|
||||
if (close (handle) != 0)
|
||||
close_error (path);
|
||||
close_error (file_name);
|
||||
}
|
||||
|
||||
/* Implement the 'r' (add files to end of archive), and 'u' (add files
|
||||
@@ -106,12 +106,12 @@ void
|
||||
update_archive (void)
|
||||
{
|
||||
enum read_header previous_status = HEADER_STILL_UNREAD;
|
||||
int found_end = 0;
|
||||
bool found_end = false;
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
xheader_write_global ();
|
||||
|
||||
|
||||
while (!found_end)
|
||||
{
|
||||
enum read_header status = read_header (false);
|
||||
@@ -126,30 +126,33 @@ update_archive (void)
|
||||
{
|
||||
struct name *name;
|
||||
|
||||
decode_header (current_header, ¤t_stat_info,
|
||||
¤t_format, 0);
|
||||
archive_format = current_format;
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
&& (name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
struct stat s;
|
||||
enum archive_format unused;
|
||||
|
||||
decode_header (current_header, ¤t_stat_info, &unused, 0);
|
||||
chdir_do (name->change_dir);
|
||||
if (deref_stat (dereference_option,
|
||||
current_stat_info.file_name, &s) == 0
|
||||
&& s.st_mtime <= current_stat_info.stat.st_mtime)
|
||||
add_avoided_name (current_stat_info.file_name);
|
||||
}
|
||||
|
||||
skip_member ();
|
||||
break;
|
||||
}
|
||||
|
||||
case HEADER_ZERO_BLOCK:
|
||||
current_block = current_header;
|
||||
found_end = 1;
|
||||
found_end = true;
|
||||
break;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
found_end = 1;
|
||||
found_end = true;
|
||||
break;
|
||||
|
||||
case HEADER_FAILURE:
|
||||
@@ -175,6 +178,8 @@ update_archive (void)
|
||||
break;
|
||||
}
|
||||
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
xheader_destroy (&extended_header);
|
||||
previous_status = status;
|
||||
}
|
||||
|
||||
@@ -183,18 +188,18 @@ update_archive (void)
|
||||
output_start = current_block->buffer;
|
||||
|
||||
{
|
||||
char *path;
|
||||
char *file_name;
|
||||
|
||||
while ((path = name_from_list ()) != NULL)
|
||||
while ((file_name = name_from_list ()) != NULL)
|
||||
{
|
||||
if (excluded_name (path))
|
||||
if (excluded_name (file_name))
|
||||
continue;
|
||||
if (interactive_option && !confirm ("add", path))
|
||||
if (interactive_option && !confirm ("add", file_name))
|
||||
continue;
|
||||
if (subcommand_option == CAT_SUBCOMMAND)
|
||||
append_file (path);
|
||||
append_file (file_name);
|
||||
else
|
||||
dump_file (path, 1, (dev_t) 0);
|
||||
dump_file (file_name, 1, (dev_t) 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
293
src/utf8.c
293
src/utf8.c
@@ -16,283 +16,30 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
#include <localcharset.h>
|
||||
#include "common.h"
|
||||
#ifdef HAVE_ICONV_H
|
||||
# include <iconv.h>
|
||||
#endif
|
||||
|
||||
struct langtab
|
||||
{
|
||||
char *lang; /* Language code */
|
||||
char *terr; /* Territory code */
|
||||
char *charset; /* Corresponding charset */
|
||||
};
|
||||
#ifndef ICONV_CONST
|
||||
# define ICONV_CONST
|
||||
#endif
|
||||
|
||||
/* The list of language codes defined in ISO 639 with the corresponding
|
||||
default character sets.
|
||||
#ifndef HAVE_ICONV
|
||||
|
||||
NOTES:
|
||||
# undef iconv_open
|
||||
# define iconv_open(tocode, fromcode) ((iconv_t) -1)
|
||||
|
||||
1) The list must be ordered by:
|
||||
a) lang field in ascending order
|
||||
b) terr field in descending order.
|
||||
NULL fields are considered less than non-null ones.
|
||||
2) Many entries have NULL charset fields. Please help fill them!
|
||||
3) The "default" character set for a given language is a matter
|
||||
of preference. Possibly the table should contain a *list* of
|
||||
possible character sets.
|
||||
4) LC_ALL "modifier" field is not taken into account */
|
||||
# undef iconv
|
||||
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) ((size_t) 0)
|
||||
|
||||
static struct langtab langtab[] = {
|
||||
{ "C", NULL, "ASCII"},
|
||||
{ "POSIX", NULL, "ASCII" },
|
||||
{ "aa", NULL, NULL}, /* Afar */
|
||||
{ "ab", NULL, NULL}, /* Abkhazian */
|
||||
{ "ae", NULL, NULL}, /* Avestan */
|
||||
{ "af", NULL, "iso-8859-1"}, /* Afrikaans */
|
||||
{ "am", NULL, "UTF-8"}, /* Amharic */
|
||||
{ "ar", NULL, "iso-8859-6"}, /* Arabic */
|
||||
{ "as", NULL, NULL}, /* Assamese */
|
||||
{ "ay", NULL, "iso-8859-1"}, /* Aymara */
|
||||
{ "az", NULL, NULL}, /* Azerbaijani */
|
||||
{ "ba", NULL, NULL}, /* Bashkir */
|
||||
{ "be", NULL, "UTF-8"}, /* Byelorussian; Belarusian */
|
||||
{ "bg", NULL, "iso-8859-5"}, /* Bulgarian */
|
||||
{ "bh", NULL, NULL}, /* Bihari */
|
||||
{ "bi", NULL, NULL}, /* Bislama */
|
||||
{ "bn", NULL, NULL}, /* Bengali; Bangla */
|
||||
{ "bo", NULL, NULL}, /* Tibetan */
|
||||
{ "br", NULL, "iso-8859-1"}, /* Breton: 1,5,8,9 */
|
||||
{ "bs", NULL, NULL}, /* Bosnian */
|
||||
{ "ca", NULL, "iso-8859-1"}, /* Catalan: 1,5,8,9 */
|
||||
{ "ce", NULL, NULL}, /* Chechen */
|
||||
{ "ch", NULL, NULL}, /* Chamorro */
|
||||
{ "co", NULL, "iso-8859-1"}, /* Corsican */
|
||||
{ "cs", NULL, "iso-8859-2"}, /* Czech */
|
||||
{ "cu", NULL, NULL }, /* Church Slavic */
|
||||
{ "cv", NULL, NULL}, /* Chuvash */
|
||||
{ "cy", NULL, "iso-8859-1"}, /* Welsh */
|
||||
{ "da", NULL, "iso-8859-1"}, /* Danish: 4-9 */
|
||||
{ "de", NULL, "iso-8859-1"}, /* German */
|
||||
{ "dz", NULL, NULL }, /* Dzongkha; Bhutani */
|
||||
{ "el", NULL, "iso-8859-7"}, /* Greek */
|
||||
{ "en", NULL, "iso-8859-1"}, /* English */
|
||||
{ "eo", NULL, "iso-8859-3"}, /* Esperanto */
|
||||
{ "es", NULL, "iso-8859-1"}, /* Spanish */
|
||||
{ "et", NULL, "iso-8859-15"}, /* Estonian: 6,7,9 */
|
||||
{ "eu", NULL, "iso-8859-1"}, /* Basque: 5,8,9 */
|
||||
{ "fa", NULL, "UTF-8"}, /* Persian */
|
||||
{ "fi", NULL, "iso-8859-15"}, /* Finnish */
|
||||
{ "fj", NULL, NULL }, /* Fijian; Fiji */
|
||||
{ "fo", NULL, "iso-8859-1"}, /* Faroese: 6,9 */
|
||||
{ "fr", NULL, "iso-8859-1"}, /* French */
|
||||
{ "fy", NULL, "iso-8859-1"}, /* Frisian */
|
||||
{ "ga", NULL, "iso-8859-14"}, /* Irish */
|
||||
{ "gd", NULL, "iso-8859-14" }, /* Scots; Gaelic */
|
||||
{ "gl", NULL, NULL }, /* Gallegan; Galician */
|
||||
{ "gn", NULL, NULL}, /* Guarani */
|
||||
{ "gu", NULL, NULL}, /* Gujarati */
|
||||
{ "gv", NULL, "iso-8859-14"}, /* Manx */
|
||||
{ "ha", NULL, NULL }, /* Hausa (?) */
|
||||
{ "he", NULL, "iso-8859-8" }, /* Hebrew */
|
||||
{ "hi", NULL, NULL}, /* Hindi */
|
||||
{ "ho", NULL, NULL}, /* Hiri Motu */
|
||||
{ "hr", NULL, "iso-8859-2"}, /* Croatian: 10 */
|
||||
{ "hu", NULL, "iso-8859-2"}, /* Hungarian */
|
||||
{ "hy", NULL, NULL}, /* Armenian */
|
||||
{ "hz", NULL, NULL}, /* Herero */
|
||||
{ "id", NULL, "iso-8859-1"}, /* Indonesian (formerly in) */
|
||||
{ "ia", NULL, NULL}, /* Interlingua */
|
||||
{ "ie", NULL, NULL}, /* Interlingue */
|
||||
{ "ik", NULL, NULL}, /* Inupiak */
|
||||
{ "io", NULL, NULL}, /* Ido */
|
||||
{ "is", NULL, "iso-8859-1"}, /* Icelandic */
|
||||
{ "it", NULL, "iso-8859-1"}, /* Italian */
|
||||
{ "iu", NULL, NULL}, /* Inuktitut */
|
||||
{ "ja", NULL, "EUC-JP"}, /* Japanese */
|
||||
{ "jv", NULL, NULL}, /* Javanese */
|
||||
{ "ka", NULL, NULL}, /* Georgian */
|
||||
{ "ki", NULL, NULL}, /* Kikuyu */
|
||||
{ "kj", NULL, NULL}, /* Kuanyama */
|
||||
{ "kk", NULL, NULL}, /* Kazakh */
|
||||
{ "kl", NULL, "iso-8859-1"}, /* Kalaallisut; Greenlandic */
|
||||
{ "km", NULL, NULL}, /* Khmer; Cambodian */
|
||||
{ "kn", NULL, NULL}, /* Kannada */
|
||||
{ "ko", NULL, "EUC-KR"}, /* Korean */
|
||||
{ "ks", NULL, NULL}, /* Kashmiri */
|
||||
{ "ku", NULL, NULL}, /* Kurdish */
|
||||
{ "kv", NULL, NULL}, /* Komi */
|
||||
{ "kw", NULL, "iso-8859-14"}, /* Cornish: 1,5,8 */
|
||||
{ "ky", NULL, NULL}, /* Kirghiz */
|
||||
{ "la", NULL, "iso-8859-1"}, /* Latin */
|
||||
{ "lb", NULL, "iso-8859-1"}, /* Letzeburgesch */
|
||||
{ "ln", NULL, NULL}, /* Lingala */
|
||||
{ "lo", NULL, NULL}, /* Lao; Laotian */
|
||||
{ "lt", NULL, "iso-8859-4"}, /* Lithuanian */
|
||||
{ "lv", NULL, "iso-8859-4"}, /* Latvian; Lettish */
|
||||
{ "mg", NULL, NULL}, /* Malagasy */
|
||||
{ "mh", NULL, NULL}, /* Marshall */
|
||||
{ "mi", NULL, NULL}, /* Maori */
|
||||
{ "mk", NULL, NULL}, /* Macedonian */
|
||||
{ "ml", NULL, NULL}, /* Malayalam */
|
||||
{ "mn", NULL, NULL}, /* Mongolian */
|
||||
{ "mo", NULL, "iso-8859-2"}, /* Moldavian */
|
||||
{ "mr", NULL, NULL}, /* Marathi */
|
||||
{ "ms", NULL, NULL}, /* Malay */
|
||||
{ "mt", NULL, "iso-8859-3"}, /* Maltese */
|
||||
{ "my", NULL, NULL}, /* Burmese */
|
||||
{ "na", NULL, NULL}, /* Nauru */
|
||||
{ "nb", NULL, "iso-8859-1"}, /* Norwegian Bokm<6B>l; Bokm@aa{}l */
|
||||
{ "nd", NULL, NULL}, /* Ndebele, North */
|
||||
{ "ne", NULL, NULL}, /* Nepali */
|
||||
{ "ng", NULL, NULL}, /* Ndonga */
|
||||
{ "nl", NULL, "iso-8859-1"}, /* Dutch: 5,9 */
|
||||
{ "nn", NULL, "iso-8859-1"}, /* Norwegian Nynorsk */
|
||||
{ "no", NULL, "iso-8859-1"}, /* Norwegian */
|
||||
{ "nr", NULL, NULL}, /* Ndebele, South */
|
||||
{ "nv", NULL, NULL}, /* Navajo */
|
||||
{ "ny", NULL, NULL}, /* Chichewa; Nyanja */
|
||||
{ "oc", NULL, NULL}, /* Occitan; Proven<65>al; Proven@,{c}al */
|
||||
{ "om", NULL, NULL}, /* (Afan) Oromo */
|
||||
{ "or", NULL, NULL}, /* Oriya */
|
||||
{ "os", NULL, NULL}, /* Ossetian; Ossetic */
|
||||
{ "pa", NULL, NULL}, /* Panjabi; Punjabi */
|
||||
{ "pi", NULL, NULL}, /* Pali */
|
||||
{ "pl", NULL, "iso-8859-2"}, /* Polish */
|
||||
{ "ps", NULL, NULL}, /* Pashto, Pushto */
|
||||
{ "pt", NULL, "iso-8859-1"}, /* Portuguese */
|
||||
{ "qu", NULL, "iso-8859-1"}, /* Quechua */
|
||||
{ "rm", NULL, "iso-8859-1"}, /* Rhaeto-Romance */
|
||||
{ "rn", NULL, NULL }, /* Rundi; Kirundi */
|
||||
{ "ro", NULL, "iso-8859-2"}, /* Romanian */
|
||||
{ "ru", NULL, "koi8-r"}, /* Russian */
|
||||
{ "rw", NULL, NULL}, /* Kinyarwanda */
|
||||
{ "sa", NULL, NULL}, /* Sanskrit */
|
||||
{ "sc", NULL, "iso-8859-1"}, /* Sardinian */
|
||||
{ "sd", NULL, NULL}, /* Sindhi */
|
||||
{ "se", NULL, "iso-8859-10"}, /* Northern Sami */
|
||||
{ "sg", NULL, NULL}, /* Sango; Sangro */
|
||||
{ "si", NULL, NULL}, /* Sinhalese */
|
||||
{ "sk", NULL, "iso-8859-2"}, /* Slovak */
|
||||
{ "sl", NULL, "iso-8859-1"}, /* Slovenian */
|
||||
{ "sm", NULL, NULL}, /* Samoan */
|
||||
{ "sn", NULL, NULL}, /* Shona */
|
||||
{ "so", NULL, NULL}, /* Somali */
|
||||
{ "sq", NULL, "iso-8859-1"}, /* Albanian: 2,5,8,9,10 */
|
||||
{ "sr", NULL, "iso-8859-2"}, /* Serbian */
|
||||
{ "ss", NULL, NULL}, /* Swati; Siswati */
|
||||
{ "st", NULL, NULL}, /* Sesotho; Sotho, Southern */
|
||||
{ "su", NULL, NULL}, /* Sundanese */
|
||||
{ "sv", NULL, "iso-8859-1"}, /* Swedish */
|
||||
{ "sw", NULL, NULL}, /* Swahili */
|
||||
{ "ta", NULL, NULL}, /* Tamil */
|
||||
{ "te", NULL, NULL}, /* Telugu */
|
||||
{ "tg", NULL, NULL}, /* Tajik */
|
||||
{ "th", NULL, "iso-8859-11"}, /* Thai */
|
||||
{ "ti", NULL, NULL}, /* Tigrinya */
|
||||
{ "tk", NULL, NULL}, /* Turkmen */
|
||||
{ "tl", NULL, "iso-8859-1"}, /* Tagalog */
|
||||
{ "tn", NULL, NULL}, /* Tswana; Setswana */
|
||||
{ "to", NULL, NULL}, /* Tonga (?) */
|
||||
{ "tr", NULL, "iso-8859-9"}, /* Turkish */
|
||||
{ "ts", NULL, NULL}, /* Tsonga */
|
||||
{ "tt", NULL, NULL}, /* Tatar */
|
||||
{ "tw", NULL, NULL}, /* Twi */
|
||||
{ "ty", NULL, NULL}, /* Tahitian */
|
||||
{ "ug", NULL, NULL}, /* Uighur */
|
||||
{ "uk", NULL, "koi8-u"}, /* Ukrainian */
|
||||
{ "ur", NULL, NULL}, /* Urdu */
|
||||
{ "uz", NULL, NULL}, /* Uzbek */
|
||||
{ "vi", NULL, NULL}, /* Vietnamese */
|
||||
{ "vo", NULL, NULL}, /* Volap<61>k; Volap@"{u}k; Volapuk */
|
||||
{ "wa", NULL, "iso-8859-1"}, /* Walloon */
|
||||
{ "wo", NULL, NULL}, /* Wolof */
|
||||
{ "xh", NULL, NULL}, /* Xhosa */
|
||||
{ "yi", NULL, "iso-8859-8"}, /* Yiddish (formerly ji) */
|
||||
{ "yo", NULL, NULL}, /* Yoruba */
|
||||
{ "za", NULL, NULL}, /* Zhuang */
|
||||
{ "zh", "TW", "big5"}, /* Chinese */
|
||||
{ "zh", NULL, "gb2312"}, /* Chinese */
|
||||
{ "zu", NULL, NULL}, /* Zulu */
|
||||
{ NULL }
|
||||
};
|
||||
# undef iconv_close
|
||||
# define iconv_close(cd) 0
|
||||
|
||||
/* Given the language and (optionally) territory code, return the
|
||||
default character set for that language. See notes above. */
|
||||
|
||||
const char *
|
||||
charset_lookup (char *lang, char *terr)
|
||||
{
|
||||
static struct langtab *p;
|
||||
|
||||
if (!lang)
|
||||
return NULL;
|
||||
for (p = langtab; p->lang; p++)
|
||||
if (strcasecmp (p->lang, lang) == 0
|
||||
&& (terr == NULL
|
||||
|| p->terr == NULL
|
||||
|| !strcasecmp (p->terr, terr) == 0))
|
||||
return p->charset;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_input_charset ()
|
||||
{
|
||||
const char *charset = NULL;
|
||||
char *tmp;
|
||||
int rc;
|
||||
|
||||
/* Try to deduce the charset from LC_ALL or LANG variables */
|
||||
|
||||
tmp = getenv ("LC_ALL");
|
||||
if (!tmp)
|
||||
tmp = getenv ("LANG");
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
char *lang;
|
||||
char *terr;
|
||||
|
||||
lang = strtok (tmp, "_");
|
||||
terr = strtok (NULL, ".");
|
||||
charset = strtok (NULL, "@");
|
||||
|
||||
if (!charset)
|
||||
charset = charset_lookup (lang, terr);
|
||||
}
|
||||
|
||||
if (!charset)
|
||||
charset = "iso-8859-1";
|
||||
return charset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef HAVE_LIBICONV
|
||||
|
||||
iconv_t
|
||||
iconv_open (const char *tocode, const char *fromcode)
|
||||
{
|
||||
return (iconv_t)(-1);
|
||||
}
|
||||
|
||||
size_t
|
||||
iconv (iconv_t cd, ICONV_CONST char **inbuf, size_t *inbytesleft,
|
||||
char **outbuf, size_t *outbytesleft)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iconv_close (iconv_t cd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !HAVE_LIBICONV */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -305,22 +52,22 @@ utf8_init (bool to_utf)
|
||||
if (conv_desc[(int) to_utf] == (iconv_t) -1)
|
||||
{
|
||||
if (to_utf)
|
||||
conv_desc[(int) to_utf] = iconv_open ("UTF-8", get_input_charset ());
|
||||
conv_desc[(int) to_utf] = iconv_open ("UTF-8", locale_charset ());
|
||||
else
|
||||
conv_desc[(int) to_utf] = iconv_open (get_input_charset (), "UTF-8");
|
||||
conv_desc[(int) to_utf] = iconv_open (locale_charset (), "UTF-8");
|
||||
}
|
||||
return conv_desc[(int) to_utf];
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
utf8_convert(bool to_utf, char *input, char **output)
|
||||
utf8_convert (bool to_utf, char const *input, char **output)
|
||||
{
|
||||
const char *ib;
|
||||
char ICONV_CONST *ib;
|
||||
char *ob;
|
||||
size_t inlen;
|
||||
size_t outlen;
|
||||
size_t rc;
|
||||
iconv_t cd = utf8_init(to_utf);
|
||||
iconv_t cd = utf8_init (to_utf);
|
||||
|
||||
if (cd == 0)
|
||||
{
|
||||
@@ -333,7 +80,7 @@ utf8_convert(bool to_utf, char *input, char **output)
|
||||
inlen = strlen (input) + 1;
|
||||
outlen = inlen * MB_LEN_MAX + 1;
|
||||
ob = *output = xmalloc (outlen);
|
||||
ib = input;
|
||||
ib = (char ICONV_CONST *) input;
|
||||
rc = iconv (cd, &ib, &inlen, &ob, &outlen);
|
||||
*ob = 0;
|
||||
return rc != -1;
|
||||
|
||||
206
src/xheader.c
206
src/xheader.c
@@ -16,10 +16,12 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
#include <system.h>
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <hash.h>
|
||||
#include <quotearg.h>
|
||||
#include <stpcpy.h>
|
||||
#include <xstrtol.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -28,13 +30,16 @@
|
||||
#define obstack_chunk_free free
|
||||
#include <obstack.h>
|
||||
|
||||
bool xheader_protected_pattern_p (const char *pattern);
|
||||
bool xheader_protected_keyword_p (const char *keyword);
|
||||
#include <fnmatch.h>
|
||||
|
||||
static bool xheader_protected_pattern_p (char const *pattern);
|
||||
static bool xheader_protected_keyword_p (char const *keyword);
|
||||
static void xheader_set_single_keyword (char *) __attribute__ ((noreturn));
|
||||
|
||||
/* Used by xheader_finish() */
|
||||
static void code_string (char const *string, char const *keyword,
|
||||
struct xheader *xhdr);
|
||||
static void extended_header_init ();
|
||||
static void extended_header_init (void);
|
||||
|
||||
/* Number of global headers written so far. */
|
||||
static size_t global_header_count;
|
||||
@@ -78,7 +83,7 @@ static char *exthdr_name;
|
||||
/* Template for the name field of a 'g' type header */
|
||||
static char *globexthdr_name;
|
||||
|
||||
bool
|
||||
static bool
|
||||
xheader_keyword_deleted_p (const char *kw)
|
||||
{
|
||||
struct keyword_list *kp;
|
||||
@@ -89,7 +94,7 @@ xheader_keyword_deleted_p (const char *kw)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
xheader_keyword_override_p (const char *keyword)
|
||||
{
|
||||
struct keyword_list *kp;
|
||||
@@ -100,7 +105,7 @@ xheader_keyword_override_p (const char *keyword)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
xheader_list_append (struct keyword_list **root, char const *kw,
|
||||
char const *value)
|
||||
{
|
||||
@@ -111,7 +116,7 @@ xheader_list_append (struct keyword_list **root, char const *kw,
|
||||
*root = kp;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
xheader_list_destroy (struct keyword_list **root)
|
||||
{
|
||||
if (root)
|
||||
@@ -128,15 +133,14 @@ xheader_list_destroy (struct keyword_list **root)
|
||||
*root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
|
||||
static void
|
||||
xheader_set_single_keyword (char *kw)
|
||||
{
|
||||
USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet imlemented"), kw));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
xheader_set_keyword_equal (char *kw, char *eq)
|
||||
{
|
||||
bool global = true;
|
||||
@@ -155,7 +159,7 @@ xheader_set_keyword_equal (char *kw, char *eq)
|
||||
|
||||
for (p = eq + 1; *p && isspace (*p); p++)
|
||||
;
|
||||
|
||||
|
||||
if (strcmp (kw, "delete") == 0)
|
||||
{
|
||||
if (xheader_protected_pattern_p (p))
|
||||
@@ -191,15 +195,35 @@ xheader_set_option (char *string)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
to_decimal (uintmax_t value, char *where, size_t size)
|
||||
{
|
||||
size_t i = 0, j;
|
||||
|
||||
where[i++] = 0;
|
||||
do
|
||||
{
|
||||
where[i++] = '0' + value % 10;
|
||||
value /= 10;
|
||||
}
|
||||
while (i < size && value);
|
||||
for (j = 0, i--; j < i; j++, i--)
|
||||
{
|
||||
char c = where[j];
|
||||
where[j] = where[i];
|
||||
where[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
string Includes: Replaced By:
|
||||
%d The directory name of the file,
|
||||
equivalent to the result of the
|
||||
dirname utility on the translated
|
||||
pathname.
|
||||
file name.
|
||||
%f The filename of the file, equivalent
|
||||
to the result of the basename
|
||||
utility on the translated pathname.
|
||||
utility on the translated file name.
|
||||
%p The process ID of the pax process.
|
||||
%% A '%' character. */
|
||||
|
||||
@@ -210,11 +234,11 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n)
|
||||
size_t len = strlen (fmt);
|
||||
char *q;
|
||||
const char *p;
|
||||
char *dirname = NULL;
|
||||
char *basename = NULL;
|
||||
char *dir = NULL;
|
||||
char *base = NULL;
|
||||
char pidbuf[64];
|
||||
char nbuf[64];
|
||||
|
||||
|
||||
for (p = fmt; *p && (p = strchr (p, '%')); )
|
||||
{
|
||||
switch (p[1])
|
||||
@@ -226,38 +250,35 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n)
|
||||
case 'd':
|
||||
if (st)
|
||||
{
|
||||
dirname = safer_name_suffix (dir_name (st->orig_file_name),
|
||||
false);
|
||||
len += strlen (dirname) - 1;
|
||||
dir = safer_name_suffix (dir_name (st->orig_file_name), false);
|
||||
len += strlen (dir) - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'f':
|
||||
if (st)
|
||||
{
|
||||
basename = base_name (st->orig_file_name);
|
||||
len += strlen (basename) - 1;
|
||||
base = base_name (st->orig_file_name);
|
||||
len += strlen (base) - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'p':
|
||||
snprintf (pidbuf, sizeof pidbuf, "%lu",
|
||||
(unsigned long) getpid ());
|
||||
to_decimal (getpid (), pidbuf, sizeof pidbuf);
|
||||
len += strlen (pidbuf) - 1;
|
||||
break;
|
||||
|
||||
|
||||
case 'n':
|
||||
if (allow_n)
|
||||
{
|
||||
snprintf (nbuf, sizeof nbuf, "%lu",
|
||||
(unsigned long) global_header_count + 1);
|
||||
to_decimal (global_header_count + 1, pidbuf, sizeof pidbuf);
|
||||
len += strlen (nbuf) - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
|
||||
buf = xmalloc (len + 1);
|
||||
for (q = buf, p = fmt; *p; )
|
||||
{
|
||||
@@ -269,19 +290,19 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n)
|
||||
*q++ = *p++;
|
||||
p++;
|
||||
break;
|
||||
|
||||
|
||||
case 'd':
|
||||
if (dirname)
|
||||
q = stpcpy (q, dirname);
|
||||
if (dir)
|
||||
q = stpcpy (q, dir);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
|
||||
case 'f':
|
||||
if (basename)
|
||||
q = stpcpy (q, basename);
|
||||
if (base)
|
||||
q = stpcpy (q, base);
|
||||
p += 2;
|
||||
break;
|
||||
|
||||
|
||||
case 'p':
|
||||
q = stpcpy (q, pidbuf);
|
||||
p += 2;
|
||||
@@ -294,7 +315,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n)
|
||||
p += 2;
|
||||
}
|
||||
/* else fall through */
|
||||
|
||||
|
||||
default:
|
||||
*q++ = *p++;
|
||||
if (*p)
|
||||
@@ -323,7 +344,7 @@ xheader_xhdr_name (struct tar_stat_info *st)
|
||||
#define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n"
|
||||
|
||||
char *
|
||||
xheader_ghdr_name ()
|
||||
xheader_ghdr_name (void)
|
||||
{
|
||||
if (!globexthdr_name)
|
||||
{
|
||||
@@ -346,7 +367,7 @@ xheader_write (char type, char *name, struct xheader *xhdr)
|
||||
union block *header;
|
||||
size_t size;
|
||||
char *p;
|
||||
|
||||
|
||||
size = xhdr->size;
|
||||
header = start_private_header (name, size);
|
||||
header->header.typeflag = type;
|
||||
@@ -354,11 +375,11 @@ xheader_write (char type, char *name, struct xheader *xhdr)
|
||||
simple_finish_header (header);
|
||||
|
||||
p = xhdr->buffer;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
size_t len;
|
||||
|
||||
|
||||
header = find_next_block ();
|
||||
len = BLOCKSIZE;
|
||||
if (len > size)
|
||||
@@ -372,17 +393,17 @@ xheader_write (char type, char *name, struct xheader *xhdr)
|
||||
}
|
||||
while (size > 0);
|
||||
xheader_destroy (xhdr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xheader_write_global ()
|
||||
xheader_write_global (void)
|
||||
{
|
||||
char *name;
|
||||
struct keyword_list *kp;
|
||||
|
||||
if (!keyword_global_override_list)
|
||||
return;
|
||||
|
||||
|
||||
extended_header_init ();
|
||||
for (kp = keyword_global_override_list; kp; kp = kp->next)
|
||||
code_string (kp->value, kp->pattern, &extended_header);
|
||||
@@ -424,7 +445,7 @@ locate_handler (char const *keyword)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
xheader_protected_pattern_p (const char *pattern)
|
||||
{
|
||||
struct xhdr_tab const *p;
|
||||
@@ -435,7 +456,7 @@ xheader_protected_pattern_p (const char *pattern)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
xheader_protected_keyword_p (const char *keyword)
|
||||
{
|
||||
struct xhdr_tab const *p;
|
||||
@@ -514,7 +535,7 @@ decx (void *data, char const *keyword, char const *value)
|
||||
if (xheader_keyword_deleted_p (keyword)
|
||||
|| xheader_keyword_override_p (keyword))
|
||||
return;
|
||||
|
||||
|
||||
t = locate_handler (keyword);
|
||||
if (t)
|
||||
t->decoder (st, value);
|
||||
@@ -525,12 +546,12 @@ xheader_decode (struct tar_stat_info *st)
|
||||
{
|
||||
run_override_list (keyword_global_override_list, st);
|
||||
run_override_list (global_header_override_list, st);
|
||||
|
||||
|
||||
if (extended_header.size)
|
||||
{
|
||||
char *p = extended_header.buffer + BLOCKSIZE;
|
||||
char *endp = &extended_header.buffer[extended_header.size-1];
|
||||
|
||||
|
||||
while (p < endp)
|
||||
if (!decode_record (&p, decx, st))
|
||||
break;
|
||||
@@ -546,7 +567,7 @@ decg (void *data, char const *keyword, char const *value)
|
||||
}
|
||||
|
||||
void
|
||||
xheader_decode_global ()
|
||||
xheader_decode_global (void)
|
||||
{
|
||||
if (extended_header.size)
|
||||
{
|
||||
@@ -561,7 +582,7 @@ xheader_decode_global ()
|
||||
}
|
||||
|
||||
static void
|
||||
extended_header_init ()
|
||||
extended_header_init (void)
|
||||
{
|
||||
if (!extended_header.stk)
|
||||
{
|
||||
@@ -574,8 +595,7 @@ void
|
||||
xheader_store (char const *keyword, struct tar_stat_info const *st, void *data)
|
||||
{
|
||||
struct xhdr_tab const *t;
|
||||
char *value;
|
||||
|
||||
|
||||
if (extended_header.buffer)
|
||||
return;
|
||||
t = locate_handler (keyword);
|
||||
@@ -606,7 +626,7 @@ xheader_read (union block *p, size_t size)
|
||||
|
||||
if (len > BLOCKSIZE)
|
||||
len = BLOCKSIZE;
|
||||
|
||||
|
||||
memcpy (&extended_header.buffer[j], p->buffer, len);
|
||||
set_next_block_after (p);
|
||||
|
||||
@@ -764,19 +784,22 @@ code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
|
||||
char const *keyword __attribute__ ((unused)),
|
||||
struct xheader *xhdr __attribute__ ((unused)),
|
||||
void *data __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_decoder (struct tar_stat_info *st, char const *arg)
|
||||
dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)),
|
||||
char const *arg __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
atime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_time (st->stat.st_atime, st->atime_nsec, keyword, xhdr);
|
||||
}
|
||||
@@ -789,7 +812,7 @@ atime_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
gid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_num (st->stat.st_gid, keyword, xhdr);
|
||||
}
|
||||
@@ -804,7 +827,7 @@ gid_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
gname_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_string (st->gname, keyword, xhdr);
|
||||
}
|
||||
@@ -817,7 +840,7 @@ gname_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
linkpath_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_string (st->link_name, keyword, xhdr);
|
||||
}
|
||||
@@ -830,7 +853,7 @@ linkpath_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
ctime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_time (st->stat.st_ctime, st->ctime_nsec, keyword, xhdr);
|
||||
}
|
||||
@@ -843,7 +866,7 @@ ctime_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
mtime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_time (st->stat.st_mtime, st->mtime_nsec, keyword, xhdr);
|
||||
}
|
||||
@@ -856,7 +879,7 @@ mtime_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
path_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_string (st->file_name, keyword, xhdr);
|
||||
}
|
||||
@@ -871,7 +894,7 @@ path_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
size_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_num (st->stat.st_size, keyword, xhdr);
|
||||
}
|
||||
@@ -881,12 +904,12 @@ size_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
|
||||
st->stat.st_size = u;
|
||||
st->archive_file_size = st->stat.st_size = u;
|
||||
}
|
||||
|
||||
static void
|
||||
uid_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_num (st->stat.st_uid, keyword, xhdr);
|
||||
}
|
||||
@@ -901,7 +924,7 @@ uid_decoder (struct tar_stat_info *st, char const *arg)
|
||||
|
||||
static void
|
||||
uname_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_string (st->uname, keyword, xhdr);
|
||||
}
|
||||
@@ -924,12 +947,13 @@ sparse_size_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
uintmax_t u;
|
||||
if (xstrtoumax (arg, NULL, 10, &u, "") == LONGINT_OK)
|
||||
st->archive_file_size = u;
|
||||
st->stat.st_size = u;
|
||||
}
|
||||
|
||||
static void
|
||||
sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data)
|
||||
struct xheader *xhdr,
|
||||
void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_num (st->sparse_map_avail, keyword, xhdr);
|
||||
}
|
||||
@@ -978,7 +1002,7 @@ sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
if (st->sparse_map_avail == st->sparse_map_size)
|
||||
{
|
||||
size_t newsize = st->sparse_map_size *= 2;
|
||||
st->sparse_map_size *= 2;
|
||||
st->sparse_map = xrealloc (st->sparse_map,
|
||||
st->sparse_map_size
|
||||
* sizeof st->sparse_map[0]);
|
||||
@@ -988,18 +1012,18 @@ sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg)
|
||||
}
|
||||
|
||||
struct xhdr_tab const xhdr_tab[] = {
|
||||
{ "atime", atime_coder, atime_decoder },
|
||||
{ "comment", dummy_coder, dummy_decoder },
|
||||
{ "charset", dummy_coder, dummy_decoder },
|
||||
{ "ctime", ctime_coder, ctime_decoder },
|
||||
{ "gid", gid_coder, gid_decoder },
|
||||
{ "gname", gname_coder, gname_decoder },
|
||||
{ "linkpath", linkpath_coder, linkpath_decoder},
|
||||
{ "mtime", mtime_coder, mtime_decoder },
|
||||
{ "path", path_coder, path_decoder },
|
||||
{ "size", size_coder, size_decoder },
|
||||
{ "uid", uid_coder, uid_decoder },
|
||||
{ "uname", uname_coder, uname_decoder },
|
||||
{ "atime", atime_coder, atime_decoder, false },
|
||||
{ "comment", dummy_coder, dummy_decoder, false },
|
||||
{ "charset", dummy_coder, dummy_decoder, false },
|
||||
{ "ctime", ctime_coder, ctime_decoder, false },
|
||||
{ "gid", gid_coder, gid_decoder, false },
|
||||
{ "gname", gname_coder, gname_decoder, false },
|
||||
{ "linkpath", linkpath_coder, linkpath_decoder, false },
|
||||
{ "mtime", mtime_coder, mtime_decoder, false },
|
||||
{ "path", path_coder, path_decoder, false },
|
||||
{ "size", size_coder, size_decoder, false },
|
||||
{ "uid", uid_coder, uid_decoder, false },
|
||||
{ "uname", uname_coder, uname_decoder, false },
|
||||
|
||||
/* Sparse file handling */
|
||||
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
|
||||
@@ -1015,12 +1039,12 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
/* The next directory entry actually contains the names of files
|
||||
that were in the directory at the time the dump was made.
|
||||
Supersedes GNUTYPE_DUMPDIR header type. */
|
||||
{ "GNU.dump.name", dump_name_coder, dump_name_decoder },
|
||||
{ "GNU.dump.status", dump_status_coder, dump_status_decoder },
|
||||
{ "GNU.dump.name", dump_name_coder, dump_name_decoder, false },
|
||||
{ "GNU.dump.status", dump_status_coder, dump_status_decoder, false },
|
||||
|
||||
/* Keeps the tape/volume header. May be present only in the global headers.
|
||||
Equivalent to GNUTYPE_VOLHDR. */
|
||||
{ "GNU.volume.header", volume_header_coder, volume_header_decoder },
|
||||
{ "GNU.volume.header", volume_header_coder, volume_header_decoder, false },
|
||||
|
||||
/* These may be present in a first global header of the archive.
|
||||
They provide the same functionality as GNUTYPE_MULTIVOL header.
|
||||
@@ -1028,9 +1052,9 @@ struct xhdr_tab const xhdr_tab[] = {
|
||||
otherwise kept in the size field of a multivolume header. The
|
||||
GNU.volume.offset keeps the offset of the start of this volume,
|
||||
otherwise kept in oldgnu_header.offset. */
|
||||
{ "GNU.volume.size", volume_size_coder, volume_size_decoder },
|
||||
{ "GNU.volume.offset", volume_offset_coder, volume_offset_decoder },
|
||||
{ "GNU.volume.size", volume_size_coder, volume_size_decoder, false },
|
||||
{ "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, false },
|
||||
#endif
|
||||
|
||||
{ NULL, NULL, NULL }
|
||||
{ NULL, NULL, NULL, false }
|
||||
};
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
preset
|
||||
.deps
|
||||
genfile
|
||||
tmp-*
|
||||
directory
|
||||
archive
|
||||
atconfig
|
||||
atlocal
|
||||
testsuite
|
||||
genfile.c
|
||||
testsuite.dir
|
||||
testsuite.log
|
||||
package.m4
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Makefile for GNU tar regression tests.
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003 Free Software
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# François Pinard <pinard@iro.umontreal.ca>, 1988.
|
||||
# Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004.
|
||||
|
||||
## 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,26 +21,100 @@
|
||||
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
check_PROGRAMS = genfile mksparse
|
||||
BUILT_SOURCES = preset
|
||||
EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 star/README star/quicktest.sh
|
||||
DISTCLEANFILES = atconfig $(check_SCRIPTS)
|
||||
MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
|
||||
|
||||
TESTS = version.sh \
|
||||
append.sh delete01.sh delete02.sh delete03.sh delete04.sh \
|
||||
extrac01.sh extrac02.sh extrac03.sh extrac04.sh \
|
||||
gzip.sh incremen.sh ignfail.sh listed01.sh \
|
||||
multiv01.sh old.sh options.sh volume.sh \
|
||||
recurse.sh
|
||||
## ------------ ##
|
||||
## package.m4. ##
|
||||
## ------------ ##
|
||||
|
||||
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
{ \
|
||||
echo '# Signature of the current package.'; \
|
||||
echo 'm4_define([AT_PACKAGE_NAME], [@PACKAGE_NAME@])'; \
|
||||
echo 'm4_define([AT_PACKAGE_TARNAME], [@PACKAGE_TARNAME@])'; \
|
||||
echo 'm4_define([AT_PACKAGE_VERSION], [@PACKAGE_VERSION@])'; \
|
||||
echo 'm4_define([AT_PACKAGE_STRING], [@PACKAGE_STRING@])'; \
|
||||
echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
|
||||
} >$(srcdir)/package.m4
|
||||
|
||||
#
|
||||
|
||||
## ------------ ##
|
||||
## Test suite. ##
|
||||
## ------------ ##
|
||||
|
||||
TESTSUITE_AT = \
|
||||
testsuite.at\
|
||||
delete01.at\
|
||||
delete02.at\
|
||||
delete03.at\
|
||||
delete04.at\
|
||||
delete05.at\
|
||||
extrac01.at\
|
||||
extrac02.at\
|
||||
extrac03.at\
|
||||
extrac04.at\
|
||||
extrac05.at\
|
||||
gzip.at\
|
||||
incremental.at\
|
||||
ignfail.at\
|
||||
link01.at\
|
||||
listed01.at\
|
||||
listed02.at\
|
||||
longv7.at\
|
||||
multiv01.at\
|
||||
multiv02.at\
|
||||
multiv03.at\
|
||||
old.at\
|
||||
options.at\
|
||||
recurse.at\
|
||||
same-order01.at\
|
||||
same-order02.at\
|
||||
sparse01.at\
|
||||
volume.at\
|
||||
version.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
star/multi-fail.at\
|
||||
star/ustar-big-2g.at\
|
||||
star/ustar-big-8g.at\
|
||||
star/pax-big-10g.at
|
||||
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
|
||||
AUTOTEST = $(AUTOM4TE) --language=autotest
|
||||
$(TESTSUITE): package.m4 $(TESTSUITE_AT)
|
||||
$(AUTOTEST) -I $(srcdir) testsuite.at -o $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
atconfig: $(top_builddir)/config.status
|
||||
cd $(top_builddir) && ./config.status tests/$@
|
||||
|
||||
clean-local:
|
||||
$(SHELL) $(TESTSUITE) --clean
|
||||
|
||||
check-local: atconfig atlocal $(TESTSUITE)
|
||||
$(SHELL) $(TESTSUITE)
|
||||
|
||||
#check_SCRIPTS = tar
|
||||
|
||||
# Run the test suite on the *installed* tree.
|
||||
installcheck-local:
|
||||
$(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin
|
||||
|
||||
|
||||
## ------------ ##
|
||||
## genfile ##
|
||||
## ------------ ##
|
||||
|
||||
check_PROGRAMS = genfile
|
||||
|
||||
genfile_SOURCES = genfile.c
|
||||
mksparse_SOURCES = mksparse.c
|
||||
EXTRA_DIST = after before preset.in $(TESTS)
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I$(top_srcdir)/lib -I../lib -I$(top_srcdir)/src
|
||||
|
||||
LDADD = ../lib/libtar.a $(LIBINTL)
|
||||
|
||||
mostlyclean:
|
||||
rm -rf tmp-*
|
||||
|
||||
$(TESTS): genfile mksparse
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Do common operations after a particular test.
|
||||
|
||||
cd ..
|
||||
exec 1> /dev/null
|
||||
exec 2> /dev/null
|
||||
echo $echo_n "$out$echo_c" | cmp -s - tmp-$$/stdout || exit 1
|
||||
echo $echo_n "$err$echo_c" | cmp -s - tmp-$$/stderr || exit 1
|
||||
rm -rf tmp-$$
|
||||
48
tests/delete03.sh → tests/append.at
Executable file → Normal file
48
tests/delete03.sh → tests/append.at
Executable file → Normal file
@@ -1,46 +1,34 @@
|
||||
#! /bin/sh
|
||||
# Deleting members with long file names.
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
# Copyright (C) 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
prereq gnu oldgnu posix
|
||||
AT_SETUP([append])
|
||||
AT_KEYWORDS([append])
|
||||
|
||||
set -e
|
||||
prefix=This_is_a_very_long_file_name_prefix_that_is_designed_to_cause_problems_with_file_names_that_run_into_a_limit_of_the_posix_tar_formatXX
|
||||
rm -f $prefix*
|
||||
for i in 1 2 3 4 5 6 7 8 9
|
||||
do touch $prefix$i
|
||||
done
|
||||
tar -cf archive ./$prefix*
|
||||
tar --delete -f archive ./${prefix}5
|
||||
tar -tf archive
|
||||
AT_TAR_CHECK([touch file1
|
||||
touch file2
|
||||
tar cf archive file1
|
||||
tar rf archive file2
|
||||
tar tf archive],
|
||||
[0],
|
||||
[file1
|
||||
file2
|
||||
])
|
||||
|
||||
out="\
|
||||
./${prefix}1
|
||||
./${prefix}2
|
||||
./${prefix}3
|
||||
./${prefix}4
|
||||
./${prefix}6
|
||||
./${prefix}7
|
||||
./${prefix}8
|
||||
./${prefix}9
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
AT_CLEANUP
|
||||
@@ -1,19 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Append was just not working.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
touch file1
|
||||
touch file2
|
||||
tar cf archive file1
|
||||
tar rf archive file2
|
||||
tar tf archive
|
||||
|
||||
out="\
|
||||
file1
|
||||
file2
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
6
tests/atlocal.in
Normal file
6
tests/atlocal.in
Normal file
@@ -0,0 +1,6 @@
|
||||
# @configure_input@ -*- shell-script -*-
|
||||
# Configurable variable values for tar test suite.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
PATH=@abs_builddir@:@abs_top_builddir@/src:$top_srcdir:$srcdir:$PATH
|
||||
|
||||
38
tests/before
38
tests/before
@@ -1,38 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Do common operations before a particular test.
|
||||
|
||||
mkdir tmp-$$
|
||||
cd tmp-$$
|
||||
|
||||
case $srcdir in
|
||||
/*|~*) ;;
|
||||
*) srcdir=../$srcdir ;;
|
||||
esac
|
||||
|
||||
out=
|
||||
err=
|
||||
|
||||
echo $0 > checking
|
||||
exec 1> stdout
|
||||
exec 2> stderr
|
||||
|
||||
PATH=..:../../src:$PATH
|
||||
|
||||
prereq() {
|
||||
if test $# -ne 0; then
|
||||
case $TAR_OPTIONS in
|
||||
--format=*) FMTOPT=$TAR_OPTIONS;;
|
||||
*) FMTOPT=`tar --show-defaults`;;
|
||||
esac
|
||||
|
||||
FORMAT=
|
||||
for option
|
||||
do
|
||||
case $FMTOPT in
|
||||
--format=$option*) FORMAT=$option
|
||||
break;;
|
||||
esac
|
||||
done
|
||||
test -z "$FORMAT" && exit 77
|
||||
fi
|
||||
}
|
||||
36
tests/delete01.at
Normal file
36
tests/delete01.at
Normal file
@@ -0,0 +1,36 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Deleting a member after a big one was destroying the archive.
|
||||
|
||||
AT_SETUP([deleting a member after a big one])
|
||||
AT_KEYWORDS([delete01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile -l 50000 > file1
|
||||
genfile -l 1024 > file2
|
||||
tar cf archive file1 file2
|
||||
tar f archive --delete file2
|
||||
tar tf archive],
|
||||
[0],
|
||||
[file1
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,18 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Deleting a member after a big one was destroying the archive.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
genfile -l 50000 > file1
|
||||
genfile -l 1024 > file2
|
||||
tar cf archive file1 file2
|
||||
tar f archive --delete file2
|
||||
tar tf archive
|
||||
|
||||
out="\
|
||||
file1
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
44
tests/delete02.at
Normal file
44
tests/delete02.at
Normal file
@@ -0,0 +1,44 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Deleting a member with the archive from stdin was not working correctly.
|
||||
|
||||
AT_SETUP([deleting a member from stdin archive])
|
||||
AT_KEYWORDS([delete02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile -l 3073 -p zeros > 1
|
||||
cp 1 2
|
||||
cp 2 3
|
||||
tar cf archive 1 2 3
|
||||
tar tf archive
|
||||
cat archive | tar f - --delete 2 > archive2
|
||||
echo separator
|
||||
tar tf archive2],
|
||||
[0],
|
||||
[1
|
||||
2
|
||||
3
|
||||
separator
|
||||
1
|
||||
3
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,26 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Deleting a member with the archive from stdin was not working correctly.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
genfile -l 3073 -p zeros > 1
|
||||
cp 1 2
|
||||
cp 2 3
|
||||
tar cf archive 1 2 3
|
||||
tar tf archive
|
||||
cat archive | tar f - --delete 2 > archive2
|
||||
echo -----
|
||||
tar tf archive
|
||||
|
||||
out="\
|
||||
1
|
||||
2
|
||||
3
|
||||
-----
|
||||
1
|
||||
3
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
48
tests/delete03.at
Normal file
48
tests/delete03.at
Normal file
@@ -0,0 +1,48 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
AT_SETUP([deleting members with long names])
|
||||
AT_KEYWORDS([delete03])
|
||||
|
||||
m4_define([PREFIX],[This_is_a_very_long_file_name_prefix_that_is_designed_to_cause_problems_with_file_names_that_run_into_a_limit_of_the_posix_tar_formatXX])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
prefix=PREFIX
|
||||
rm -f $prefix*
|
||||
for i in 1 2 3 4 5 6 7 8 9
|
||||
do touch $prefix$i
|
||||
done
|
||||
tar -cf archive ./$prefix* &&
|
||||
tar --delete -f archive ./${prefix}5 &&
|
||||
tar -tf archive
|
||||
],
|
||||
[0],
|
||||
[./PREFIX[]1
|
||||
./PREFIX[]2
|
||||
./PREFIX[]3
|
||||
./PREFIX[]4
|
||||
./PREFIX[]6
|
||||
./PREFIX[]7
|
||||
./PREFIX[]8
|
||||
./PREFIX[]9
|
||||
],[],[],[],[gnu, oldgnu, posix])
|
||||
|
||||
AT_CLEANUP
|
||||
53
tests/delete04.at
Normal file
53
tests/delete04.at
Normal file
@@ -0,0 +1,53 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Deleting a large last member was destroying earlier members.
|
||||
|
||||
AT_SETUP([deleting a large last member])
|
||||
AT_KEYWORDS([delete04])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile -l 3 >file1
|
||||
genfile -l 5 >file2
|
||||
genfile -l 3 >file3
|
||||
genfile -l 6 >file4
|
||||
genfile -l 24 >file5
|
||||
genfile -l 13 >file6
|
||||
genfile -l 1385 >file7
|
||||
genfile -l 30 >file8
|
||||
genfile -l 10 >file9
|
||||
genfile -l 256000 >file10
|
||||
tar cf archive file1 file2 file3 file4 file5 file6 file7 file8 file9 file10
|
||||
tar f archive --delete file10
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
file2
|
||||
file3
|
||||
file4
|
||||
file5
|
||||
file6
|
||||
file7
|
||||
file8
|
||||
file9
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,34 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Deleting a large last member was destroying earlier members.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
genfile -l 3 >file1
|
||||
genfile -l 5 >file2
|
||||
genfile -l 3 >file3
|
||||
genfile -l 6 >file4
|
||||
genfile -l 24 >file5
|
||||
genfile -l 13 >file6
|
||||
genfile -l 1385 >file7
|
||||
genfile -l 30 >file8
|
||||
genfile -l 10 >file9
|
||||
genfile -l 256000 >file10
|
||||
tar cf archive file1 file2 file3 file4 file5 file6 file7 file8 file9 file10
|
||||
tar f archive --delete file10
|
||||
tar tf archive
|
||||
|
||||
out="\
|
||||
file1
|
||||
file2
|
||||
file3
|
||||
file4
|
||||
file5
|
||||
file6
|
||||
file7
|
||||
file8
|
||||
file9
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
48
tests/delete05.at
Normal file
48
tests/delete05.at
Normal file
@@ -0,0 +1,48 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# When attempted to delete a non-existing member, tar used to destroy
|
||||
# last blocking_factor blocks.
|
||||
# References:
|
||||
# <Pine.LNX.4.10.10412160956460.30933-100000@electra.znyx.com>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-12/msg00016.html
|
||||
|
||||
AT_SETUP([deleting non-existing member])
|
||||
AT_KEYWORDS([delete05])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile -l 1024 > en
|
||||
genfile -l 1024 > to
|
||||
|
||||
tar cf archive en to
|
||||
# Make sure we don't use bogus blocking factor.
|
||||
# GNU tar up to and including 1.14.91 produced an empty archive this way:
|
||||
tar --file archive --blocking-factor=20 --delete tre
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[en
|
||||
to
|
||||
],
|
||||
[tar: tre: Not found in archive
|
||||
tar: Error exit delayed from previous errors
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
33
tests/extrac01.at
Normal file
33
tests/extrac01.at
Normal file
@@ -0,0 +1,33 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# There was a diagnostic when directory already exists.
|
||||
|
||||
AT_SETUP([extract01])
|
||||
AT_KEYWORDS([extract01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
touch directory/file
|
||||
tar cf archive directory || exit 1
|
||||
tar xf archive || exit 1
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,13 +0,0 @@
|
||||
#! /bin/sh
|
||||
# There was a diagnostic when directory already exists.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
mkdir directory
|
||||
touch directory/file
|
||||
tar cf archive directory || exit 1
|
||||
tar xf archive || exit 1
|
||||
|
||||
. $srcdir/after
|
||||
37
tests/extrac02.at
Normal file
37
tests/extrac02.at
Normal file
@@ -0,0 +1,37 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Could not extract symlinks over an existing file.
|
||||
|
||||
AT_SETUP([extracting symlinks over an existing file])
|
||||
AT_KEYWORDS([extract02])
|
||||
|
||||
# FIXME: Skip if symlinks are not supported on the system
|
||||
|
||||
AT_TAR_CHECK([
|
||||
touch file
|
||||
ln -s file link 2> /dev/null || ln file link
|
||||
tar cf archive link
|
||||
rm link
|
||||
touch link
|
||||
tar xf archive
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,15 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Could not extract symlinks over an existing file.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
touch file
|
||||
ln -s file link 2> /dev/null || ln file link
|
||||
tar cf archive link
|
||||
rm link
|
||||
touch link
|
||||
tar xf archive
|
||||
|
||||
. $srcdir/after
|
||||
37
tests/extrac03.at
Normal file
37
tests/extrac03.at
Normal file
@@ -0,0 +1,37 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Paths going up and down were inducing extraction loops.
|
||||
|
||||
AT_SETUP([extraction loops])
|
||||
AT_KEYWORDS([extract03])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
tar -cPvf archive directory/../directory
|
||||
echo separator
|
||||
tar -xPvf archive],
|
||||
[0],
|
||||
[directory/../directory/
|
||||
separator
|
||||
directory/../directory/
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,19 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Paths going up and down were inducing extraction loops.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
mkdir directory
|
||||
tar cfv archive directory/../directory
|
||||
echo -----
|
||||
tar xfv archive
|
||||
|
||||
out="\
|
||||
directory/../directory/
|
||||
-----
|
||||
directory/../directory/
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
46
tests/extrac04.at
Normal file
46
tests/extrac04.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Check for fnmatch problems in glibc 2.1.95.
|
||||
|
||||
AT_SETUP([extract + fnmatch])
|
||||
AT_KEYWORDS([extract04])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
touch file1
|
||||
mkdir directory
|
||||
mkdir directory/subdirectory
|
||||
touch directory/file1
|
||||
touch directory/file2
|
||||
touch directory/subdirectory/file1
|
||||
touch directory/subdirectory/file2
|
||||
tar -cf archive ./file1 directory
|
||||
tar -tf archive \
|
||||
--exclude='./*1' \
|
||||
--exclude='d*/*1' \
|
||||
--exclude='d*/s*/*2' | sort
|
||||
],
|
||||
[0],
|
||||
[directory/
|
||||
directory/file2
|
||||
directory/subdirectory/
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,27 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Check for fnmatch problems in glibc 2.1.95.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
touch file1
|
||||
mkdir directory
|
||||
mkdir directory/subdirectory
|
||||
touch directory/file1
|
||||
touch directory/file2
|
||||
touch directory/subdirectory/file1
|
||||
touch directory/subdirectory/file2
|
||||
tar -cf archive ./file1 directory
|
||||
tar -tf archive \
|
||||
--exclude='./*1' \
|
||||
--exclude='d*/*1' \
|
||||
--exclude='d*/s*/*2' | sort
|
||||
|
||||
out="\
|
||||
directory/
|
||||
directory/file2
|
||||
directory/subdirectory/
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
61
tests/extrac05.at
Normal file
61
tests/extrac05.at
Normal file
@@ -0,0 +1,61 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Problem: when extracting selected members from a PAX archive,
|
||||
# tar 1.14 incorrectly deemed all members to be sparse and
|
||||
# therefore was not able to properly skip them.
|
||||
#
|
||||
# Reported by: Luca Fibbi <fibbi@lamma.rete.toscana.it>
|
||||
#
|
||||
# References: <3.0.6.32.20040809113727.00a30e50@localhost>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-08/msg00008.html
|
||||
|
||||
AT_SETUP([extracting selected members from pax])
|
||||
AT_KEYWORDS([extract05])
|
||||
|
||||
AT_DATA([list],
|
||||
[jeden
|
||||
cztery
|
||||
])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --length 118 > jeden
|
||||
genfile --length 223 > dwa
|
||||
genfile --length 517 > trzy
|
||||
genfile --sparse --file sparsefile 0 ABCD 1M EFGH 2000K IJKL
|
||||
genfile --length 110 > cztery
|
||||
|
||||
tar cf archive jeden dwa trzy cztery || exit 1
|
||||
|
||||
mkdir dir
|
||||
cd dir
|
||||
|
||||
tar xvfT ../archive ../../list || exit 1
|
||||
|
||||
cd ..
|
||||
],
|
||||
[0],
|
||||
[jeden
|
||||
cztery
|
||||
],
|
||||
[],[],[],
|
||||
[posix])
|
||||
|
||||
AT_CLEANUP
|
||||
170
tests/genfile.c
170
tests/genfile.c
@@ -1,170 +0,0 @@
|
||||
/* Generate a file containing some preset patterns.
|
||||
|
||||
Copyright (C) 1995, 1996, 1997, 2001, 2003 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
François Pinard <pinard@iro.umontreal.ca>, 1995.
|
||||
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <argmatch.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#ifndef EXIT_SUCCESS
|
||||
# define EXIT_SUCCESS 0
|
||||
#endif
|
||||
#ifndef EXIT_FAILURE
|
||||
# define EXIT_FAILURE 1
|
||||
#endif
|
||||
|
||||
enum pattern
|
||||
{
|
||||
DEFAULT_PATTERN,
|
||||
ZEROS_PATTERN
|
||||
};
|
||||
|
||||
/* The name this program was run with. */
|
||||
const char *program_name;
|
||||
|
||||
/* If nonzero, display usage information and exit. */
|
||||
static int show_help = 0;
|
||||
|
||||
/* If nonzero, print the version on standard output and exit. */
|
||||
static int show_version = 0;
|
||||
|
||||
/* Length of file to generate. */
|
||||
static int file_length = 0;
|
||||
|
||||
/* Pattern to generate. */
|
||||
static enum pattern pattern = DEFAULT_PATTERN;
|
||||
|
||||
/* Explain how to use the program, then get out. */
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("Generate data files for GNU tar test suite.\n"));
|
||||
printf (_("\
|
||||
\n\
|
||||
Usage: %s [OPTION]...\n"), program_name);
|
||||
fputs (_("\
|
||||
If a long option shows an argument as mandatory, then it is mandatory\n\
|
||||
for the equivalent short option also.\n\
|
||||
\n\
|
||||
-l, --file-length=LENGTH LENGTH of generated file\n\
|
||||
-p, --pattern=PATTERN PATTERN is `default' or `zeros'\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n"),
|
||||
stdout);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Main program. Decode ARGC arguments passed through the ARGV array
|
||||
of strings, then launch execution. */
|
||||
|
||||
/* Long options equivalences. */
|
||||
static const struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, &show_help, 1},
|
||||
{"length", required_argument, NULL, 'l'},
|
||||
{"pattern", required_argument, NULL, 'p'},
|
||||
{"version", no_argument, &show_version, 1},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static char const * const pattern_args[] = { "default", "zeros", 0 };
|
||||
static enum pattern const pattern_types[] = {DEFAULT_PATTERN, ZEROS_PATTERN};
|
||||
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
int option_char; /* option character */
|
||||
int counter; /* general purpose counter */
|
||||
|
||||
/* Decode command options. */
|
||||
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
while (option_char = getopt_long (argc, argv, "l:p:", long_options, NULL),
|
||||
option_char != EOF)
|
||||
switch (option_char)
|
||||
{
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
case '\0':
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
file_length = atoi (optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pattern = XARGMATCH ("--pattern", optarg,
|
||||
pattern_args, pattern_types);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process trivial options. */
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
printf ("genfile (GNU %s) %s\n", PACKAGE, VERSION);
|
||||
printf (_("Copyright (C) %d Free Software Foundation, Inc.\n"), 2003);
|
||||
puts (_("\
|
||||
This program comes with NO WARRANTY, to the extent permitted by law.\n\
|
||||
You may redistribute it under the terms of the GNU General Public License;\n\
|
||||
see the file named COPYING for details."));
|
||||
|
||||
/* Note to translator: Please translate "F. Pinard" to "François
|
||||
Pinard" if "ç" (c-with-cedilla) is available in the
|
||||
translation's character set and encoding. */
|
||||
puts (_("Written by F. Pinard."));
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (show_help)
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
if (optind < argc)
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
/* Generate file. */
|
||||
|
||||
switch (pattern)
|
||||
{
|
||||
case DEFAULT_PATTERN:
|
||||
for (counter = 0; counter < file_length; counter++)
|
||||
putchar (counter & 255);
|
||||
break;
|
||||
|
||||
case ZEROS_PATTERN:
|
||||
for (counter = 0; counter < file_length; counter++)
|
||||
putchar (0);
|
||||
break;
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
41
tests/gzip.at
Normal file
41
tests/gzip.at
Normal file
@@ -0,0 +1,41 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# tar should detect that its gzip child failed.
|
||||
|
||||
AT_SETUP([gzip])
|
||||
AT_KEYWORDS([gzip])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
|
||||
AT_CHECK([
|
||||
tar xfvz /dev/null
|
||||
test $? = 2 || exit 1
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
[
|
||||
gzip: stdin: unexpected end of file
|
||||
tar: Child returned status 1
|
||||
tar: Error exit delayed from previous errors
|
||||
],
|
||||
[],[])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,17 +0,0 @@
|
||||
#! /bin/sh
|
||||
# tar should detect that its gzip child failed.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
tar xfvz /dev/null
|
||||
test $? = 2 || exit 1
|
||||
|
||||
err="\
|
||||
|
||||
gzip: stdin: unexpected end of file
|
||||
tar: Child returned status 1
|
||||
tar: Error exit delayed from previous errors
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
79
tests/ignfail.at
Normal file
79
tests/ignfail.at
Normal file
@@ -0,0 +1,79 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Unreadable directories yielded error despite --ignore-failed-read.
|
||||
|
||||
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
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 file
|
||||
tar cf archive file
|
||||
status=$?
|
||||
chmod 600 file
|
||||
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 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
|
||||
fi
|
||||
],
|
||||
[0],
|
||||
[],
|
||||
[
|
||||
-----
|
||||
tar: file: Cannot open: Permission denied
|
||||
tar: Error exit delayed from previous errors
|
||||
-----
|
||||
tar: file: Warning: Cannot open: Permission denied
|
||||
-----
|
||||
tar: directory: Cannot savedir: Permission denied
|
||||
tar: Error exit delayed from previous errors
|
||||
-----
|
||||
tar: directory: Warning: Cannot savedir: Permission denied
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -1,63 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Unreadable directories yielded error despite --ignore-failed-read.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
> check-uid
|
||||
set - x`ls -l check-uid`
|
||||
if test $3 = root; then
|
||||
|
||||
# The test is meaningless for super-user.
|
||||
rm check-uid
|
||||
|
||||
else
|
||||
|
||||
touch file
|
||||
mkdir directory
|
||||
touch directory/file
|
||||
|
||||
echo 1>&2 -----
|
||||
chmod 000 file
|
||||
tar cf archive file
|
||||
status=$?
|
||||
chmod 600 file
|
||||
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 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 || exit 1
|
||||
|
||||
err="\
|
||||
-----
|
||||
tar: Cannot add file file: Permission denied
|
||||
tar: Error exit delayed from previous errors
|
||||
-----
|
||||
tar: Cannot add file file: Permission denied
|
||||
-----
|
||||
tar: Cannot add directory directory: Permission denied
|
||||
tar: Error exit delayed from previous errors
|
||||
-----
|
||||
tar: Cannot add directory directory: Permission denied
|
||||
"
|
||||
|
||||
fi
|
||||
|
||||
. $srcdir/after
|
||||
@@ -1,40 +0,0 @@
|
||||
#! /bin/sh
|
||||
# A directory older than the listed entry was skipped completely.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
prereq gnu oldgnu
|
||||
|
||||
set -e
|
||||
mkdir structure
|
||||
echo x >structure/file
|
||||
|
||||
# On Nextstep (and perhaps other 4.3BSD systems),
|
||||
# a newly created file's ctime isn't updated
|
||||
# until the next sync or stat operation on the file.
|
||||
ls -l structure/file >/dev/null
|
||||
|
||||
# If the time of an initial backup and the creation time of a file contained
|
||||
# in that backup are the same, the file will be backed up again when an
|
||||
# incremental backup is done, because the incremental backup backs up
|
||||
# files created `on or after' the initial backup time. Without the sleep
|
||||
# command, behaviour of tar becomes variable, depending whether the system
|
||||
# clock ticked over to the next second between creating the file and
|
||||
# backing it up.
|
||||
sleep 1
|
||||
|
||||
tar cf archive --listed=list structure
|
||||
tar cfv archive --listed=list structure
|
||||
echo -----
|
||||
sleep 1
|
||||
echo y >structure/file
|
||||
tar cfv archive --listed=list structure
|
||||
|
||||
out="\
|
||||
structure/
|
||||
-----
|
||||
structure/
|
||||
structure/file
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
60
tests/incremental.at
Normal file
60
tests/incremental.at
Normal file
@@ -0,0 +1,60 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# A directory older than the listed entry was skipped completely.
|
||||
|
||||
AT_SETUP([incremental])
|
||||
AT_KEYWORDS([incremental])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir structure
|
||||
echo x >structure/file
|
||||
|
||||
# On Nextstep (and perhaps other 4.3BSD systems),
|
||||
# a newly created file's ctime isn't updated
|
||||
# until the next sync or stat operation on the file.
|
||||
ls -l structure/file >/dev/null
|
||||
|
||||
# If the time of an initial backup and the creation time of a file contained
|
||||
# in that backup are the same, the file will be backed up again when an
|
||||
# incremental backup is done, because the incremental backup backs up
|
||||
# files created `on or after' the initial backup time. Without the sleep
|
||||
# command, behaviour of tar becomes variable, depending whether the system
|
||||
# clock ticked over to the next second between creating the file and
|
||||
# backing it up.
|
||||
sleep 1
|
||||
|
||||
tar cf archive --listed=list structure
|
||||
tar cfv archive --listed=list structure
|
||||
echo separator
|
||||
sleep 1
|
||||
echo y >structure/file
|
||||
tar cfv archive --listed=list structure
|
||||
],
|
||||
[0],
|
||||
[
|
||||
structure/
|
||||
separator
|
||||
structure/
|
||||
structure/file
|
||||
],
|
||||
[],[],[],[gnu,oldgnu])
|
||||
|
||||
AT_CLEANUP
|
||||
55
tests/link01.at
Normal file
55
tests/link01.at
Normal file
@@ -0,0 +1,55 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Problem: If a member with link count > 2 was stored in the archive twice,
|
||||
# previous versions of tar were not able to extract it, since they
|
||||
# were trying to link the file to itself, which always failed and
|
||||
# lead to removing the already extracted copy. This script tests
|
||||
# the workaround by Paul Eggert that leaves the extracted copy
|
||||
# untouched.
|
||||
#
|
||||
# Reported by: Toby Peterson <toby@apple.com>
|
||||
#
|
||||
# References: <2330D503-D20A-11D8-A0CF-00039391EECE@apple.com>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-07/msg00009.html
|
||||
|
||||
AT_SETUP([link count gt 2])
|
||||
AT_KEYWORDS([link01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
mkdir directory/test1
|
||||
mkdir directory/test2
|
||||
|
||||
echo TEST > directory/test1/test.txt
|
||||
ln directory/test1/test.txt directory/test2/test.txt
|
||||
|
||||
tar cf archive directory/test1/test.txt directory/test1/test.txt
|
||||
|
||||
rm -r directory
|
||||
tar xf archive
|
||||
|
||||
ls directory/test1
|
||||
],
|
||||
[0],
|
||||
[test.txt
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
46
tests/listed01.sh → tests/listed01.at
Executable file → Normal file
46
tests/listed01.sh → tests/listed01.at
Executable file → Normal file
@@ -1,32 +1,34 @@
|
||||
#! /bin/sh
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Check if listed-incremental backups work for individual files.
|
||||
# Script proposed by Andreas Schuldei <andreas@schuldei.org>
|
||||
|
||||
# This file is part of GNU tar testsuite.
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
prereq gnu oldgnu
|
||||
# Check if listed-incremental backups work for individual files.
|
||||
# Script proposed by Andreas Schuldei <andreas@schuldei.org>
|
||||
# References: <20040215014223.GA9699@lukas.schuldei.com>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-02/msg00011.html
|
||||
|
||||
AT_SETUP([--listed for individual files])
|
||||
AT_KEYWORDS([listed01])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
dd if=/dev/zero of=directory/file1 bs=1024 count=10 2>/dev/null
|
||||
genfile --length 10240 --pattern zeros > directory/file1
|
||||
# Let the things settle
|
||||
sleep 1
|
||||
|
||||
@@ -35,23 +37,25 @@ tar --create \
|
||||
--listed-incremental=listing \
|
||||
directory/file*
|
||||
|
||||
tar tf archive.1
|
||||
tar tf archive.1 || exit 1
|
||||
|
||||
dd if=/dev/zero of=directory/file2 bs=1024 count=20 2>/dev/null
|
||||
genfile --length 10240 --pattern zeros > directory/file2
|
||||
|
||||
echo "separator"
|
||||
|
||||
tar --create \
|
||||
--file=archive.2 \
|
||||
--listed-incremental=listing \
|
||||
directory/file*
|
||||
directory/file* || exit 1
|
||||
|
||||
tar tf archive.2
|
||||
|
||||
out="\
|
||||
directory/file1
|
||||
tar tf archive.2 || exit 1
|
||||
],
|
||||
[0],
|
||||
[directory/file1
|
||||
separator
|
||||
directory/file2
|
||||
"
|
||||
],
|
||||
[],[],[],[gnu, oldgnu])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
. $srcdir/after
|
||||
150
tests/listed02.at
Normal file
150
tests/listed02.at
Normal file
@@ -0,0 +1,150 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Check if listed-incremental backups work for files moved from one directory
|
||||
# to another.
|
||||
# Based on a script by Martin Simmons <ZYHYLCRMZPRP@spammotel.com>
|
||||
# References:
|
||||
# <20040626230315.163AA1D148@cpc5-cmbg1-6-0-cust208.cmbg.cable.ntl.com>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-06/msg00028.html
|
||||
|
||||
AT_SETUP([working --listed])
|
||||
AT_KEYWORDS([listed02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
|
||||
echo Create directories
|
||||
mkdir tart
|
||||
sleep 1
|
||||
mkdir tart/c0
|
||||
sleep 1
|
||||
mkdir tart/c1
|
||||
sleep 1
|
||||
|
||||
for file in tart/a1 tart/b1 tart/c0/cq1 tart/c0/cq2 tart/c1/ca1 tart/c1/ca2
|
||||
do
|
||||
echo File $file > $file
|
||||
sleep 1
|
||||
done
|
||||
|
||||
sleep 1
|
||||
echo Creating main archive
|
||||
tar -c -v --listed-incremental=tart.incr1 -f archive.1 tart || exit 1
|
||||
|
||||
sleep 1
|
||||
echo Modifying filesystem
|
||||
rm tart/a1
|
||||
mv tart/b1 tart/b2
|
||||
mv tart/c1 tart/c2
|
||||
touch tart/c2/ca3
|
||||
|
||||
echo Directory contents
|
||||
find tart|sort
|
||||
|
||||
sleep 1
|
||||
echo Creating incremental archive
|
||||
cp -p tart.incr1 tart.incr2
|
||||
tar -c -v --listed-incremental=tart.incr2 -f archive.2 tart || exit 1
|
||||
|
||||
sleep 1
|
||||
|
||||
rm -rf tart/*
|
||||
echo Extracting main archive
|
||||
tar -x -v --listed-incremental=tart.incr1 -f archive.1 || exit 1
|
||||
echo Extracting incremental archive
|
||||
# This command should produce three messages about deletion
|
||||
# of the existing files, that may appear in any order. Piping
|
||||
# to sort makes sure we don't depend on any particular ordering.
|
||||
tar -x -v --listed-incremental=tart.incr2 -f archive.2 | sort
|
||||
|
||||
echo Final files:
|
||||
find tart|sort
|
||||
],
|
||||
[0],
|
||||
[Create directories
|
||||
Creating main archive
|
||||
tart/
|
||||
tart/c0/
|
||||
tart/c1/
|
||||
tart/a1
|
||||
tart/b1
|
||||
tart/c0/cq1
|
||||
tart/c0/cq2
|
||||
tart/c1/ca1
|
||||
tart/c1/ca2
|
||||
Modifying filesystem
|
||||
Directory contents
|
||||
tart
|
||||
tart/b2
|
||||
tart/c0
|
||||
tart/c0/cq1
|
||||
tart/c0/cq2
|
||||
tart/c2
|
||||
tart/c2/ca1
|
||||
tart/c2/ca2
|
||||
tart/c2/ca3
|
||||
Creating incremental archive
|
||||
tart/
|
||||
tart/c0/
|
||||
tart/c2/
|
||||
tart/b2
|
||||
tart/c2/ca1
|
||||
tart/c2/ca2
|
||||
tart/c2/ca3
|
||||
Extracting main archive
|
||||
tart/
|
||||
tart/c0/
|
||||
tart/c1/
|
||||
tart/a1
|
||||
tart/b1
|
||||
tart/c0/cq1
|
||||
tart/c0/cq2
|
||||
tart/c1/ca1
|
||||
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
|
||||
tart/b2
|
||||
tart/c0
|
||||
tart/c0/cq1
|
||||
tart/c0/cq2
|
||||
tart/c2
|
||||
tart/c2/ca1
|
||||
tart/c2/ca2
|
||||
tart/c2/ca3
|
||||
],
|
||||
[tar: tart/c0: Directory is new
|
||||
tar: tart/c1: Directory is new
|
||||
tar: tart/c2: Directory is new
|
||||
],
|
||||
[],[],[gnu, oldgnu])
|
||||
|
||||
AT_CLEANUP
|
||||
48
tests/longv7.at
Normal file
48
tests/longv7.at
Normal file
@@ -0,0 +1,48 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Old format (V7) archives should not accept file names longer than
|
||||
# 99 characters
|
||||
|
||||
AT_SETUP([V7 and long names])
|
||||
AT_KEYWORDS([longv7])
|
||||
|
||||
m4_define([DIR],[this_is_a_very_long_name_for_a_directory_which_causes_problems])
|
||||
m4_define([FILE],[this_is_a_very_long_file_name_which_raises_issues.c])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
mkdir DIR
|
||||
touch DIR/FILE
|
||||
|
||||
tar cf archive DIR
|
||||
echo separator
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[separator
|
||||
DIR/
|
||||
],
|
||||
[tar: DIR/FILE: file name is too long (max 99); not dumped
|
||||
tar: Error exit delayed from previous errors
|
||||
],
|
||||
[],[],[v7])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
159
tests/mksparse.c
159
tests/mksparse.c
@@ -1,159 +0,0 @@
|
||||
/* This file is part of GNU tar test suite
|
||||
|
||||
Copyright (C) 2004 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.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
char *progname;
|
||||
char *buffer;
|
||||
size_t buffer_size;
|
||||
|
||||
void
|
||||
die (char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stderr, fmt, ap);
|
||||
va_end (ap);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
mkhole (int fd, off_t displ)
|
||||
{
|
||||
if (displ = lseek (fd, displ, SEEK_CUR) == -1)
|
||||
{
|
||||
perror ("lseek");
|
||||
exit (1);
|
||||
}
|
||||
ftruncate (fd, lseek (fd, 0, SEEK_CUR));
|
||||
}
|
||||
|
||||
void
|
||||
mksparse (int fd, off_t displ, char *marks)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (; *marks; marks++)
|
||||
{
|
||||
memset (buffer, *marks, buffer_size);
|
||||
if (write(fd, buffer, buffer_size) != buffer_size)
|
||||
{
|
||||
perror ("write");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (lseek (fd, displ, SEEK_CUR) == -1)
|
||||
{
|
||||
perror ("lseek");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
printf ("Usage: mksparse filename blocksize disp letters [disp letters...] [disp]\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int
|
||||
xlat_suffix (off_t *vp, char *p)
|
||||
{
|
||||
if (p[1])
|
||||
return 1;
|
||||
switch (p[0])
|
||||
{
|
||||
case 'g':
|
||||
case 'G':
|
||||
*vp *= 1024;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
*vp *= 1024;
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
*vp *= 1024;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int fd;
|
||||
char *p;
|
||||
off_t n;
|
||||
|
||||
progname = strrchr (argv[0], '/');
|
||||
if (progname)
|
||||
progname++;
|
||||
else
|
||||
progname = argv[0];
|
||||
|
||||
if (argc < 4)
|
||||
usage ();
|
||||
|
||||
fd = open (argv[1], O_CREAT|O_TRUNC|O_RDWR, 0644);
|
||||
if (fd < 0)
|
||||
die ("cannot open %s", argv[1]);
|
||||
|
||||
n = strtoul (argv[2], &p, 0);
|
||||
if (n <= 0 || (*p && xlat_suffix (&n, p)))
|
||||
die ("Invalid buffer size: %s", argv[2]);
|
||||
buffer_size = n;
|
||||
buffer = malloc (buffer_size);
|
||||
if (!buffer)
|
||||
die ("Not enough memory");
|
||||
|
||||
for (i = 3; i < argc; i += 2)
|
||||
{
|
||||
off_t displ;
|
||||
|
||||
displ = strtoul (argv[i], &p, 0);
|
||||
if (displ < 0 || (*p && xlat_suffix (&displ, p)))
|
||||
die ("Invalid displacement: %s", argv[i]);
|
||||
|
||||
if (i == argc-1)
|
||||
{
|
||||
mkhole (fd, displ);
|
||||
break;
|
||||
}
|
||||
else
|
||||
mksparse (fd, displ, argv[i+1]);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
59
tests/multiv01.at
Normal file
59
tests/multiv01.at
Normal file
@@ -0,0 +1,59 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Test multivolume dumps from pipes.
|
||||
|
||||
AT_SETUP([multivolume dumps from pipes])
|
||||
AT_KEYWORDS([multiv01])
|
||||
|
||||
# Fixme: should be configurable
|
||||
# TRUSS=truss -o /tmp/tr
|
||||
# TRUSS=strace
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --length 7168 > file1
|
||||
|
||||
for block in " 1" " 2" " 3" " 4" " 5" " 6" " 7" " 8" \
|
||||
" 9" "10" "11" "12" "13" "14" "15" "16" ; do \
|
||||
echo "file2 block ${block} bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla"
|
||||
for count in 2 3 4 5 6 7 8 ; do
|
||||
echo "bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla"
|
||||
done
|
||||
done >file2
|
||||
|
||||
tar -c --multi-volume --tape-length=10 \
|
||||
--listed-incremental=t.snar \
|
||||
-f t1-pipe.tar -f t2-pipe.tar ./file1 ./file2 || exit 1
|
||||
|
||||
mkdir extract-dir-pipe
|
||||
dd bs=4096 count=10 if=t2-pipe.tar 2>/dev/null |
|
||||
PATH=$PATH ${TRUSS} tar -f t1-pipe.tar -f - \
|
||||
-C extract-dir-pipe -x --multi-volume \
|
||||
--tape-length=10 --read-full-records || exit 1
|
||||
|
||||
cmp file1 extract-dir-pipe/file1
|
||||
cmp file2 extract-dir-pipe/file2
|
||||
],
|
||||
[0],
|
||||
[],[],[],[],[gnu, oldgnu])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Test multivolume dumps from pipes.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
prereq gnu oldgnu
|
||||
|
||||
# Fixme: should be configurable
|
||||
# TRUSS=truss -o /tmp/tr
|
||||
# TRUSS=strace
|
||||
set -e
|
||||
|
||||
dd if=/dev/zero bs=1024 count=7 2>/dev/null >file1
|
||||
|
||||
for block in " 1" " 2" " 3" " 4" " 5" " 6" " 7" " 8" \
|
||||
" 9" "10" "11" "12" "13" "14" "15" "16" ; do \
|
||||
echo "file2 block ${block} bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla"
|
||||
for count in 2 3 4 5 6 7 8 ; do
|
||||
echo "bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla!bla"
|
||||
done
|
||||
done >file2
|
||||
|
||||
tar -c --multi-volume --tape-length=10 \
|
||||
--listed-incremental=t.snar \
|
||||
-f t1-pipe.tar -f t2-pipe.tar ./file1 ./file2
|
||||
|
||||
mkdir extract-dir-pipe
|
||||
dd bs=4096 count=10 if=t2-pipe.tar 2>/dev/null |
|
||||
PATH=$PATH ${TRUSS} tar -f t1-pipe.tar -f - \
|
||||
-C extract-dir-pipe -x --multi-volume \
|
||||
--tape-length=10 --read-full-records
|
||||
|
||||
cmp file1 extract-dir-pipe/file1
|
||||
cmp file2 extract-dir-pipe/file2
|
||||
|
||||
out="\
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
47
tests/multiv02.at
Normal file
47
tests/multiv02.at
Normal file
@@ -0,0 +1,47 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Previous versions of tar were not able to skip a member straddling
|
||||
# the multivolume archive boundary. Reported by Mads Martin Joergensen
|
||||
# <mmj@suse.de>
|
||||
#
|
||||
# References: <20040402144254.GC4409@suse.de>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-04/msg00002.html
|
||||
|
||||
AT_SETUP([skipping a straddling member])
|
||||
AT_KEYWORDS([multiv02])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
genfile --length 10240 > en
|
||||
genfile --length 20000 > to
|
||||
genfile --length 20000 > tre
|
||||
genfile --length 10240 > fire
|
||||
|
||||
tar -c -f A.tar -f B.tar -f C.tar -M -L 30 en to tre fire || exit 1
|
||||
echo separator
|
||||
tar -v -x -f A.tar -f B.tar -f C.tar -M en || exit 1
|
||||
],
|
||||
[0],
|
||||
[separator
|
||||
en
|
||||
],
|
||||
[],[],[],[gnu, oldgnu])
|
||||
|
||||
AT_CLEANUP
|
||||
61
tests/multiv03.at
Normal file
61
tests/multiv03.at
Normal file
@@ -0,0 +1,61 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Problem: GNU multivolume archives are not able to continue on members
|
||||
# with filenames longer than 100 characters. Versions of tar <= 1.14
|
||||
# were not checking filename lengths and produced malformed multivolume
|
||||
# headers.
|
||||
# References: <20040809214854.GB32706@suse.de>
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2004-08/msg00012.html
|
||||
|
||||
AT_SETUP([MV archive & long filenames])
|
||||
AT_KEYWORDS([multiv03])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AFILE=`awk 'BEGIN { for (i = 0; i < 100; i++) printf "a"; exit; }'`
|
||||
BFILE=`awk 'BEGIN { for (i = 0; i < 101; i++) printf "b"; exit; }'`
|
||||
|
||||
cat > ../experr <<EOF
|
||||
tar: $BFILE: file name too long to be stored in a GNU multivolume header
|
||||
tar: Error is not recoverable: exiting now
|
||||
EOF
|
||||
|
||||
cat > ../expout <<EOF
|
||||
$AFILE
|
||||
separator
|
||||
EOF
|
||||
|
||||
genfile --length 15360 > $AFILE
|
||||
|
||||
tar -M -L 10 -c -f arch.1 -f arch.2 $AFILE || exit 1
|
||||
tar -tM -f arch.1 -f arch.2 || exit 1
|
||||
|
||||
echo separator
|
||||
|
||||
genfile --length 15360 > $BFILE
|
||||
tar -M -L 10 -c -f arch.1 -f arch.2 $BFILE
|
||||
],
|
||||
[2],
|
||||
[expout],
|
||||
[experr],
|
||||
[],[],[gnu, oldgnu])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
37
tests/old.at
Normal file
37
tests/old.at
Normal file
@@ -0,0 +1,37 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# An old archive was not receiving directories.
|
||||
|
||||
AT_SETUP([old archives])
|
||||
AT_KEYWORDS([old])
|
||||
|
||||
unset TAR_OPTIONS
|
||||
AT_CHECK([
|
||||
mkdir directory
|
||||
tar cfvo archive directory || exit 1
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[directory/
|
||||
directory/
|
||||
])
|
||||
|
||||
AT_CLEANUP
|
||||
17
tests/old.sh
17
tests/old.sh
@@ -1,17 +0,0 @@
|
||||
#! /bin/sh
|
||||
# An old archive was not receiving directories.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
mkdir directory
|
||||
tar cfvo archive directory
|
||||
tar tf archive
|
||||
|
||||
out="\
|
||||
directory/
|
||||
directory/
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user