Compare commits
376 Commits
old
...
alpha_1_13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a887bbbe5 | ||
|
|
9e0d059205 | ||
|
|
97b9e3d31c | ||
|
|
7add6e4274 | ||
|
|
96148abcfe | ||
|
|
a00631babf | ||
|
|
b8754a37c7 | ||
|
|
fb766eefb4 | ||
|
|
b1f33c8362 | ||
|
|
7a8bded5dd | ||
|
|
2de1477b3d | ||
|
|
634927b7d2 | ||
|
|
7eeb467132 | ||
|
|
6847d128e9 | ||
|
|
44da0983c0 | ||
|
|
dfbfc2446f | ||
|
|
c145d8a6e3 | ||
|
|
985199c260 | ||
|
|
e8af2fec8a | ||
|
|
ee6aa2bea8 | ||
|
|
2ad098dfff | ||
|
|
b960c38c4b | ||
|
|
ccaedb6b29 | ||
|
|
d46025b23c | ||
|
|
72ac31581d | ||
|
|
64cca92a1f | ||
|
|
c487595864 | ||
|
|
29e59e07b1 | ||
|
|
74d29bc5de | ||
|
|
069c0d99ae | ||
|
|
f038194718 | ||
|
|
eff25ef359 | ||
|
|
b3060eabaf | ||
|
|
93a4273b66 | ||
|
|
17be45c834 | ||
|
|
694f427d0e | ||
|
|
b4e605a829 | ||
|
|
b58452bdbd | ||
|
|
ff541dcac6 | ||
|
|
6613170489 | ||
|
|
6ac0d0aadd | ||
|
|
694e8376ab | ||
|
|
440e65ef2c | ||
|
|
d0eceef438 | ||
|
|
434f2a22ba | ||
|
|
0bfb6e136d | ||
|
|
7d31c8176c | ||
|
|
cbde0aa660 | ||
|
|
251935d751 | ||
|
|
b840052b46 | ||
|
|
67d29a4d60 | ||
|
|
df7792b5d8 | ||
|
|
8b107d09e1 | ||
|
|
f6db096374 | ||
|
|
814c517a15 | ||
|
|
9771467dc8 | ||
|
|
64dd6a38b4 | ||
|
|
65ef81b0a3 | ||
|
|
143e677b5e | ||
|
|
092b81cb95 | ||
|
|
0ad27d1986 | ||
|
|
6c347931b1 | ||
|
|
d7860cb091 | ||
|
|
1665d38fb7 | ||
|
|
da99cd963d | ||
|
|
bda7d59010 | ||
|
|
463e7278f4 | ||
|
|
829b1dc328 | ||
|
|
dd6094f6c0 | ||
|
|
bc89f023c1 | ||
|
|
95be2c50b4 | ||
|
|
7631b4e595 | ||
|
|
aa5d3fc8a6 | ||
|
|
2690759c06 | ||
|
|
b74232b9ad | ||
|
|
3d09d579c1 | ||
|
|
a39523cc61 | ||
|
|
c506c33ad3 | ||
|
|
3710b34c7e | ||
|
|
ad37f06975 | ||
|
|
12b111ffa3 | ||
|
|
5160a64f71 | ||
|
|
f30c03c934 | ||
|
|
67a6a93b2f | ||
|
|
50b2227279 | ||
|
|
defde32533 | ||
|
|
fc184a85e1 | ||
|
|
f7ce5a4ec5 | ||
|
|
2a027394ef | ||
|
|
278a8945a6 | ||
|
|
bb0b5c01c9 | ||
|
|
15cb6d782c | ||
|
|
3b3f5da0e9 | ||
|
|
2a822f7a76 | ||
|
|
fb8788008b | ||
|
|
6eafe45176 | ||
|
|
084291fca1 | ||
|
|
5f32345fe6 | ||
|
|
fa2801b6dc | ||
|
|
f193c4c04a | ||
|
|
47e73c7a44 | ||
|
|
2632f1c8d2 | ||
|
|
4dcf7987f8 | ||
|
|
374ce58aa0 | ||
|
|
475a54cc06 | ||
|
|
b741d17b27 | ||
|
|
a41d27ff5b | ||
|
|
869326ae90 | ||
|
|
25d9ca1163 | ||
|
|
d7e8c16a89 | ||
|
|
8d6e47cc7f | ||
|
|
b3404769c3 | ||
|
|
bb798080be | ||
|
|
d4e70d3656 | ||
|
|
82e94dab6d | ||
|
|
a8b2b68c33 | ||
|
|
40ede4e2df | ||
|
|
22ae47de82 | ||
|
|
7c05e2f650 | ||
|
|
80e5de9310 | ||
|
|
3999bf6360 | ||
|
|
87fa28ed2a | ||
|
|
3cdbeffe30 | ||
|
|
80b8de13ce | ||
|
|
caa20e5bac | ||
|
|
18ef8acac5 | ||
|
|
fad21ebf58 | ||
|
|
69bbe71607 | ||
|
|
7836f927b3 | ||
|
|
8c0a6b24b2 | ||
|
|
ebeb3d4f30 | ||
|
|
3bfdc3f8ce | ||
|
|
bc73e3d68d | ||
|
|
5f152198cb | ||
|
|
8f5dc5ffa4 | ||
|
|
f92c7cf4c8 | ||
|
|
ca99923dcd | ||
|
|
347ea38cc4 | ||
|
|
7e2f7ead1c | ||
|
|
052118a907 | ||
|
|
fe4ee38fce | ||
|
|
040bc32535 | ||
|
|
d4f872de37 | ||
|
|
4ed709c3c2 | ||
|
|
c95535bae8 | ||
|
|
cc8628df0c | ||
|
|
572225dfdc | ||
|
|
182091e79f | ||
|
|
f035e8f9e2 | ||
|
|
8a3b098acf | ||
|
|
8cea4725f4 | ||
|
|
f6be77cada | ||
|
|
4414f1a82c | ||
|
|
761802e87a | ||
|
|
b7ed638806 | ||
|
|
5d0b6564f3 | ||
|
|
9e445dcdd1 | ||
|
|
c2ba0ffa3e | ||
|
|
4bc226bb42 | ||
|
|
1a1f2d33d5 | ||
|
|
80088dcafc | ||
|
|
006d3dc1d5 | ||
|
|
80e978dc2e | ||
|
|
89d2ad35e6 | ||
|
|
bf6b473b3b | ||
|
|
151d1386e1 | ||
|
|
32c1e664e5 | ||
|
|
cb090cfe82 | ||
|
|
1e7d274cd8 | ||
|
|
4f644c3479 | ||
|
|
0008f61237 | ||
|
|
a0d91086c4 | ||
|
|
c1b9212b16 | ||
|
|
3b76d26206 | ||
|
|
719c762d80 | ||
|
|
b085ca3097 | ||
|
|
cf08a6de1b | ||
|
|
86f7407ffe | ||
|
|
33b04d5ecd | ||
|
|
eb6bef9909 | ||
|
|
bbbbf42fa6 | ||
|
|
91493ea9b6 | ||
|
|
dcb7c93527 | ||
|
|
f4935ab55d | ||
|
|
660c6d9b64 | ||
|
|
35d44a05eb | ||
|
|
4cf3121472 | ||
|
|
7c1a245918 | ||
|
|
634baf4d87 | ||
|
|
a6344f97a6 | ||
|
|
e23ad5b4f6 | ||
|
|
f364d50661 | ||
|
|
17878ad672 | ||
|
|
13be4005e7 | ||
|
|
6c16197226 | ||
|
|
05b3fdccc1 | ||
|
|
9373182407 | ||
|
|
00ac26f00c | ||
|
|
07286647fb | ||
|
|
b0e8ba8839 | ||
|
|
21dd6332cc | ||
|
|
867f933aac | ||
|
|
6848f79e3b | ||
|
|
491bcfb153 | ||
|
|
6de6421787 | ||
|
|
0e1e4d8381 | ||
|
|
54e322110c | ||
|
|
659f70a38a | ||
|
|
9e783c548c | ||
|
|
a0c656364a | ||
|
|
674691c7ba | ||
|
|
0289902e4a | ||
|
|
187c23b8d7 | ||
|
|
91b2d65e9d | ||
|
|
99f41a1224 | ||
|
|
eada0a9b35 | ||
|
|
3590887776 | ||
|
|
ddab1f615e | ||
|
|
d93cbfbf0b | ||
|
|
5b9d8c93c7 | ||
|
|
08cfd54f54 | ||
|
|
75b511727c | ||
|
|
a86cdfa58b | ||
|
|
f3875c4a26 | ||
|
|
8b4453b4e2 | ||
|
|
7645d20465 | ||
|
|
08780d289d | ||
|
|
e400810b5d | ||
|
|
3f998f69b9 | ||
|
|
aea0a1d970 | ||
|
|
87ff702389 | ||
|
|
c92c357a62 | ||
|
|
0ba3b75ad4 | ||
|
|
9f0cdc8f56 | ||
|
|
c54ec5a895 | ||
|
|
10edb315da | ||
|
|
df06a57b8c | ||
|
|
14e8c10222 | ||
|
|
a546fc7c21 | ||
|
|
86a9b9261d | ||
|
|
7653d2f6b8 | ||
|
|
2c390b2c21 | ||
|
|
c4d396f8d1 | ||
|
|
40138ceb05 | ||
|
|
99a5f5d4f9 | ||
|
|
01decb5737 | ||
|
|
ce059f3cc8 | ||
|
|
01f19e973b | ||
|
|
c76e8a861e | ||
|
|
8750043986 | ||
|
|
49ce0ebbea | ||
|
|
9e4f9e232c | ||
|
|
c3440ae0c9 | ||
|
|
d71b31e241 | ||
|
|
4d0ac610b0 | ||
|
|
c22a8b44d7 | ||
|
|
4189af3785 | ||
|
|
33b63ebe94 | ||
|
|
879ae47aa1 | ||
|
|
53eec8f039 | ||
|
|
83c68b4e40 | ||
|
|
cb3ec64970 | ||
|
|
72e5a9beb6 | ||
|
|
7657bd4323 | ||
|
|
518748f939 | ||
|
|
db783659b0 | ||
|
|
d858a433c8 | ||
|
|
096bc2bffd | ||
|
|
6f12dbc264 | ||
|
|
450636adfa | ||
|
|
4e59b9d7e3 | ||
|
|
5be0f2ba49 | ||
|
|
81a9e2ae36 | ||
|
|
a18256492a | ||
|
|
cab627b49d | ||
|
|
317fbb9d5f | ||
|
|
a687cf05b7 | ||
|
|
df2f967cdd | ||
|
|
d52a1bb366 | ||
|
|
2adfef0149 | ||
|
|
bee35fc152 | ||
|
|
1fef6258aa | ||
|
|
b68057816b | ||
|
|
6dd7e857e5 | ||
|
|
eb42c0070d | ||
|
|
d4bcefe915 | ||
|
|
7219c538eb | ||
|
|
5a73638d27 | ||
|
|
83a5c01349 | ||
|
|
b84cc97df7 | ||
|
|
4f48e61fcf | ||
|
|
eb66edaa9f | ||
|
|
31d9c7e2a4 | ||
|
|
cd206cd899 | ||
|
|
4dc30d7397 | ||
|
|
96148b87b7 | ||
|
|
09c4d7dc3c | ||
|
|
46f2740ff9 | ||
|
|
88ffc1355e | ||
|
|
4a16f6c039 | ||
|
|
33cdac5e60 | ||
|
|
bce576a03b | ||
|
|
f7ccf5eb1c | ||
|
|
8912f582ac | ||
|
|
4c690508bd | ||
|
|
42d05fcb6e | ||
|
|
40835c2c55 | ||
|
|
1722082cfe | ||
|
|
45dd602433 | ||
|
|
935cd4f515 | ||
|
|
f29b54b237 | ||
|
|
675c5a2f24 | ||
|
|
ea202e1adf | ||
|
|
664f2dbdd9 | ||
|
|
15726fabad | ||
|
|
f2ad7d403e | ||
|
|
01d81c7f0f | ||
|
|
e4a052cd21 | ||
|
|
89662fe926 | ||
|
|
d5100e76cf | ||
|
|
622724a886 | ||
|
|
b9be191da0 | ||
|
|
121b4241d7 | ||
|
|
39f69360f0 | ||
|
|
f3364ac428 | ||
|
|
e547e855e9 | ||
|
|
bdece51882 | ||
|
|
fcb62b60d9 | ||
|
|
dc861c7ab9 | ||
|
|
7154feb583 | ||
|
|
4f5e37c861 | ||
|
|
504274b059 | ||
|
|
4ff9279d9d | ||
|
|
b94aa0bc5f | ||
|
|
784a497c40 | ||
|
|
f2daf2e598 | ||
|
|
859ba730d5 | ||
|
|
d1c27c2308 | ||
|
|
9ded0a0567 | ||
|
|
4bfdfaa270 | ||
|
|
ba32aa1147 | ||
|
|
bb5b309581 | ||
|
|
f762709bb0 | ||
|
|
88711e3972 | ||
|
|
06384f1def | ||
|
|
bab605d5bd | ||
|
|
9c93a32114 | ||
|
|
7f1bf2e09f | ||
|
|
3847d0f51f | ||
|
|
dd83d5dd9d | ||
|
|
1735867f56 | ||
|
|
fb1c65e512 | ||
|
|
1a9ace4d99 | ||
|
|
1ad624bbbc | ||
|
|
02a275c6ac | ||
|
|
61170ee840 | ||
|
|
f42a0e5af3 | ||
|
|
e6e72bf7ed | ||
|
|
1b10ab140f | ||
|
|
9a15fcf491 | ||
|
|
e2b5f1e918 | ||
|
|
4dbeac6c7f | ||
|
|
63db9071d2 | ||
|
|
5a5f4d06e7 | ||
|
|
ec63030958 | ||
|
|
0e041a7bfe | ||
|
|
85f651c8c6 | ||
|
|
6c9e824ce5 | ||
|
|
95a4feb37b | ||
|
|
06e4c77310 | ||
|
|
a942967415 | ||
|
|
92734c1511 | ||
|
|
4b5d60ef38 | ||
|
|
7a1b6cfa67 | ||
|
|
cc818a584f | ||
|
|
45bf6a9089 |
21
.cvsignore
Normal file
21
.cvsignore
Normal file
@@ -0,0 +1,21 @@
|
||||
config
|
||||
configure
|
||||
aclocal.m4
|
||||
ABOUT-NLS
|
||||
autom4te.cache
|
||||
config.hin
|
||||
COPYING
|
||||
INSTALL
|
||||
Makefile.in
|
||||
config.log
|
||||
config.status
|
||||
Makefile
|
||||
config.h
|
||||
stamp-h1
|
||||
*.tar
|
||||
*.tar.gz
|
||||
*.tar.bz2
|
||||
*.shar.gz
|
||||
gnulib
|
||||
gnulib/*
|
||||
gnulib/*/*
|
||||
6
AUTHORS
6
AUTHORS
@@ -3,6 +3,12 @@ Authors of GNU tar.
|
||||
The following contributions warranted legal paper exchanges with the
|
||||
Free Software Foundation. Also see files ChangeLog and THANKS.
|
||||
|
||||
TAR Sergey Poznyakoff 2003-10
|
||||
Assigns his past and future changes.
|
||||
|
||||
TAR Paul Eggert 2000-10
|
||||
Assigns his past and future changes.
|
||||
|
||||
TAR Jay Fenlason
|
||||
Assigns his changes.
|
||||
|
||||
|
||||
850
ChangeLog.1
850
ChangeLog.1
File diff suppressed because it is too large
Load Diff
71
Makefile.am
71
Makefile.am
@@ -1,60 +1,23 @@
|
||||
# Main Makefile for GNU tar.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997 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.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
## This 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.
|
||||
|
||||
# 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.
|
||||
## 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.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits dist-shar
|
||||
## 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.
|
||||
|
||||
BABYL = rmail/* admin/*/RMAIL
|
||||
EXTRA_DIST = AC-PATCHES AM-PATCHES BI-PATCHES PORTS rebox.el
|
||||
SUBDIRS = doc lib intl src scripts po tests
|
||||
|
||||
all-local: $(CONFIG_HEADER)
|
||||
|
||||
id: ID
|
||||
|
||||
ID:
|
||||
cd lib && $(MAKE) $@
|
||||
cd src && $(MAKE) $@
|
||||
|
||||
dist-zoo: $(DISTFILES)
|
||||
rm -rf $(distdir)
|
||||
mkdir $(distdir)
|
||||
distdir=`cd $(distdir) && pwd` \
|
||||
&& cd $(srcdir) \
|
||||
&& automake --include-deps --output-dir=$$distdir
|
||||
@for file in $(DISTFILES); do \
|
||||
test -f $(distdir)/$$file \
|
||||
|| cp -p $(srcdir)/$$file $(distdir)/$$file; \
|
||||
done
|
||||
for subdir in $(SUBDIRS); do \
|
||||
test -d $(distdir)/$$subdir \
|
||||
|| mkdir $(distdir)/$$subdir \
|
||||
|| exit 1; \
|
||||
chmod 777 $(distdir)/$$subdir; \
|
||||
(cd $$subdir && $(MAKE) dist) || exit 1; \
|
||||
done
|
||||
@sublist="$(DIST_SUBDIRS)"; \
|
||||
for dir in $$sublist; do \
|
||||
echo copying directory $$dir; \
|
||||
tar -chf - $$dir | (cd $(distdir) && tar -xBpf -); \
|
||||
done
|
||||
chmod -R a+r $(distdir)
|
||||
find $(distdir) -type f | xargs dosfn
|
||||
# find $(distdir) -type f | xargs recode :ibmpc
|
||||
mv $(distdir) $(PACKAGE)
|
||||
find $(PACKAGE) -type f | zoo ahIq $(PACKAGE).zoo
|
||||
rm -rf $(PACKAGE)
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = ChangeLog.1 PORTS
|
||||
SUBDIRS = doc lib src scripts po tests
|
||||
|
||||
92
NEWS
92
NEWS
@@ -1,4 +1,77 @@
|
||||
GNU tar NEWS - User visible changes.
|
||||
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
|
||||
Free Software Foundation, Inc.
|
||||
See the end for copying conditions.
|
||||
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
|
||||
version 1.13.93
|
||||
|
||||
* Added support for POSIX.1-2001 and ustar archive formats.
|
||||
* New option --format allows to select the output archive format
|
||||
* The default output format can be selected at configuration time
|
||||
by presetting the environment variable DEFAULT_ARCHIVE_FORMAT.
|
||||
Allowed values are GNU, V7, OLDGNU and POSIX.
|
||||
* New option --strip-path allows to cut off a given number of
|
||||
path elements from the name of the file being extracted.
|
||||
|
||||
* New options --index-file, --no-overwrite-dir. The --overwrite-dir
|
||||
option is now the default; use --no-overwrite-dir if you prefer
|
||||
the previous default behavior.
|
||||
|
||||
* The semantics of -o option is changed. When extracting, it
|
||||
does the same as --no-same-owner GNU tar option. This is compatible
|
||||
with UNIX98 tar. Otherwise, its effect is the same as that of
|
||||
--old-archive option. This latter is deprecated and will be removed
|
||||
in future.
|
||||
|
||||
* New option --check-links prints a message if not all links are dumped
|
||||
for a file being archived. This corresponds to the UNIX98 -l option.
|
||||
The current semantics of the -l option is retained for compatibility
|
||||
with previous releases, however such usage is strongly deprecated as
|
||||
the option will change to its UNIX98 semantics in the future releases.
|
||||
|
||||
* New option --occurrence[=N] can be used in conjunction with one of
|
||||
the subcommands --delete, --diff, --extract or --list when a list of
|
||||
files is given either on the command line or via -T option. This
|
||||
option instructs tar to process only the Nth occurrence of each named
|
||||
file. N defaults to 1, so `tar -x -f archive --occurrence filename'
|
||||
extracts the first occurrence of `filename' from `archive'
|
||||
and terminates without scanning to the end of the archive.
|
||||
|
||||
* New option --pax-option allows to control the handling of POSIX
|
||||
keywords in `pax' extended headers. It is equivalent to `pax'
|
||||
-o option.
|
||||
|
||||
* --incremental and --listed-incremental options work correctly on
|
||||
individual files, as well as on directories.
|
||||
|
||||
* Removed obsolete command line options:
|
||||
** --absolute-paths superseded by --absolute-names
|
||||
** --block-compress is not needed any longer
|
||||
** --block-size superseded by --blocking-factor
|
||||
** --modification-time superseded by --touch
|
||||
** --read-full-blocks superseded by --read-full-records
|
||||
** --record-number superseded by --block-number
|
||||
** --version-control superseded by --backup
|
||||
|
||||
* 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.
|
||||
|
||||
* 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
|
||||
|
||||
@@ -104,7 +177,7 @@ version 1.13.16 - Paul Eggert, 1999-12-13.
|
||||
To enable the old behavior, use the -P or --absolute-names option.
|
||||
|
||||
* Tar now handles file names with multibyte encodings (e.g. UTF-8, Shift-JIS)
|
||||
correctly. It relies on the mbrtowc function to handle multibytes.
|
||||
correctly. It relies on the mbrtowc function to handle multibyte characters.
|
||||
|
||||
* The file generated by -g or --listed-incremental now uses a format
|
||||
that is independent of locale, so that users need not worry about
|
||||
@@ -297,7 +370,7 @@ version 1.13 - Paul Eggert, 1999-07-08.
|
||||
but they have been removed to maintain compatibility with paxutils.
|
||||
Please try --use=bzip2 instead of --bzip2.
|
||||
|
||||
Version 1.12 - Fran<EFBFBD>ois Pinard, 1997-04.
|
||||
Version 1.12 - François Pinard, 1997-04.
|
||||
|
||||
Sensitive matters
|
||||
* Use shell globbing patterns for --label, instead of regular expressions.
|
||||
@@ -340,7 +413,7 @@ Various changes
|
||||
|
||||
Many bugs are squashed, while others still run free.
|
||||
|
||||
Version 1.11.8 - Fran<EFBFBD>ois Pinard, 1995-06.
|
||||
Version 1.11.8 - François Pinard, 1995-06.
|
||||
|
||||
* Messages available in French, German, Portuguese and Swedish.
|
||||
* The distribution provides a rudimentary Texinfo manual.
|
||||
@@ -476,8 +549,8 @@ Versions 1.07 back to 1.00 by Jay Fenlason.
|
||||
|
||||
|
||||
|
||||
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -495,9 +568,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
|
||||
Local Variables:
|
||||
coding: iso-latin-1
|
||||
End:
|
||||
Local variables:
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
end:
|
||||
|
||||
154
README
154
README
@@ -1,25 +1,7 @@
|
||||
README for GNU tar
|
||||
See the end of file for copying conditions.
|
||||
|
||||
Copyright 1990, 1991, 1992, 1994, 1997, 1998, 1999, 2000, 2001
|
||||
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 tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
* Introduction
|
||||
|
||||
Please glance through *all* sections of this
|
||||
`README' file before starting configuration. Also make sure you read files
|
||||
@@ -48,9 +30,15 @@ See file `THANKS' for a list of contributors.
|
||||
Besides those configure options documented in files `INSTALL' and
|
||||
`ABOUT-NLS', an extra option may be accepted after `./configure':
|
||||
|
||||
* `--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.
|
||||
* Install
|
||||
|
||||
** Selecting the default archive format.
|
||||
|
||||
The default archive format is GNU, this can be overridden by
|
||||
presetting DEFAULT_ARCHIVE_FORMAT while configuring. The allowed
|
||||
values are GNU, V7, OLDGNU, USTAR and POSIX.
|
||||
|
||||
** Selecting the default archive device
|
||||
|
||||
The default archive device is now `stdin' on read and `stdout' on write.
|
||||
The installer can still override this by presetting `DEFAULT_ARCHIVE'
|
||||
@@ -58,34 +46,15 @@ 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.
|
||||
|
||||
For comprehensive modifications to GNU tar, you might need tools beyond
|
||||
those used in simple installations. Fully install GNU m4 1.4 first,
|
||||
and only then, Autoconf 2.13 or later. Install Perl, then Automake
|
||||
1.4 or later. You might need Bison 1.28 or later, and GNU tar itself.
|
||||
All are available on GNU archive sites, like in
|
||||
ftp://ftp.gnu.org/pub/gnu/.
|
||||
** `--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.
|
||||
|
||||
Send bug reports to `bug-tar@gnu.org'. (Beware, old-timers: it is
|
||||
`@gnu', not `@prep'; and not `bug-gnu-utils' anymore.) A bug report is
|
||||
an adequate description of the problem: your input, what you expected,
|
||||
what you got, and why this is wrong. Diffs are welcome, but they only
|
||||
describe a solution, from which the problem might be uneasy to infer.
|
||||
If needed, submit actual data files with your report. Small data files
|
||||
are preferred. Big files may sometimes be necessary, but do not send them
|
||||
to the report address; rather take special arrangement with the maintainer.
|
||||
|
||||
Your feedback will help us to make a better and more portable package.
|
||||
Consider documentation errors as bugs, and report them as such. If you
|
||||
develop anything pertaining to `tar' or have suggestions, let us know
|
||||
and share your findings by writing to <bug-tar@gnu.org>.
|
||||
|
||||
|
||||
Installation hints
|
||||
------------------
|
||||
* Installation hints
|
||||
|
||||
Here are a few hints which might help installing `tar' on some systems.
|
||||
|
||||
* gzip and bzip2.
|
||||
** gzip and bzip2.
|
||||
|
||||
GNU tar uses the gzip and bzip2 programs to read and write compressed
|
||||
archives. If you don't have these programs already, you need to
|
||||
@@ -106,7 +75,7 @@ in gzip test version 1.3, which as of this writing is available at
|
||||
incompatibility by using a shell command like
|
||||
`gzip -d <file.tar.gz | tar -xzf -'.
|
||||
|
||||
* Solaris issues.
|
||||
** Solaris issues.
|
||||
|
||||
GNU tar exercises many features that can cause problems with older GCC
|
||||
versions. In particular, GCC 2.8.1 (sparc, -O1 or -O2) is known to
|
||||
@@ -117,7 +86,7 @@ Recent versions of Solaris tar sport a new -E option to generate
|
||||
extended headers in an undocumented format. GNU tar does not
|
||||
understand these headers.
|
||||
|
||||
* Static linking.
|
||||
** Static linking.
|
||||
|
||||
Some platform will, by default, prepare a smaller `tar' executable
|
||||
which depends on shared libraries. Since GNU `tar' may be used for
|
||||
@@ -138,34 +107,32 @@ to a value from the table below, before configuration (see `INSTALL').
|
||||
Solaris (vendor) -Bstatic
|
||||
SunOS (vendor) -Bstatic
|
||||
|
||||
* Failed tests `ignfail.sh' or `incremen.sh'.
|
||||
** Failed tests `ignfail.sh' or `incremen.sh'.
|
||||
|
||||
In an NFS environment, lack of synchronization between machine clocks
|
||||
might create difficulties to any tool comparing dates and file time stamps,
|
||||
like `tar' in incremental dumps. This has been a recurrent problem with
|
||||
GNU Make for the last few years. We would like a general solution.
|
||||
|
||||
* BSD compatibility matters.
|
||||
** BSD compatibility matters.
|
||||
|
||||
Set LIBS to `-lbsd' before configuration (see `INSTALL') if the linker
|
||||
complains about `bsd_ioctl' (Slackware). Also set CPPFLAGS to
|
||||
`-I/usr/include/bsd' if <sgtty.h> is not found (Slackware).
|
||||
|
||||
* OPENStep 4.2 swap files
|
||||
** OPENStep 4.2 swap files
|
||||
|
||||
Tar cannot read the file /private/vm/swapfile.front (even as root).
|
||||
This file is not a real file, but some kind of uncompressed view of
|
||||
the real compressed swap file; there is no reason to back it up, so
|
||||
the simplest workaround is to avoid tarring this file.
|
||||
|
||||
|
||||
Special topics
|
||||
--------------
|
||||
* Special topics
|
||||
|
||||
Here are a few special matters about GNU `tar', not related to build
|
||||
matters. See previous section for such.
|
||||
|
||||
* File attributes.
|
||||
** File attributes.
|
||||
|
||||
About *security*, it is probable that future releases of `tar' will have
|
||||
some behavior changed. There are many pending suggestions to choose from.
|
||||
@@ -178,19 +145,76 @@ implement flavors of symbolic links showing different behavior and
|
||||
properties. We did not successfully sorted all these out yet. Currently,
|
||||
the `lchown' call will be used if available, but that's all.
|
||||
|
||||
* POSIX compliance.
|
||||
** POSIX compliance.
|
||||
|
||||
GNU `tar' implements an early draft of the POSIX 1003.1 `ustar' standard
|
||||
which is different from the final standard. This will be progressively
|
||||
corrected over the incoming few years. Don't be mislead by the mere
|
||||
existence of the --posix option. Later releases will become able to
|
||||
read truly POSIX archives, and also to produce them under option. (Also,
|
||||
if you look at the internals, don't take the GNU extensions you see for
|
||||
granted, as they are planned to change.) GNU tar 2.0 will produce POSIX
|
||||
archives by default, but there is a long way before we get there.
|
||||
GNU `tar' is able to create archive in the following formats:
|
||||
|
||||
*** The format of UNIX version 7
|
||||
*** POSIX.1-1988 format, also known as "ustar format"
|
||||
*** POSIX.1-2001 format, also known as "pax format"
|
||||
*** Old GNU format (described below)
|
||||
|
||||
In addition to those, GNU `tar' is also able to read archives
|
||||
produced by `star' archiver.
|
||||
|
||||
A so called `Old GNU' format is based on an early draft of the
|
||||
POSIX 1003.1 `ustar' standard which is different from the final
|
||||
standard. It defines its extensions (such as incremental backups
|
||||
and handling of the long file names) in a way incompatible with
|
||||
any existing tar archive format, therefore the use of old GNU
|
||||
format is strongly discouraged.
|
||||
|
||||
Please read the file NEWS for more information about POSIX compliance
|
||||
and new `tar' features.
|
||||
|
||||
* 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.
|
||||
|
||||
* Bug reporting.
|
||||
|
||||
Send bug reports to <bug-tar@gnu.org>. A bug report should contain
|
||||
an adequate description of the problem, your input, what you expected,
|
||||
what you got, and why this is wrong. Diffs are welcome, but they only
|
||||
describe a solution, from which the problem might be uneasy to infer.
|
||||
If needed, submit actual data files with your report. Small data files
|
||||
are preferred. Big files may sometimes be necessary, but do not send them
|
||||
to the report address; rather take special arrangement with the maintainer.
|
||||
|
||||
Your feedback will help us to make a better and more portable package.
|
||||
Consider documentation errors as bugs, and report them as such. If you
|
||||
develop anything pertaining to `tar' or have suggestions, let us know
|
||||
and share your findings by writing to <bug-tar@gnu.org>.
|
||||
|
||||
|
||||
* Copying
|
||||
|
||||
Copyright (C) 1990, 1991, 1992, 1994, 1997, 1998, 1999, 2000,
|
||||
2001, 2003, 2004 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 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:
|
||||
|
||||
|
||||
172
README-alpha
172
README-alpha
@@ -1,112 +1,72 @@
|
||||
This is a test release of GNU tar.
|
||||
This is GNU tar.
|
||||
|
||||
This is a *pre-release* version, and not ready for production use yet.
|
||||
Please send comments and problem reports to <bug-tar@gnu.org>.
|
||||
|
||||
This release was built with GNU automake 1.5 patched as follows:
|
||||
If you have taken the sources from CVS you will need the following
|
||||
packages (or later) to build GNU tar. We don't make any extra effort
|
||||
to accommodate older versions of these packages. If we discover that
|
||||
newer versions are needed to bootstrap, we'll update the version
|
||||
numbers in this list.
|
||||
|
||||
2001-09-14 Paul Eggert <eggert@twinsun.com>
|
||||
autoconf 2.59
|
||||
automake 1.8
|
||||
bison 1.875
|
||||
gettext 0.12.1
|
||||
m4 1.4
|
||||
wget 1.7
|
||||
|
||||
* lib/am/distdir.am (REMOVE_DISTDIR):
|
||||
New macro. Do not change permission of non-directories.
|
||||
(distdir, dist, dist-bzip2, dist-tarZ, dist-shar, dist-zip, dist-all,
|
||||
distcheck): Use it.
|
||||
For GNU m4 1.4, we recommend also installing the `translit' patch; see
|
||||
Debian bug 211477 <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=211477>.
|
||||
This patch is bundled into Debian m4 1.4-17 or later.
|
||||
|
||||
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:
|
||||
|
||||
|
||||
--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.
|
||||
--cvs-auth=METHOD Set the CVS access method used for downloading
|
||||
gnulib files. METHOD is one of the keywords
|
||||
accepted by cvs -d option (see info cvs
|
||||
repository).
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
--no-po Do not download po files.
|
||||
|
||||
Notice also that when using CVS authentication method "ext", bootstrap
|
||||
will set the variable CVS_RSH to "ssh", unless it is already set to
|
||||
some other value.
|
||||
|
||||
|
||||
|
||||
Copyright (C) 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 tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
===================================================================
|
||||
RCS file: lib/am/distdir.am,v
|
||||
retrieving revision 1.5
|
||||
retrieving revision 1.5.0.1
|
||||
diff -pu -r1.5 -r1.5.0.1
|
||||
--- lib/am/distdir.am 2001/07/14 20:12:52 1.5
|
||||
+++ lib/am/distdir.am 2001/09/15 05:12:18 1.5.0.1
|
||||
@@ -29,6 +29,11 @@ else !%?TOPDIR_P%
|
||||
?DISTDIR?distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
|
||||
endif !%?TOPDIR_P%
|
||||
|
||||
+REMOVE_DISTDIR = \
|
||||
+ { test ! -d $(distdir) \
|
||||
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
+ && rm -fr $(distdir); }; }
|
||||
+
|
||||
distdir: $(DISTFILES)
|
||||
##
|
||||
## For Gnits users, this is pretty handy. Look at 15 lines
|
||||
@@ -47,7 +52,7 @@ endif %?TOPDIR_P%
|
||||
## Only for the top dir.
|
||||
##
|
||||
if %?TOPDIR_P%
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
mkdir $(distdir)
|
||||
endif %?TOPDIR_P%
|
||||
##
|
||||
@@ -168,13 +173,13 @@ GZIP_ENV = --best
|
||||
.PHONY: dist
|
||||
dist: distdir
|
||||
$(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
|
||||
if %?BZIP2%
|
||||
.PHONY: dist-bzip2
|
||||
dist-bzip2: distdir
|
||||
$(AMTAR) chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
endif %?BZIP2%
|
||||
|
||||
|
||||
@@ -182,7 +187,7 @@ if %?COMPRESS%
|
||||
.PHONY: dist-tarZ
|
||||
dist-tarZ: distdir
|
||||
$(AMTAR) chof - $(distdir) | compress -c >$(distdir).tar.Z
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
endif %?COMPRESS%
|
||||
|
||||
|
||||
@@ -190,7 +195,7 @@ if %?SHAR%
|
||||
.PHONY: dist-shar
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
endif %?SHAR%
|
||||
|
||||
|
||||
@@ -199,7 +204,7 @@ if %?ZIP%
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
endif %?ZIP%
|
||||
|
||||
endif %?TOPDIR_P%
|
||||
@@ -223,7 +228,7 @@ dist-all: distdir
|
||||
?SHAR? shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
?ZIP? -rm -f $(distdir).zip
|
||||
?ZIP? zip -rq $(distdir).zip $(distdir)
|
||||
- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
|
||||
endif %?TOPDIR_P%
|
||||
|
||||
@@ -239,8 +244,7 @@ if %?TOPDIR_P%
|
||||
# tarfile.
|
||||
.PHONY: distcheck
|
||||
distcheck: dist
|
||||
-## Make sure we can remove distdir before trying to remove it.
|
||||
- -chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf -
|
||||
## Make the new source tree read-only. Distributions ought to work in
|
||||
## this case. However, make the top-level directory writable so we
|
||||
@@ -273,7 +277,7 @@ distcheck: dist
|
||||
&& (test `find . -type f -print | wc -l` -eq 0 \
|
||||
|| (echo "Error: files left after distclean" 1>&2; \
|
||||
exit 1) )
|
||||
- -chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
|
||||
+ $(REMOVE_DISTDIR)
|
||||
@echo "$(distdir).tar.gz is ready for distribution" | \
|
||||
sed 'h;s/./=/g;p;x;p;x'
|
||||
endif %?TOPDIR_P%
|
||||
|
||||
101
THANKS
101
THANKS
@@ -1,9 +1,16 @@
|
||||
GNU tar THANKS file
|
||||
|
||||
GNU tar has originally been written by Graham Todd. Many people
|
||||
further contributed to GNU tar by reporting problems, suggesting
|
||||
various improvements or submitting actual code. Here is a list of
|
||||
these people. Help me keep it complete and exempt of errors.
|
||||
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
|
||||
Pinard and Paul Eggert.
|
||||
|
||||
Many people further contributed to GNU tar by reporting problems,
|
||||
suggesting various improvements or submitting actual code. Here is a
|
||||
list of these people. Help me keep it complete and exempt of errors.
|
||||
See various ChangeLogs for a detailed description of contributions.
|
||||
|
||||
Aage Robeck aagero@ifi.uio.no
|
||||
Akiko Matsushita matusita@sra.co.jp
|
||||
@@ -25,6 +32,7 @@ Andreas Haumer andreas@vlsivie.tuwien.ac.at
|
||||
Andreas Jaeger aj@arthur.pfalz.de
|
||||
Andreas Koppenhoefer koppenh@trick.informatik.uni-stuttgart.de
|
||||
Andreas Reuter ar205@bonzo.geowiss.nat.tu-bs.de
|
||||
Andreas Schuldei andreas@schuldei.org
|
||||
Andreas Schwab schwab@issan.informatik.uni-dortmund.de
|
||||
Andrew A. Ivanov ivanov@mics.msu.su
|
||||
Andrew J. Schorr schorr@ead.dsa.com
|
||||
@@ -34,7 +42,7 @@ Andy Gay andy@rdl.co.uk
|
||||
Antonio Jose Coutinho ajc@di.uminho.pt
|
||||
Ariel Faigon ariel@engr.sgi.com
|
||||
Arne Wichmann aw@math.uni-sb.de
|
||||
Arnold Robbins arnold@gnu.ai.mit.edu
|
||||
Arnold Robbins arnold@gnu.org
|
||||
Art Isbell aisbell@cubicsol.com
|
||||
Axel Boldt boldt@math.ucsb.edu
|
||||
Axel Habermann kiwi@belly.in-berlin.de
|
||||
@@ -47,6 +55,7 @@ Bennett Todd bet@mordor.com
|
||||
Benny Holmgren benny@hgs.se
|
||||
Bernard Chen bern@cs.ucla.edu
|
||||
Bernard Derval derval@iro.umontreal.ca
|
||||
Bernhard Rosenkraenzer bero@redhat.de
|
||||
Bo Nygaard Bai bai@iesd.auc.dk
|
||||
Bob Kaehms kaehms@was.archive.org
|
||||
Bob Mende Pie mende@piecomputer.rutgers.edu
|
||||
@@ -57,21 +66,22 @@ Brian Perkins bperkins@netspace.org
|
||||
Brian R. Smith brian@cygnus.com
|
||||
Bruce Evans bde@runx.oz.au
|
||||
Bruce Jerrick bruce@cse.ogi.edu
|
||||
Bruno Haible haible@ma2s2.mathematik.uni-karlsruhe.de
|
||||
Bruno Haible haible@ilog.fr
|
||||
Bryant Fujimoto fujimoto@denali.chem.washington.edu
|
||||
Burkhard Plache plache@krusty.optimax.ns.ca
|
||||
Calvin Cliff cliff@trifid.astro.ucla.edu
|
||||
Cameron Elliott cam@mvbms.mvbms.com
|
||||
Carl Streeter streeter@cae.wisc.edu
|
||||
Carsten Heyl heyl@nads.de
|
||||
Catrin Urbanneck cur@gppc.de
|
||||
Cesar Romani romani@ifm.uni-hamburg.de
|
||||
Chad Hurwitz churritz@cts.com
|
||||
Chance Reschke creschke@usra.edu
|
||||
Charles Fu ccwf@klab.caltech.edu
|
||||
Charles Lopes Charles.Lopes@infm.ulst.ac.uk
|
||||
Charles M. Hannum mycroft@gnu.ai.mit.edu
|
||||
Charles M. Hannum mycroft@gnu.org
|
||||
Chip Salzenberg tct!chip
|
||||
Chris Arthur csa@gnu.ai.mit.edu
|
||||
Chris Arthur csa@gnu.org
|
||||
Chris F.M. Verberne verberne@prl.philips.nl
|
||||
Chris G. Demetriou cgd@sun-lamp.cs.berkeley.edu
|
||||
Chris Hopps sycom.mi.org!ro-chp!chopps
|
||||
@@ -79,10 +89,12 @@ Chris Metcalf metcalf@catfish.lcs.mit.edu
|
||||
Chris Ransom chris@quests.com
|
||||
Christian Callsen Christian.Callsen@eng.sun.com
|
||||
Christian Kirsch ck@held.mind.de
|
||||
Christian Laubscher <christian.laubscher@tiscalinet.ch>
|
||||
Christian T. Dum ctd@mpe-garching.mpg.de
|
||||
Christian von Roques roques@pond.sub.org
|
||||
Christoph Litauer litauer@mailhost.uni-koblenz.de
|
||||
Christophe Colle colle@krtkg1.rug.ac.be
|
||||
Christophe Kalt Christophe.Kalt@kbcfp.com
|
||||
Christopher T. Johnson cjohnson@camelot.com
|
||||
Christopher Vickery vickery@ipc1.cs.qc.edu
|
||||
Claude Scarpelli claude@genethon.fr
|
||||
@@ -96,7 +108,7 @@ Dale R. Worley worley@world.std.com
|
||||
Dale Wiles wiles@geordi.calspan.com
|
||||
Dan Bloch dan@transarc.com
|
||||
Dan Reish dreish@izzy.net
|
||||
Daniel Hagerty hag@gnu.ai.mit.edu
|
||||
Daniel Hagerty hag@gnu.org
|
||||
Daniel Quinlan quinlan@pathname.com
|
||||
Daniel R. Guilderson d.guilderson@ma30.bull.com
|
||||
Daniel S. Barclay daniel@compass-da.com
|
||||
@@ -127,7 +139,7 @@ Dimitri Bougoulias opus@hol.gr
|
||||
Dimitris Fousekis dfousek@leon.nrcps.ariadne-t.gr
|
||||
Dirk Herr-Hoyman hoymand@gate.net
|
||||
Don Bennett dpb@netcom.com
|
||||
Donald B Gordon dbgordon@gnu.ai.mit.edu
|
||||
Donald B Gordon dbgordon@gnu.org
|
||||
Donald H. Locker dhl@spuf1d83.lcp.chrysler.com
|
||||
Douglas Scott doug@foxtrot.ccmrc.ucsb.edu
|
||||
Drew Sullivan drew@sni.ca
|
||||
@@ -152,11 +164,12 @@ 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<EFBFBD>ois Pinard pinard@iro.umontreal.ca
|
||||
Franç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
|
||||
Gerd Knorr kraxel@cs.tu-berlin.de
|
||||
Gerhard Poul gpoul@gnu.org
|
||||
Giorgio Signorini signo@chim.unifi.it
|
||||
Graham Whitted gbw@sgrail.com
|
||||
Grant McDorman grant@isgtec.com
|
||||
@@ -165,9 +178,9 @@ Greg Chung gchung@caip.rutgers.edu
|
||||
Greg Hudson ghudson@mit.edu
|
||||
Greg Maples greg@clari.net
|
||||
Greg McGary gkm@cstone.net
|
||||
G<EFBFBD>ran Uddeborg gvran@uddeborg.pp.se
|
||||
Göran Uddeborg gvran@uddeborg.pp.se
|
||||
Hans Guerth 100664.3101@compuserve.com
|
||||
Harald K<EFBFBD>nig koenig@tat.physik.uni-tuebingen.de
|
||||
Harald Kö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
|
||||
@@ -177,7 +190,7 @@ Hiroyuki Bessho bsh@grotto.iijnet.or.jp
|
||||
Holger Teutsch holger@hotbso.rhein-main.de
|
||||
Hugh Secker-Walker hugh@ear.mit.edu
|
||||
Hunyue Yau hunyue.yau@picksys.com
|
||||
Ian Jackson ijackson@gnu.ai.mit.edu
|
||||
Ian Jackson ijackson@gnu.org
|
||||
Ian Lance Taylor ian@cygnus.com
|
||||
Ian T. Zimmerman itz@crl.com
|
||||
Indra Singhal indra@synoptics.com
|
||||
@@ -196,7 +209,7 @@ Jan Djarv jan.djarv@mbox200.swipnet.se
|
||||
Janice Burton r06a165@bcc25.kodak.com
|
||||
Janne Snabb snabb@niksula.hut.fi
|
||||
Jason R. Mastaler jason@webmaster.net
|
||||
Jay Fenlason hack@gnu.ai.mit.edu
|
||||
Jay Fenlason hack@gnu.org
|
||||
Jean-Michel Soenen soenen@lectra.fr
|
||||
Jean-Ph. Martin-Flatin syj@ecmwf.int
|
||||
Jean-loup Gailly jloup@chorus.fr
|
||||
@@ -238,15 +251,15 @@ 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<EFBFBD>rgen L<EFBFBD>ters jlueters@t-online.de
|
||||
J<EFBFBD>rgen Reiss reiss@psychologie.uni-wuerzburg.de
|
||||
Jürgen Lüters jlueters@t-online.de
|
||||
Jürgen Reiss reiss@psychologie.uni-wuerzburg.de
|
||||
Jyh-Shyang Wang erik@vsp.ee.nctu.edu.tw
|
||||
J<EFBFBD>rg Weule weule@cs.uni-duesseldorf.de
|
||||
J<EFBFBD>rgen H<EFBFBD>gg Jorgen.Hagg@axis.se
|
||||
Jörg Weule weule@cs.uni-duesseldorf.de
|
||||
Jörgen Hägg Jorgen.Hagg@axis.se
|
||||
Kai Petzke wpp@marie.physik.tu-berlin.de
|
||||
Kai Schlichting kai@computel.com
|
||||
Karl Berry karl@cs.umb.edu
|
||||
Karl Heuer kwzh@gnu.ai.mit.edu
|
||||
Karl Heuer kwzh@gnu.org
|
||||
Karl Vogel vogelke@c-17igp.wpafb.af.mil
|
||||
Karlos Z. Smith kazen@viptx.net
|
||||
Karsten Thygesen karthy@kom.auc.dk
|
||||
@@ -268,8 +281,9 @@ Laurent Caillat-Vallet caillat@noe.lyon.cemagref.fr
|
||||
Laurent Sainte-Marthe smarthe@genethon.fr
|
||||
Les Mikesell les@mcs.com
|
||||
Loren J. Rittle rittle@comm.mot.com
|
||||
Lo<EFBFBD>c Prylli Loic.Prylli@lip.ens-lyon.fr
|
||||
Loïc Prylli Loic.Prylli@lip.ens-lyon.fr
|
||||
Luke Mewburn lukem@connect.com.au
|
||||
Machael Stone mstone@cs.loyola.edu
|
||||
Manfred Weichel Manfred.Weichel@mch.sni.de
|
||||
Manuel Munier Manuel.Munier@loria.fr
|
||||
Marc Boucher marc@cam.org
|
||||
@@ -283,7 +297,7 @@ Mark Kollert Mark.Kollert@oi42.kwu.siemens.de
|
||||
Mark W. Eichin eichin@cygnus.com
|
||||
Markus Kuhn mskuhn@cip.informatik.uni-erlangen.de
|
||||
Martin Bellenberg sunsoft@ifm.uni-hamburg.de
|
||||
Martin Goik goma0002@fh-karlsruhe.de
|
||||
Martin Goik goik@HDM-Stuttgart.de
|
||||
Martin Mares mj@k332.feld.cvut.cz
|
||||
Marty Leisner leisner@eso.mc.xerox.com
|
||||
Massimo Dal Zotto dz@cs.unitn.it
|
||||
@@ -293,7 +307,8 @@ Matthew J. D'Errico doc@deathstar.lis.cch.com
|
||||
Matti Aarnio mea@utu.fi
|
||||
Max Hailperin max@nic.gac.edu
|
||||
Maxime Taksar mmt@redbrick.com
|
||||
Melissa Weisshaus melissa@gnu.ai.mit.edu
|
||||
Melissa O'Neill oneill@cs.sfu.ca
|
||||
Melissa Weisshaus melissa@gnu.org
|
||||
Michael Dietrich mdt@is.in-berlin.de
|
||||
Michael Ellis bosun@aquarius.seaoar.uvic.ca
|
||||
Michael Giddings giddings@whitewater.chem.wisc.edu
|
||||
@@ -317,11 +332,12 @@ Mike Walker M.D.Walker@larc.nasa.gov
|
||||
Milan Hodoscek milan@kihp6.ki.si
|
||||
Minh Tran-Le tranle@intellicorp.com
|
||||
Mitsuaki Masuhara masuhara@mcprv.mec.mei.co.jp
|
||||
Nate Eldredge nate@cs.hmc.edu
|
||||
Neil Faulks neil@dcs.kcl.ac.uk
|
||||
Neil Jerram nj104@cus.cam.ac.uk
|
||||
Nelson H.F. Beebe beebe@math.utah.edu
|
||||
Nick Barron nikb@cix.compulink.co.uk
|
||||
Noah Friedman friedman@prep.ai.mit.edu
|
||||
Noah Friedman friedman@gnu.org
|
||||
Noel Cragg noel@red-bean.com
|
||||
Norbert Kiesel norbert@rwthi3.informatik.rwth-aachen.de
|
||||
Olaf Schlueter olaf@toppoint.de
|
||||
@@ -354,7 +370,7 @@ Piercarlo Grandi piercarl@sabi.demon.co.uk
|
||||
Pierce Cantrell cantrell@ee.tamu.edu
|
||||
R. Kent Dybvig dyb@cadence.bloomington.in.us
|
||||
R. Scott Butler butler@prism.es.dupont.com
|
||||
Rainer Orth ro@thp.uni-koeln.de
|
||||
Rainer Orth ro@TechFak.Uni-Bielefeld.DE
|
||||
Ralf Suckow suckow@contrib.de
|
||||
Ralph Schleicher rs@purple.ul.bawue.de
|
||||
Randy Bias randyb@edge.edge.net
|
||||
@@ -363,11 +379,11 @@ Reuben J. Ravago reuben@asti.dost.gov.ph
|
||||
Reuben Sumner rasumner@undergrad.math.uwaterloo.ca
|
||||
Ricardo Marek ricky@ornet.co.il
|
||||
Richard Deal deal@xi.cs.fsu.edu
|
||||
Richard J. Kettlewell richard@elmail.co.uk
|
||||
Richard J. Kettlewell rjk@greenend.org.uk
|
||||
Richard Lloyd R.K.Lloyd@csc.liv.ac.uk
|
||||
Richard O'Neill richard@nexus.vnus.bc.ca
|
||||
Richard Sims rbs@acs.bu.edu
|
||||
Richard Stallman rms@gnu.ai.mit.edu
|
||||
Richard Stallman rms@gnu.org
|
||||
Richard Westerik richardw@bssi.nl
|
||||
Rick Emerson rick@ssg.com
|
||||
Rob Parry rparry@hydrolab.arsusda.gov
|
||||
@@ -386,7 +402,7 @@ Rod Buchanan rod.buchanan@kratos.co.uk
|
||||
Rod Thompson rodt@synopsys.com
|
||||
Roderich Schupp roderich@syntec.m.eunet.de
|
||||
Rodney Brown RBrown@cocam.com.au
|
||||
Roland McGrath roland@gnu.ai.mit.edu
|
||||
Roland McGrath roland@gnu.org
|
||||
Roland Schemers III schemers@vela.acs.oakland.edu
|
||||
Rolf Niepraschk niepraschk@chbrb.berlin.ptb.de
|
||||
Roman Gollent roman@portal.stwing.upenn.edu
|
||||
@@ -411,8 +427,9 @@ Seth Robertson seth@ctr.columbia.edu
|
||||
Sherwood Botsford sherwood@space.ualberta.ca
|
||||
Simon Wright simon.j.wright@gecm.com
|
||||
Sisira Jayasinghe sisira.jayasinghe@sdrc.com
|
||||
Skip Montanaro skip@automatrix.com
|
||||
Skip Montanaro skip@mojam.com http://www.musi-cal.com/~skip/
|
||||
Simon Wright simon@pogner.demon.co.uk
|
||||
Solar Designer solar@openwall.com
|
||||
Stefan Skoglund sp2stes1@ida.his.se
|
||||
Steffen Stempel stempel@ira.uka.de
|
||||
Stephen Gildea gildea@intouchsys.com
|
||||
@@ -421,12 +438,12 @@ Stephen Saroff saroff@msc.edu
|
||||
Stuart Kemp skemp@bmc.com
|
||||
Stuart Poulin stuart@indsys.com
|
||||
Sven Verdoolaege skimo@breughel.ufsia.ac.be
|
||||
Sylvain ROUGIER un@grolier.fr
|
||||
Sylvain Rougier un@grolier.fr
|
||||
Tarang Kumar Patel mombasa@ptolemy.arc.nasa.gov
|
||||
Ted Rule Ted_Rule@flextech.co.uk
|
||||
The King elvis@gnu.ai.mit.edu
|
||||
Thomas Bushnell n/BSG thomas@gnu.ai.mit.edu
|
||||
Thomas K<EFBFBD>nig Thomas.Koenig@ciw.uni-karlsruhe.de
|
||||
The King elvis@gnu.org
|
||||
Thomas Bushnell n/BSG thomas@gnu.org
|
||||
Thomas Kö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
|
||||
@@ -449,28 +466,34 @@ Tom Tromey tromey@drip.colorado.edu
|
||||
Tor Lillqvist tml@hemuli.tte.vtt.fi
|
||||
Torbjorn Granlund tege@sics.se
|
||||
Torkel Hasle torkel@bibsyst.no
|
||||
Torsten Lull tlupi@gppc.de
|
||||
Toshiaki Nishi toshi@sss.osa.sharp.co.jp
|
||||
Travis L. Priest T.L.Priest@larc.nasa.gov
|
||||
Troy Rudolph rudtr01@cai.com
|
||||
Tsutomu Yamada tsutomu@sra.co.jp
|
||||
Ulrich Drepper drepper@gnu.ai.mit.edu
|
||||
Ulrich Drepper drepper@gnu.org
|
||||
Van Snyder vsnyder@math.jpl.nasa.gov
|
||||
Vic Abell abe@cc.purdue.edu
|
||||
Victor J. Griswold vgris@aironet.com
|
||||
Ville Herva v@iki.fi
|
||||
Vince Del Vecchio vdelvecc@inmet.com
|
||||
W. Phillip Moore wpm@morgan.com
|
||||
Warner Losh imp@boulder.parcplace.com
|
||||
Warren Dodge warrend@sptekwv3.wv.tek.com
|
||||
Wayne Christopher wayne@icemcfd.com
|
||||
Werner Almesberger werner.almesberger@lrc.di.epfl.ch
|
||||
William Bader wbader@pluto.csee.lehigh.edu
|
||||
William Bader william@nscs.fast.net
|
||||
William J. Eaton wje@hoffman.rstnu.bcm.tmc.edu
|
||||
William Kucharski kucharsk@netcom.com
|
||||
Wlodzimierz Jan Martin wjm@pg.gda.pl
|
||||
Włodzimierz Jan Martin wjm@pg.gda.pl
|
||||
Wojciech Polak polak@gnu.org
|
||||
Wolfgang Rupprecht wolfgang@wsrcc.com
|
||||
Wolfram Gloger Wolfram.Gloger@dent.med.uni-muenchen.de
|
||||
Wolfram Wagner ww@mpi-sb.mpg.de
|
||||
Yasushi Suzudo ysuzudo@mail.asiandevbank.org
|
||||
Yasushi Suzudo SGR00413@niftyserve.or.jp
|
||||
Yu-Min Liang min@taz.ho.att.com
|
||||
maximum entropy entropy@zippy.bernstein.com
|
||||
|
||||
|
||||
;;;; Local variables:
|
||||
;;;; mode: Fundamental
|
||||
;;;; buffer-file-coding-system: utf-8
|
||||
;;;; End:
|
||||
|
||||
79
TODO
79
TODO
@@ -1,5 +1,76 @@
|
||||
From: Roesinger Eric <ROESINGE@tce.com>
|
||||
Date: Sat, 28 Jul 2001 18:43:43 -0500
|
||||
Suggestions for improving GNU tar.
|
||||
|
||||
It would be useful to be able to use '--remove-files' with '--diff',
|
||||
to remove all files that compare successfully, when verifying a backup.
|
||||
* Incorporate fixes from major distributions, e.g., Debian GNU/Linux.
|
||||
|
||||
* Add support for GNU private keywords in POSIX 1003.1-2001 headers,
|
||||
so that the GNU extensions (--sparse, --incremental, --label and
|
||||
--multi-volume) may be used with POSIX archives.
|
||||
|
||||
* Add support for a 'pax' command that conforms to POSIX 1003.1-2001.
|
||||
This would unify paxutils with tar.
|
||||
|
||||
* Remove command-line incompatibilities between GNU tar and UNIX tar
|
||||
as specified by UNIX98. The main problem is:
|
||||
|
||||
l GNU tar doesn't cross filesystem boundaries.
|
||||
UNIX98 tar warns if all links cannot be resolved.
|
||||
(GNU tar --check-links option)
|
||||
|
||||
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.
|
||||
|
||||
* Interoperate better with Joerg Schilling's star implementation.
|
||||
|
||||
* Add an option to remove files that compare successfully.
|
||||
|
||||
From: Roesinger Eric <ROESINGE@tce.com>
|
||||
Date: Sat, 28 Jul 2001 18:43:43 -0500
|
||||
|
||||
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.
|
||||
|
||||
* Consider this:
|
||||
|
||||
From: Dennis Pund
|
||||
Subject: TAR suggestion...
|
||||
Date: Wed, 1 May 2002 18:26:36 -0500 (EST)
|
||||
|
||||
What I would like to do is:
|
||||
|
||||
foo my.tar.gz | tar -xzOf - | tar -cMf - -L 650000 - | bar
|
||||
|
||||
where 'foo' is a program that retrieves the archive and streams it
|
||||
to stdout and bar is a program that streams the stdin to CDR.
|
||||
|
||||
(http://mail.gnu.org/archive/html/bug-gnu-utils/2002-05/msg00022.html)
|
||||
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright (C) 2003 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 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: "[ ]*$"
|
||||
end:
|
||||
|
||||
217
bootstrap
Executable file
217
bootstrap
Executable file
@@ -0,0 +1,217 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Bootstrap 'tar' from CVS.
|
||||
|
||||
# Copyright (C) 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.
|
||||
|
||||
# Written by Paul Eggert.
|
||||
|
||||
# URL of our text domain page in Translation Project
|
||||
TP_URL="http://www2.iro.umontreal.ca/~gnutra/po/maint/tar/"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
usage: $0 [--gnulib-srcdir=DIR][--cvs-auth=AUTH-METHOD][--cvs-user=USERNAME][--no-po]
|
||||
Options are:
|
||||
--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.
|
||||
--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.
|
||||
|
||||
Running without arguments will suffice in most cases. It is equivalent
|
||||
to
|
||||
|
||||
./bootstrap --cvs-auth=ext --cvs-user=anoncvs
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse options.
|
||||
|
||||
DOWNLOAD_PO=yes
|
||||
for option
|
||||
do
|
||||
case $option in
|
||||
--help)
|
||||
usage
|
||||
exit;;
|
||||
--gnulib-srcdir=*)
|
||||
GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;;
|
||||
--cvs-auth=*)
|
||||
CVS_AUTH=`expr "$option" : '--cvs-auth=\(.*\)'`;;
|
||||
--cvs-user=*)
|
||||
CVS_USER=`expr "$option" : '--cvs-user=\(.*\)'`;;
|
||||
--no-po)
|
||||
DOWNLOAD_PO=no;;
|
||||
*)
|
||||
echo >&2 "$0: $option: unknown option"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "$0: Bootstrapping CVS tar..."
|
||||
|
||||
build_cvs_prefix() {
|
||||
CVS_PREFIX=:${1}:
|
||||
if [ "${2}" != - ]; then
|
||||
CVS_PREFIX=${CVS_PREFIX}${2}@
|
||||
fi
|
||||
if [ "$1" = "ext" ]; then
|
||||
if [ -z "${CVS_RSH}" ]; then
|
||||
CVS_RSH=ssh
|
||||
export CVS_RSH
|
||||
fi
|
||||
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
|
||||
esac
|
||||
|
||||
<$GNULIB_SRCDIR/gnulib-tool || exit
|
||||
|
||||
gnulib_modules='
|
||||
alloca
|
||||
argmatch
|
||||
backupfile
|
||||
dirname
|
||||
error
|
||||
exclude
|
||||
fileblocks
|
||||
fnmatch-gnu
|
||||
ftruncate
|
||||
full-write
|
||||
getdate
|
||||
getline
|
||||
getopt
|
||||
gettext
|
||||
hash
|
||||
human
|
||||
lchown
|
||||
memset
|
||||
modechange
|
||||
obstack
|
||||
quote
|
||||
quotearg
|
||||
rmdir
|
||||
safe-read
|
||||
save-cwd
|
||||
savedir
|
||||
stdbool
|
||||
stpcpy
|
||||
strtol
|
||||
strtoul
|
||||
unlocked-io
|
||||
utime
|
||||
xalloc
|
||||
xgetcwd
|
||||
xstrtoumax
|
||||
'
|
||||
|
||||
previous_gnulib_modules=
|
||||
while [ "$gnulib_modules" != "$previous_gnulib_modules" ]; do
|
||||
previous_gnulib_modules=$gnulib_modules
|
||||
gnulib_modules=`
|
||||
(echo "$gnulib_modules"
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-dependencies $gnulib_module
|
||||
done) | sort -u
|
||||
`
|
||||
done
|
||||
|
||||
gnulib_files=`
|
||||
(for gnulib_module in $gnulib_modules; do
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-filelist $gnulib_module
|
||||
done) | sort -u
|
||||
`
|
||||
|
||||
gnulib_dirs=`echo "$gnulib_files" | sed 's,/[^/]*$,,' | sort -u`
|
||||
mkdir -p $gnulib_dirs || exit
|
||||
|
||||
for gnulib_file in $gnulib_files; do
|
||||
dest=$gnulib_file
|
||||
|
||||
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;;
|
||||
esac
|
||||
|
||||
rm -f $dest &&
|
||||
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file" &&
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
|
||||
done
|
||||
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
# Reconfigure, getting other files.
|
||||
|
||||
echo "$0: autoreconf --verbose --install --force ..."
|
||||
autoreconf --verbose --install --force
|
||||
|
||||
|
||||
echo "$0: done. Now you can run './configure'."
|
||||
333
configure.ac
333
configure.ac
@@ -1,47 +1,47 @@
|
||||
# Configure template for GNU tar.
|
||||
# Copyright (C) 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(src/tar.c)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.12)
|
||||
AM_INIT_AUTOMAKE(tar, 1.12)
|
||||
AC_DEFINE(_GNU_SOURCE)
|
||||
ALL_LINGUAS="de fr it ko nl no pl pt sl sv"
|
||||
# Copyright (C) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
fp_PROG_ECHO
|
||||
test $fp_cv_prog_echo_nonl = no \
|
||||
&& echo 2>&1 "WARNING: \`echo' not powerful enough for \`make check'"
|
||||
# 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.
|
||||
|
||||
AC_INIT([GNU tar], [1.13.93], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([config])
|
||||
AC_CONFIG_HEADERS([config.h:config.hin])
|
||||
AC_PREREQ([2.59])
|
||||
AM_INIT_AUTOMAKE([1.8 gnits dist-bzip2 dist-shar std-options])
|
||||
|
||||
gl_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_AIX
|
||||
AC_MINIX
|
||||
AC_EXEEXT
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_YACC
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_ISC_POSIX
|
||||
AM_C_PROTOTYPES
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_CHECK_SIZEOF(unsigned long, 4)
|
||||
AC_CHECK_SIZEOF(long long, 0)
|
||||
|
||||
AC_CHECK_HEADERS(fcntl.h limits.h linux/fd.h memory.h net/errno.h poll.h \
|
||||
sgtty.h string.h stropts.h \
|
||||
sys/buf.h sys/device.h sys/gentape.h sys/inet.h sys/io/trioctl.h sys/ioccom.h \
|
||||
sys/mtio.h sys/param.h sys/tprintf.h sys/tape.h sys/time.h sys/timeb.h \
|
||||
sys/wait.h unistd.h)
|
||||
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/inet.h sys/io/trioctl.h \
|
||||
sys/mtio.h sys/tprintf.h sys/tape.h \
|
||||
unistd.h)
|
||||
|
||||
# It seems that that many machines where <utime.h> seems to be
|
||||
# broken just require something like -D_XXX_SOURCE, where XXX might
|
||||
# be POSIX, POSIX_C, ALL, HPUX or whatever, depending on the machine.
|
||||
|
||||
AC_CACHE_CHECK(for utime.h, tar_cv_header_utime_h,
|
||||
[AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utime.h>], [struct utimbuf foo],
|
||||
tar_cv_header_utime_h=yes, tar_cv_header_utime_h=no)])
|
||||
test $tar_cv_header_utime_h = yes && AC_DEFINE(HAVE_UTIME_H)
|
||||
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,
|
||||
@@ -51,103 +51,140 @@ if test $ac_cv_header_sys_mtio_h = yes; then
|
||||
#endif
|
||||
#include <sys/socket.h>],
|
||||
tar_cv_header_rmt=yes, tar_cv_header_rmt=no)])
|
||||
test $tar_cv_header_rmt = yes && RMT=rmt
|
||||
test $tar_cv_header_rmt = yes && RMT='rmt$(EXEEXT)'
|
||||
AC_SUBST(RMT)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(for getgrgid declaration, tar_cv_header_getgrgid,
|
||||
[AC_EGREP_HEADER(getgrgid, grp.h,
|
||||
tar_cv_header_getgrgid=yes, tar_cv_header_getgrgid=no)])
|
||||
test $tar_cv_header_getgrgid = yes && AC_DEFINE(HAVE_GETGRGID)
|
||||
|
||||
AC_CACHE_CHECK(for getpwuid declaration, tar_cv_header_getpwuid,
|
||||
[AC_EGREP_HEADER(getpwuid, pwd.h,
|
||||
tar_cv_header_getpwuid=yes, tar_cv_header_getpwuid=no)])
|
||||
test $tar_cv_header_getpwuid = yes && AC_DEFINE(HAVE_GETPWUID)
|
||||
|
||||
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)
|
||||
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
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_ST_BLKSIZE
|
||||
AC_STRUCT_ST_BLOCKS
|
||||
AC_MSG_CHECKING([for st_fstype string in struct stat])
|
||||
AC_CACHE_VAL(diff_cv_st_fstype_string,
|
||||
[AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <sys/stat.h>], [struct stat s; s.st_fstype[0] = 'x';],
|
||||
diff_cv_st_fstype_string=yes,
|
||||
diff_cv_st_fstype_string=no)])
|
||||
AC_MSG_RESULT($diff_cv_st_fstype_string)
|
||||
if test $diff_cv_st_fstype_string = yes; then
|
||||
AC_DEFINE(HAVE_ST_FSTYPE_STRING, 1,
|
||||
[Define if struct stat has a char st_fstype[] member.])
|
||||
fi
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_UID_T
|
||||
AC_CHECK_TYPE(major_t, , AC_DEFINE(major_t, int,
|
||||
[Type of major device numbers.]))
|
||||
AC_CHECK_TYPE(minor_t, , AC_DEFINE(minor_t, int,
|
||||
[Type of minor device numbers.]))
|
||||
AC_CHECK_TYPE(dev_t, unsigned)
|
||||
AC_CHECK_TYPE(ino_t, unsigned)
|
||||
|
||||
AC_CHECK_FUNCS(fsync ftime getcwd isascii lchown mkfifo nap napms poll \
|
||||
select strerror strstr usleep)
|
||||
gt_TYPE_SSIZE_T
|
||||
jm_AC_TYPE_UINTMAX_T
|
||||
|
||||
AC_CACHE_CHECK(for mknod, tar_cv_func_mknod,
|
||||
[AC_TRY_LINK([
|
||||
|
||||
# gnulib modules
|
||||
|
||||
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>],
|
||||
[mknod (0, 0, 0)],
|
||||
tar_cv_func_mknod=yes, tar_cv_func_mknod=no)])
|
||||
test $tar_cv_func_mknod = yes && AC_DEFINE(HAVE_MKNOD)
|
||||
#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.
|
||||
|
||||
# Whenever both -lsocket and -lnsl are needed, it seems to be always the
|
||||
# case that gethostbyname requires -lnsl. So, check -lnsl first, for it
|
||||
# to be in LIBS before the setsockopt checks are performed. *However*,
|
||||
# on SINIX-N 5.43, this is false, and gethostent seems to be a better
|
||||
# candidate. So, let's use it below instead of gethostbyname, and see.
|
||||
# Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
|
||||
# Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
|
||||
tar_save_LIBS=$LIBS
|
||||
LIB_CLOCK_GETTIME=
|
||||
AC_SEARCH_LIBS(clock_gettime, [rt posix4])
|
||||
case "$ac_cv_search_clock_gettime" in
|
||||
-l*) LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime;;
|
||||
esac
|
||||
AC_SUBST(LIB_CLOCK_GETTIME)
|
||||
AC_CHECK_FUNCS(clock_gettime)
|
||||
LIBS=$tar_save_LIBS
|
||||
|
||||
AC_CHECK_FUNC(gethostent)
|
||||
if test $ac_cv_func_gethostent = no; then
|
||||
AC_CHECK_LIB(nsl, gethostent)
|
||||
fi
|
||||
AC_CHECK_FUNC(setsockopt)
|
||||
if test $ac_cv_func_setsockopt = no; then
|
||||
AC_CHECK_LIB(socket, setsockopt)
|
||||
fi
|
||||
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_FUNC_ALLOCA
|
||||
AC_FUNC_FNMATCH
|
||||
test $ac_cv_func_fnmatch_works = yes || LIBOBJS="$LIBOBJS fnmatch.o"
|
||||
AC_FUNC_VPRINTF
|
||||
AC_REPLACE_FUNCS(basename dirname execlp ftruncate memset mkdir rename rmdir)
|
||||
test "$ac_cv_func_strstr" = yes || LIBOBJS="$LIBOBJS strstr.o"
|
||||
# Set LIB_SETSOCKOPT to -lnsl -lsocket if necessary.
|
||||
tar_save_LIBS=$LIBS
|
||||
LIB_SETSOCKOPT=
|
||||
AC_SEARCH_LIBS(setsockopt, [socket], ,
|
||||
[AC_SEARCH_LIBS(setsockopt, [socket], , , [-lnsl])])
|
||||
AC_SEARCH_LIBS(setsockopt, [nsl])
|
||||
|
||||
# The 3-argument open happens to go along with the O_* defines, which
|
||||
# are easier to check for.
|
||||
case "$ac_cv_search_setsockopt" in
|
||||
-l*) LIB_SETSOCKOPT=$ac_cv_search_setsockopt
|
||||
esac
|
||||
AC_SUBST(LIB_SETSOCKOPT)
|
||||
LIBS=$tar_save_LIBS
|
||||
|
||||
AC_CACHE_CHECK(for 3-argument open, tar_cv_func_open3,
|
||||
[AC_TRY_COMPILE([
|
||||
#if HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#else
|
||||
# include <sys/file.h>
|
||||
#endif],
|
||||
[int x = O_RDONLY],
|
||||
tar_cv_func_open3=yes, tar_cv_func_open3=no)])
|
||||
if test $tar_cv_func_open3 = no; then
|
||||
AC_DEFINE(EMUL_OPEN3)
|
||||
fi
|
||||
|
||||
# `union wait' is preferrably avoided. We merely assume below
|
||||
# that if `int pid;' fails, `union wait pid;' would have worked.
|
||||
# Directly trying `union wait pid;' is seeking for trouble, as
|
||||
# some POSIX systems are offering compatibility hacks generating
|
||||
# ugly diagnostics. Also, on some systems, WEXITSTATUS exists,
|
||||
# but fails when called on `union wait' variables.
|
||||
|
||||
AC_CACHE_CHECK(for union wait, tar_cv_header_union_wait,
|
||||
[AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#if HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif],
|
||||
[int status; int pid; pid = wait (&status);],
|
||||
tar_cv_header_union_wait=no, tar_cv_header_union_wait=yes)])
|
||||
test $tar_cv_header_union_wait = yes && AC_DEFINE(HAVE_UNION_WAIT)
|
||||
AC_REPLACE_FUNCS(waitpid)
|
||||
|
||||
AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
|
||||
[if test -n "$RSH"; then
|
||||
@@ -155,20 +192,41 @@ AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
|
||||
else
|
||||
tar_cv_path_RSH=no
|
||||
for ac_file in /usr/ucb/rsh /usr/bin/remsh /usr/bin/rsh /usr/bsd/rsh \
|
||||
/usr/bin/nsh /usr/bin/rcmd
|
||||
/usr/bin/nsh /usr/bin/rcmd
|
||||
do
|
||||
# Prefer a non-symlink rsh to a symlink one, so that binaries built
|
||||
# on AIX 4.1.4, where /usr/ucb/rsh is a symlink to /usr/bin/rsh
|
||||
# will run on AIX 4.3.0, which has only /usr/bin/rsh.
|
||||
if test -f $ac_file; then
|
||||
tar_cv_path_RSH=$ac_file
|
||||
break
|
||||
if (test -h $ac_file) 2>/dev/null; then
|
||||
test $tar_cv_path_RSH = no && tar_cv_path_RSH=$ac_file
|
||||
else
|
||||
tar_cv_path_RSH=$ac_file
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
if test $tar_cv_path_RSH = no; then
|
||||
AC_CHECK_HEADERS(netdb.h)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(REMOTE_SHELL, "$tar_cv_path_RSH")
|
||||
AC_DEFINE_UNQUOTED(REMOTE_SHELL, "$tar_cv_path_RSH",
|
||||
[Define to the full path of your rsh, if any.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for default archive format)
|
||||
|
||||
if test -z "$DEFAULT_ARCHIVE_FORMAT"; then
|
||||
DEFAULT_ARCHIVE_FORMAT="GNU"
|
||||
fi
|
||||
case $DEFAULT_ARCHIVE_FORMAT in
|
||||
V7|OLDGNU|USTAR|POSIX|GNU) ;;
|
||||
*) AC_MSG_ERROR(Invalid format name);;
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE_FORMAT, ${DEFAULT_ARCHIVE_FORMAT}_FORMAT,
|
||||
[By default produce archives of this format])
|
||||
AC_MSG_RESULT($DEFAULT_ARCHIVE_FORMAT)
|
||||
|
||||
AC_MSG_CHECKING(for default archive)
|
||||
|
||||
if test -z "$DEFAULT_ARCHIVE"; then
|
||||
@@ -181,35 +239,54 @@ else
|
||||
# FIXME: Let DEVICE_PREFIX be configured from the environment.
|
||||
# FIXME: Rearrange, here.
|
||||
case $DEFAULT_ARCHIVE in
|
||||
changequote(, )dnl
|
||||
*[0-7][lmh])
|
||||
*[[0-7][lmh]])
|
||||
AC_DEFINE(DENSITY_LETTER, 1,
|
||||
[[Define to 1 if density may be indicated by [lmh] at end of device.]])
|
||||
device_prefix=`echo $DEFAULT_ARCHIVE | sed 's/[0-7][lmh]$//'`
|
||||
changequote([, ])dnl
|
||||
AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix")
|
||||
AC_DEFINE(DENSITY_LETTER)
|
||||
;;
|
||||
changequote(, )dnl
|
||||
*[0-7])
|
||||
*[[0-7]])
|
||||
device_prefix=`echo $DEFAULT_ARCHIVE | sed 's/[0-7]$//'`
|
||||
changequote([, ])dnl
|
||||
AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix")
|
||||
;;
|
||||
*)
|
||||
device_prefix=
|
||||
;;
|
||||
esac
|
||||
case "$device_prefix" in
|
||||
?*)
|
||||
AC_DEFINE_UNQUOTED(DEVICE_PREFIX, "$device_prefix",
|
||||
[Define to a string giving the prefix of the default device, without the part specifying the unit and density.])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE, "$DEFAULT_ARCHIVE")
|
||||
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_MSG_CHECKING(for default blocking)
|
||||
DEFAULT_BLOCKING=${DEFAULT_BLOCKING-20}
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING,
|
||||
[Define to a number giving the default blocking size for archives.])
|
||||
AC_MSG_RESULT($DEFAULT_BLOCKING)
|
||||
|
||||
fp_WITH_INCLUDED_MALLOC
|
||||
AM_WITH_DMALLOC
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-ngettext])
|
||||
AM_GNU_GETTEXT_VERSION(0.12.1)
|
||||
|
||||
AM_GNU_GETTEXT
|
||||
AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
|
||||
# Iconv
|
||||
AC_CHECK_HEADERS(iconv.h,
|
||||
[AC_CHECK_TYPE(iconv_t,:,
|
||||
AC_DEFINE(iconv_t, int,
|
||||
[Conversion descriptor type]),
|
||||
[#include <iconv.h>])])
|
||||
|
||||
AC_OUTPUT([Makefile doc/Makefile intl/Makefile lib/Makefile po/Makefile.in \
|
||||
scripts/Makefile src/Makefile tests/Makefile tests/preset],
|
||||
[sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile])
|
||||
AC_CHECK_LIB(iconv, iconv)
|
||||
|
||||
|
||||
AC_OUTPUT([Makefile\
|
||||
doc/Makefile\
|
||||
lib/Makefile\
|
||||
po/Makefile.in\
|
||||
scripts/Makefile\
|
||||
src/Makefile\
|
||||
tests/Makefile\
|
||||
tests/preset])
|
||||
|
||||
28
doc/.cvsignore
Normal file
28
doc/.cvsignore
Normal file
@@ -0,0 +1,28 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
header.texi
|
||||
tar.info
|
||||
version.texi
|
||||
stamp-vti
|
||||
tar.html
|
||||
tar.log
|
||||
tar.dvi
|
||||
tar.aux
|
||||
tar.toc
|
||||
tar.cp
|
||||
tar.fn
|
||||
tar.vr
|
||||
tar.tp
|
||||
tar.ky
|
||||
tar.pg
|
||||
tar.ps
|
||||
tar.cps
|
||||
tar.fns
|
||||
tar.pgs
|
||||
tar.vrs
|
||||
tar.at
|
||||
tar.kw
|
||||
tar.ex
|
||||
tar.ats
|
||||
tar.exs
|
||||
tar.kws
|
||||
@@ -1,24 +1,25 @@
|
||||
# Makefile for GNU tar documentation.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997 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.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
## This 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.
|
||||
|
||||
# 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.
|
||||
## 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.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits
|
||||
info_TEXINFOS = tar.texi
|
||||
|
||||
EXTRA_DIST = convtexi.pl getdate.texi header.texi
|
||||
EXTRA_DIST = convtexi.pl fdl.texi freemanuals.texi getdate.texi header.texi
|
||||
|
||||
CLEANFILES = tmp-*
|
||||
|
||||
@@ -26,16 +27,11 @@ CLEANFILES = tmp-*
|
||||
# Just call `make dvi RENDITION=PROOF' if you want PROOF rendition.
|
||||
RENDITION = DISTRIB
|
||||
|
||||
tar.info: tar.texi getdate.texi header.texi version.texi
|
||||
@echo "WARNING: \`makeinfo' will not preprocess Texinfo input properly"
|
||||
@echo " for expanding Texinfo macros, if it comes from a"
|
||||
@echo " Texinfo distribution which is earlier than version 3.7."
|
||||
cd $(srcdir) && $(MAKEINFO) -D$(RENDITION) tar.texi
|
||||
$(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 header.texi version.texi
|
||||
@echo "WARNING: \`makeinfo' will not preprocess Texinfo input properly"
|
||||
@echo " for expanding Texinfo macros, if it comes from a"
|
||||
@echo " Texinfo distribution which is earlier than version 3.7."
|
||||
tar.dvi: 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*
|
||||
@@ -45,9 +41,11 @@ tar.dvi: tar.texi getdate.texi 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
|
||||
TEXINPUTS=$(srcdir):$$TEXINPUTS $(TEXI2DVI) tmp-tar.texi
|
||||
TEXINPUTS=$(top_srcdir)/config:$$TEXINPUTS \
|
||||
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
|
||||
$(TEXI2DVI) tmp-tar.texi
|
||||
mv tmp-tar.dvi $@
|
||||
|
||||
header.texi: $(top_srcdir)/src/tar.h
|
||||
$(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' > $(srcdir)/header.texi
|
||||
| expand | sed 's/\([{}]\)/@\1/g' >$@
|
||||
|
||||
@@ -3,8 +3,24 @@ eval "exec /usr/local/bin/perl -S $0 $*"
|
||||
if 0;
|
||||
|
||||
# Copy a Texinfo file, replacing @value's, @FIXME's and other gooddies.
|
||||
# Copyright <20> 1996 Free Software Foundation, Inc.
|
||||
# Fran<EFBFBD>ois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# Copyright (C) 1996, 2001 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# François Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
$_ = <>;
|
||||
while ($_)
|
||||
|
||||
452
doc/fdl.texi
Normal file
452
doc/fdl.texi
Normal file
@@ -0,0 +1,452 @@
|
||||
|
||||
@node GNU Free Documentation License
|
||||
@appendixsec GNU Free Documentation License
|
||||
|
||||
@cindex FDL, GNU Free Documentation License
|
||||
@center Version 1.2, November 2002
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
@end display
|
||||
|
||||
@enumerate 0
|
||||
@item
|
||||
PREAMBLE
|
||||
|
||||
The purpose of this License is to make a manual, textbook, or other
|
||||
functional and useful document @dfn{free} in the sense of freedom: to
|
||||
assure everyone the effective freedom to copy and redistribute it,
|
||||
with or without modifying it, either commercially or noncommercially.
|
||||
Secondarily, this License preserves for the author and publisher a way
|
||||
to get credit for their work, while not being considered responsible
|
||||
for modifications made by others.
|
||||
|
||||
This License is a kind of ``copyleft'', which means that derivative
|
||||
works of the document must themselves be free in the same sense. It
|
||||
complements the GNU General Public License, which is a copyleft
|
||||
license designed for free software.
|
||||
|
||||
We have designed this License in order to use it for manuals for free
|
||||
software, because free software needs free documentation: a free
|
||||
program should come with manuals providing the same freedoms that the
|
||||
software does. But this License is not limited to software manuals;
|
||||
it can be used for any textual work, regardless of subject matter or
|
||||
whether it is published as a printed book. We recommend this License
|
||||
principally for works whose purpose is instruction or reference.
|
||||
|
||||
@item
|
||||
APPLICABILITY AND DEFINITIONS
|
||||
|
||||
This License applies to any manual or other work, in any medium, that
|
||||
contains a notice placed by the copyright holder saying it can be
|
||||
distributed under the terms of this License. Such a notice grants a
|
||||
world-wide, royalty-free license, unlimited in duration, to use that
|
||||
work under the conditions stated herein. The ``Document'', below,
|
||||
refers to any such manual or work. Any member of the public is a
|
||||
licensee, and is addressed as ``you''. You accept the license if you
|
||||
copy, modify or distribute the work in a way requiring permission
|
||||
under copyright law.
|
||||
|
||||
A ``Modified Version'' of the Document means any work containing the
|
||||
Document or a portion of it, either copied verbatim, or with
|
||||
modifications and/or translated into another language.
|
||||
|
||||
A ``Secondary Section'' is a named appendix or a front-matter section
|
||||
of the Document that deals exclusively with the relationship of the
|
||||
publishers or authors of the Document to the Document's overall
|
||||
subject (or to related matters) and contains nothing that could fall
|
||||
directly within that overall subject. (Thus, if the Document is in
|
||||
part a textbook of mathematics, a Secondary Section may not explain
|
||||
any mathematics.) The relationship could be a matter of historical
|
||||
connection with the subject or with related matters, or of legal,
|
||||
commercial, philosophical, ethical or political position regarding
|
||||
them.
|
||||
|
||||
The ``Invariant Sections'' are certain Secondary Sections whose titles
|
||||
are designated, as being those of Invariant Sections, in the notice
|
||||
that says that the Document is released under this License. If a
|
||||
section does not fit the above definition of Secondary then it is not
|
||||
allowed to be designated as Invariant. The Document may contain zero
|
||||
Invariant Sections. If the Document does not identify any Invariant
|
||||
Sections then there are none.
|
||||
|
||||
The ``Cover Texts'' are certain short passages of text that are listed,
|
||||
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
|
||||
the Document is released under this License. A Front-Cover Text may
|
||||
be at most 5 words, and a Back-Cover Text may be at most 25 words.
|
||||
|
||||
A ``Transparent'' copy of the Document means a machine-readable copy,
|
||||
represented in a format whose specification is available to the
|
||||
general public, that is suitable for revising the document
|
||||
straightforwardly with generic text editors or (for images composed of
|
||||
pixels) generic paint programs or (for drawings) some widely available
|
||||
drawing editor, and that is suitable for input to text formatters or
|
||||
for automatic translation to a variety of formats suitable for input
|
||||
to text formatters. A copy made in an otherwise Transparent file
|
||||
format whose markup, or absence of markup, has been arranged to thwart
|
||||
or discourage subsequent modification by readers is not Transparent.
|
||||
An image format is not Transparent if used for any substantial amount
|
||||
of text. A copy that is not ``Transparent'' is called ``Opaque''.
|
||||
|
||||
Examples of suitable formats for Transparent copies include plain
|
||||
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
|
||||
format, @acronym{SGML} or @acronym{XML} using a publicly available
|
||||
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
|
||||
PostScript or @acronym{PDF} designed for human modification. Examples
|
||||
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
|
||||
@acronym{JPG}. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, @acronym{SGML} or
|
||||
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
|
||||
not generally available, and the machine-generated @acronym{HTML},
|
||||
PostScript or @acronym{PDF} produced by some word processors for
|
||||
output purposes only.
|
||||
|
||||
The ``Title Page'' means, for a printed book, the title page itself,
|
||||
plus such following pages as are needed to hold, legibly, the material
|
||||
this License requires to appear in the title page. For works in
|
||||
formats which do not have any title page as such, ``Title Page'' means
|
||||
the text near the most prominent appearance of the work's title,
|
||||
preceding the beginning of the body of the text.
|
||||
|
||||
A section ``Entitled XYZ'' means a named subunit of the Document whose
|
||||
title either is precisely XYZ or contains XYZ in parentheses following
|
||||
text that translates XYZ in another language. (Here XYZ stands for a
|
||||
specific section name mentioned below, such as ``Acknowledgements'',
|
||||
``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
|
||||
of such a section when you modify the Document means that it remains a
|
||||
section ``Entitled XYZ'' according to this definition.
|
||||
|
||||
The Document may include Warranty Disclaimers next to the notice which
|
||||
states that this License applies to the Document. These Warranty
|
||||
Disclaimers are considered to be included by reference in this
|
||||
License, but only as regards disclaiming warranties: any other
|
||||
implication that these Warranty Disclaimers may have is void and has
|
||||
no effect on the meaning of this License.
|
||||
|
||||
@item
|
||||
VERBATIM COPYING
|
||||
|
||||
You may copy and distribute the Document in any medium, either
|
||||
commercially or noncommercially, provided that this License, the
|
||||
copyright notices, and the license notice saying this License applies
|
||||
to the Document are reproduced in all copies, and that you add no other
|
||||
conditions whatsoever to those of this License. You may not use
|
||||
technical measures to obstruct or control the reading or further
|
||||
copying of the copies you make or distribute. However, you may accept
|
||||
compensation in exchange for copies. If you distribute a large enough
|
||||
number of copies you must also follow the conditions in section 3.
|
||||
|
||||
You may also lend copies, under the same conditions stated above, and
|
||||
you may publicly display copies.
|
||||
|
||||
@item
|
||||
COPYING IN QUANTITY
|
||||
|
||||
If you publish printed copies (or copies in media that commonly have
|
||||
printed covers) of the Document, numbering more than 100, and the
|
||||
Document's license notice requires Cover Texts, you must enclose the
|
||||
copies in covers that carry, clearly and legibly, all these Cover
|
||||
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
|
||||
the back cover. Both covers must also clearly and legibly identify
|
||||
you as the publisher of these copies. The front cover must present
|
||||
the full title with all words of the title equally prominent and
|
||||
visible. You may add other material on the covers in addition.
|
||||
Copying with changes limited to the covers, as long as they preserve
|
||||
the title of the Document and satisfy these conditions, can be treated
|
||||
as verbatim copying in other respects.
|
||||
|
||||
If the required texts for either cover are too voluminous to fit
|
||||
legibly, you should put the first ones listed (as many as fit
|
||||
reasonably) on the actual cover, and continue the rest onto adjacent
|
||||
pages.
|
||||
|
||||
If you publish or distribute Opaque copies of the Document numbering
|
||||
more than 100, you must either include a machine-readable Transparent
|
||||
copy along with each Opaque copy, or state in or with each Opaque copy
|
||||
a computer-network location from which the general network-using
|
||||
public has access to download using public-standard network protocols
|
||||
a complete Transparent copy of the Document, free of added material.
|
||||
If you use the latter option, you must take reasonably prudent steps,
|
||||
when you begin distribution of Opaque copies in quantity, to ensure
|
||||
that this Transparent copy will remain thus accessible at the stated
|
||||
location until at least one year after the last time you distribute an
|
||||
Opaque copy (directly or through your agents or retailers) of that
|
||||
edition to the public.
|
||||
|
||||
It is requested, but not required, that you contact the authors of the
|
||||
Document well before redistributing any large number of copies, to give
|
||||
them a chance to provide you with an updated version of the Document.
|
||||
|
||||
@item
|
||||
MODIFICATIONS
|
||||
|
||||
You may copy and distribute a Modified Version of the Document under
|
||||
the conditions of sections 2 and 3 above, provided that you release
|
||||
the Modified Version under precisely this License, with the Modified
|
||||
Version filling the role of the Document, thus licensing distribution
|
||||
and modification of the Modified Version to whoever possesses a copy
|
||||
of it. In addition, you must do these things in the Modified Version:
|
||||
|
||||
@enumerate A
|
||||
@item
|
||||
Use in the Title Page (and on the covers, if any) a title distinct
|
||||
from that of the Document, and from those of previous versions
|
||||
(which should, if there were any, be listed in the History section
|
||||
of the Document). You may use the same title as a previous version
|
||||
if the original publisher of that version gives permission.
|
||||
|
||||
@item
|
||||
List on the Title Page, as authors, one or more persons or entities
|
||||
responsible for authorship of the modifications in the Modified
|
||||
Version, together with at least five of the principal authors of the
|
||||
Document (all of its principal authors, if it has fewer than five),
|
||||
unless they release you from this requirement.
|
||||
|
||||
@item
|
||||
State on the Title page the name of the publisher of the
|
||||
Modified Version, as the publisher.
|
||||
|
||||
@item
|
||||
Preserve all the copyright notices of the Document.
|
||||
|
||||
@item
|
||||
Add an appropriate copyright notice for your modifications
|
||||
adjacent to the other copyright notices.
|
||||
|
||||
@item
|
||||
Include, immediately after the copyright notices, a license notice
|
||||
giving the public permission to use the Modified Version under the
|
||||
terms of this License, in the form shown in the Addendum below.
|
||||
|
||||
@item
|
||||
Preserve in that license notice the full lists of Invariant Sections
|
||||
and required Cover Texts given in the Document's license notice.
|
||||
|
||||
@item
|
||||
Include an unaltered copy of this License.
|
||||
|
||||
@item
|
||||
Preserve the section Entitled ``History'', Preserve its Title, and add
|
||||
to it an item stating at least the title, year, new authors, and
|
||||
publisher of the Modified Version as given on the Title Page. If
|
||||
there is no section Entitled ``History'' in the Document, create one
|
||||
stating the title, year, authors, and publisher of the Document as
|
||||
given on its Title Page, then add an item describing the Modified
|
||||
Version as stated in the previous sentence.
|
||||
|
||||
@item
|
||||
Preserve the network location, if any, given in the Document for
|
||||
public access to a Transparent copy of the Document, and likewise
|
||||
the network locations given in the Document for previous versions
|
||||
it was based on. These may be placed in the ``History'' section.
|
||||
You may omit a network location for a work that was published at
|
||||
least four years before the Document itself, or if the original
|
||||
publisher of the version it refers to gives permission.
|
||||
|
||||
@item
|
||||
For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
|
||||
the Title of the section, and preserve in the section all the
|
||||
substance and tone of each of the contributor acknowledgements and/or
|
||||
dedications given therein.
|
||||
|
||||
@item
|
||||
Preserve all the Invariant Sections of the Document,
|
||||
unaltered in their text and in their titles. Section numbers
|
||||
or the equivalent are not considered part of the section titles.
|
||||
|
||||
@item
|
||||
Delete any section Entitled ``Endorsements''. Such a section
|
||||
may not be included in the Modified Version.
|
||||
|
||||
@item
|
||||
Do not retitle any existing section to be Entitled ``Endorsements'' or
|
||||
to conflict in title with any Invariant Section.
|
||||
|
||||
@item
|
||||
Preserve any Warranty Disclaimers.
|
||||
@end enumerate
|
||||
|
||||
If the Modified Version includes new front-matter sections or
|
||||
appendices that qualify as Secondary Sections and contain no material
|
||||
copied from the Document, you may at your option designate some or all
|
||||
of these sections as invariant. To do this, add their titles to the
|
||||
list of Invariant Sections in the Modified Version's license notice.
|
||||
These titles must be distinct from any other section titles.
|
||||
|
||||
You may add a section Entitled ``Endorsements'', provided it contains
|
||||
nothing but endorsements of your Modified Version by various
|
||||
parties---for example, statements of peer review or that the text has
|
||||
been approved by an organization as the authoritative definition of a
|
||||
standard.
|
||||
|
||||
You may add a passage of up to five words as a Front-Cover Text, and a
|
||||
passage of up to 25 words as a Back-Cover Text, to the end of the list
|
||||
of Cover Texts in the Modified Version. Only one passage of
|
||||
Front-Cover Text and one of Back-Cover Text may be added by (or
|
||||
through arrangements made by) any one entity. If the Document already
|
||||
includes a cover text for the same cover, previously added by you or
|
||||
by arrangement made by the same entity you are acting on behalf of,
|
||||
you may not add another; but you may replace the old one, on explicit
|
||||
permission from the previous publisher that added the old one.
|
||||
|
||||
The author(s) and publisher(s) of the Document do not by this License
|
||||
give permission to use their names for publicity for or to assert or
|
||||
imply endorsement of any Modified Version.
|
||||
|
||||
@item
|
||||
COMBINING DOCUMENTS
|
||||
|
||||
You may combine the Document with other documents released under this
|
||||
License, under the terms defined in section 4 above for modified
|
||||
versions, provided that you include in the combination all of the
|
||||
Invariant Sections of all of the original documents, unmodified, and
|
||||
list them all as Invariant Sections of your combined work in its
|
||||
license notice, and that you preserve all their Warranty Disclaimers.
|
||||
|
||||
The combined work need only contain one copy of this License, and
|
||||
multiple identical Invariant Sections may be replaced with a single
|
||||
copy. If there are multiple Invariant Sections with the same name but
|
||||
different contents, make the title of each such section unique by
|
||||
adding at the end of it, in parentheses, the name of the original
|
||||
author or publisher of that section if known, or else a unique number.
|
||||
Make the same adjustment to the section titles in the list of
|
||||
Invariant Sections in the license notice of the combined work.
|
||||
|
||||
In the combination, you must combine any sections Entitled ``History''
|
||||
in the various original documents, forming one section Entitled
|
||||
``History''; likewise combine any sections Entitled ``Acknowledgements'',
|
||||
and any sections Entitled ``Dedications''. You must delete all
|
||||
sections Entitled ``Endorsements.''
|
||||
|
||||
@item
|
||||
COLLECTIONS OF DOCUMENTS
|
||||
|
||||
You may make a collection consisting of the Document and other documents
|
||||
released under this License, and replace the individual copies of this
|
||||
License in the various documents with a single copy that is included in
|
||||
the collection, provided that you follow the rules of this License for
|
||||
verbatim copying of each of the documents in all other respects.
|
||||
|
||||
You may extract a single document from such a collection, and distribute
|
||||
it individually under this License, provided you insert a copy of this
|
||||
License into the extracted document, and follow this License in all
|
||||
other respects regarding verbatim copying of that document.
|
||||
|
||||
@item
|
||||
AGGREGATION WITH INDEPENDENT WORKS
|
||||
|
||||
A compilation of the Document or its derivatives with other separate
|
||||
and independent documents or works, in or on a volume of a storage or
|
||||
distribution medium, is called an ``aggregate'' if the copyright
|
||||
resulting from the compilation is not used to limit the legal rights
|
||||
of the compilation's users beyond what the individual works permit.
|
||||
When the Document is included in an aggregate, this License does not
|
||||
apply to the other works in the aggregate which are not themselves
|
||||
derivative works of the Document.
|
||||
|
||||
If the Cover Text requirement of section 3 is applicable to these
|
||||
copies of the Document, then if the Document is less than one half of
|
||||
the entire aggregate, the Document's Cover Texts may be placed on
|
||||
covers that bracket the Document within the aggregate, or the
|
||||
electronic equivalent of covers if the Document is in electronic form.
|
||||
Otherwise they must appear on printed covers that bracket the whole
|
||||
aggregate.
|
||||
|
||||
@item
|
||||
TRANSLATION
|
||||
|
||||
Translation is considered a kind of modification, so you may
|
||||
distribute translations of the Document under the terms of section 4.
|
||||
Replacing Invariant Sections with translations requires special
|
||||
permission from their copyright holders, but you may include
|
||||
translations of some or all Invariant Sections in addition to the
|
||||
original versions of these Invariant Sections. You may include a
|
||||
translation of this License, and all the license notices in the
|
||||
Document, and any Warranty Disclaimers, provided that you also include
|
||||
the original English version of this License and the original versions
|
||||
of those notices and disclaimers. In case of a disagreement between
|
||||
the translation and the original version of this License or a notice
|
||||
or disclaimer, the original version will prevail.
|
||||
|
||||
If a section in the Document is Entitled ``Acknowledgements'',
|
||||
``Dedications'', or ``History'', the requirement (section 4) to Preserve
|
||||
its Title (section 1) will typically require changing the actual
|
||||
title.
|
||||
|
||||
@item
|
||||
TERMINATION
|
||||
|
||||
You may not copy, modify, sublicense, or distribute the Document except
|
||||
as expressly provided for under this License. Any other attempt to
|
||||
copy, modify, sublicense or distribute the Document is void, and will
|
||||
automatically terminate your rights under this License. However,
|
||||
parties who have received copies, or rights, from you under this
|
||||
License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
@item
|
||||
FUTURE REVISIONS OF THIS LICENSE
|
||||
|
||||
The Free Software Foundation may publish new, revised versions
|
||||
of the GNU Free Documentation License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns. See
|
||||
@uref{http://www.gnu.org/copyleft/}.
|
||||
|
||||
Each version of the License is given a distinguishing version number.
|
||||
If the Document specifies that a particular numbered version of this
|
||||
License ``or any later version'' applies to it, you have the option of
|
||||
following the terms and conditions either of that specified version or
|
||||
of any later version that has been published (not as a draft) by the
|
||||
Free Software Foundation. If the Document does not specify a version
|
||||
number of this License, you may choose any version ever published (not
|
||||
as a draft) by the Free Software Foundation.
|
||||
@end enumerate
|
||||
|
||||
@page
|
||||
@appendixsubsec ADDENDUM: How to use this License for your documents
|
||||
|
||||
To use this License in a document you have written, include a copy of
|
||||
the License in the document and put the following copyright and
|
||||
license notices just after the title page:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
Copyright (C) @var{year} @var{your name}.
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
|
||||
Texts. A copy of the license is included in the section entitled ``GNU
|
||||
Free Documentation License''.
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
|
||||
replace the ``with...Texts.'' line with this:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
with the Invariant Sections being @var{list their titles}, with
|
||||
the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
|
||||
being @var{list}.
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
If you have Invariant Sections without Cover Texts, or some other
|
||||
combination of the three, merge those two alternatives to suit the
|
||||
situation.
|
||||
|
||||
If your document contains nontrivial examples of program code, we
|
||||
recommend releasing these examples in parallel under your choice of
|
||||
free software license, such as the GNU General Public License,
|
||||
to permit their use in free software.
|
||||
|
||||
@c Local Variables:
|
||||
@c ispell-local-pdict: "ispell-dict"
|
||||
@c End:
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
@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
|
||||
|
||||
@@ -35,13 +46,13 @@ 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 @sc{posix}
|
||||
@cindex epoch, for @sc{posix}
|
||||
@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 @sc{posix} systems, the clock starts at 1970-01-01 00:00:00
|
||||
@sc{utc}: @sc{posix} does not require support for times before the
|
||||
@sc{posix} Epoch and times far in the future. Traditional Unix systems
|
||||
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
|
||||
|
||||
2355
doc/tar.texi
2355
doc/tar.texi
File diff suppressed because it is too large
Load Diff
95
lib/.cvsignore
Normal file
95
lib/.cvsignore
Normal file
@@ -0,0 +1,95 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
addext.c
|
||||
alloca.c
|
||||
alloca.h
|
||||
alloca_.h
|
||||
argmatch.c
|
||||
argmatch.h
|
||||
backupfile.c
|
||||
backupfile.h
|
||||
basename.c
|
||||
chown.c
|
||||
dirname.c
|
||||
dirname.h
|
||||
error.c
|
||||
error.h
|
||||
exclude.c
|
||||
exclude.h
|
||||
exit.h
|
||||
exitfail.c
|
||||
exitfail.h
|
||||
fileblocks.c
|
||||
fnmatch.c
|
||||
fnmatch_.h
|
||||
fnmatch_loop.c
|
||||
ftruncate.c
|
||||
full-write.c
|
||||
full-write.h
|
||||
getdate.c
|
||||
getdate.h
|
||||
getdate.y
|
||||
getline.c
|
||||
getline.h
|
||||
getndelim2.c
|
||||
getndelim2.h
|
||||
getopt.c
|
||||
getopt.h
|
||||
getopt1.c
|
||||
gettext.h
|
||||
hash.c
|
||||
hash.h
|
||||
human.c
|
||||
human.h
|
||||
lchown.c
|
||||
lchown.h
|
||||
malloc.c
|
||||
memset.c
|
||||
mktime.c
|
||||
modechange.c
|
||||
modechange.h
|
||||
obstack.c
|
||||
obstack.h
|
||||
pathmax.h
|
||||
quote.c
|
||||
quote.h
|
||||
quotearg.c
|
||||
quotearg.h
|
||||
realloc.c
|
||||
rmdir.c
|
||||
safe-read.c
|
||||
safe-read.h
|
||||
safe-write.c
|
||||
safe-write.h
|
||||
save-cwd.c
|
||||
save-cwd.h
|
||||
savedir.c
|
||||
savedir.h
|
||||
stdbool.h
|
||||
stdbool_.h
|
||||
strcase.h
|
||||
strcasecmp.c
|
||||
stripslash.c
|
||||
strncasecmp.c
|
||||
strtoimax.c
|
||||
strtol.c
|
||||
strtoll.c
|
||||
strtoul.c
|
||||
strtoull.c
|
||||
strtoumax.c
|
||||
stpcpy.c
|
||||
stpcpy.h
|
||||
time_r.c
|
||||
time_r.h
|
||||
unlocked-io.h
|
||||
utime.c
|
||||
xalloc.h
|
||||
xgetcwd.c
|
||||
xgetcwd.h
|
||||
xmalloc.c
|
||||
xstrdup.c
|
||||
xstrtol.c
|
||||
xstrtol.h
|
||||
xstrtoul.c
|
||||
xstrtoumax.c
|
||||
185
lib/Makefile.am
185
lib/Makefile.am
@@ -1,45 +1,170 @@
|
||||
# Makefile for GNU tar library.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997 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.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
## This 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.
|
||||
|
||||
# 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.
|
||||
## 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.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits
|
||||
## 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
|
||||
|
||||
EXTRA_DIST = \
|
||||
alloca.c fileblocks.c fnmatch.c ftruncate.c execlp.c gmalloc.c \
|
||||
memset.c mkdir.c modechange.h rename.c rmdir.c stpcpy.c strstr.c
|
||||
libtar_a_SOURCES = prepargs.c prepargs.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
argmatch.h backupfile.h error.h fnmatch.h getopt.h getdate.h getpagesize.h \
|
||||
pathmax.h
|
||||
|
||||
libtar_a_SOURCES = \
|
||||
argmatch.c backupfile.c error.c getdate.y getopt.c getopt1.c getversion.c \
|
||||
modechange.c msleep.c xgetcwd.c xmalloc.c xstrdup.c
|
||||
|
||||
INCLUDES = -I.. -I$(srcdir) -I../intl
|
||||
|
||||
libtar_a_LIBADD = @ALLOCA@ @LIBOBJS@
|
||||
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
|
||||
@echo Expect 13 shift/reduce conflicts...
|
||||
cd $(srcdir) && \
|
||||
$(YACC) $(YFLAGS) getdate.y; \
|
||||
$(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
|
||||
|
||||
48
lib/alloca.c
48
lib/alloca.c
@@ -33,7 +33,15 @@
|
||||
#endif
|
||||
|
||||
#ifdef emacs
|
||||
# include "lisp.h"
|
||||
# include "blockinput.h"
|
||||
# define xalloc_die() memory_full ()
|
||||
# ifdef EMACS_FREE
|
||||
# undef free
|
||||
# define free EMACS_FREE
|
||||
# endif
|
||||
#else
|
||||
# include <xalloc.h>
|
||||
#endif
|
||||
|
||||
/* If compiling with GCC 2, this file's not needed. */
|
||||
@@ -53,6 +61,8 @@
|
||||
you
|
||||
lose
|
||||
-- must know STACK_DIRECTION at compile-time
|
||||
/* Using #error here is not wise since this file should work for
|
||||
old and obscure compilers. */
|
||||
# endif /* STACK_DIRECTION undefined */
|
||||
# endif /* static */
|
||||
# endif /* emacs */
|
||||
@@ -67,32 +77,19 @@ long i00afunc ();
|
||||
# define ADDRESS_FUNCTION(arg) &(arg)
|
||||
# endif
|
||||
|
||||
# if __STDC__
|
||||
typedef void *pointer;
|
||||
# else
|
||||
typedef char *pointer;
|
||||
# ifndef POINTER_TYPE
|
||||
# ifdef __STDC__
|
||||
# define POINTER_TYPE void
|
||||
# else
|
||||
# define POINTER_TYPE char
|
||||
# endif
|
||||
# endif
|
||||
typedef POINTER_TYPE *pointer;
|
||||
|
||||
# ifndef NULL
|
||||
# define NULL 0
|
||||
# endif
|
||||
|
||||
/* Different portions of Emacs need to call different versions of
|
||||
malloc. The Emacs executable needs alloca to call xmalloc, because
|
||||
ordinary malloc isn't protected from input signals. On the other
|
||||
hand, the utilities in lib-src need alloca to call malloc; some of
|
||||
them are very simple, and don't have an xmalloc routine.
|
||||
|
||||
Non-Emacs programs expect this to call xmalloc.
|
||||
|
||||
Callers below should use malloc. */
|
||||
|
||||
# ifndef emacs
|
||||
# undef malloc
|
||||
# define malloc xmalloc
|
||||
# endif
|
||||
extern pointer malloc ();
|
||||
|
||||
/* Define STACK_DIRECTION if you know the direction of stack
|
||||
growth for your system; otherwise it will be automatically
|
||||
deduced at run-time.
|
||||
@@ -169,7 +166,8 @@ static header *last_alloca_header = NULL; /* -> last alloca header. */
|
||||
implementations of C, for example under Gould's UTX/32. */
|
||||
|
||||
pointer
|
||||
alloca (size_t size)
|
||||
alloca (size)
|
||||
size_t size;
|
||||
{
|
||||
auto char probe; /* Probes stack depth: */
|
||||
register char *depth = ADDRESS_FUNCTION (probe);
|
||||
@@ -215,8 +213,14 @@ alloca (size_t size)
|
||||
/* Allocate combined header + user data storage. */
|
||||
|
||||
{
|
||||
register pointer new = malloc (sizeof (header) + size);
|
||||
/* Address of header. */
|
||||
register pointer new;
|
||||
|
||||
size_t combined_size = sizeof (header) + size;
|
||||
if (combined_size < sizeof (header))
|
||||
xalloc_die ();
|
||||
|
||||
new = xmalloc (combined_size);
|
||||
|
||||
if (new == 0)
|
||||
abort();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* argmatch.c -- find a match for a string in an array
|
||||
Copyright (C) 1990, 1998, 1999 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1990, 1998, 1999, 2001, 2002, 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
|
||||
@@ -18,39 +20,33 @@
|
||||
/* Written by David MacKenzie <djm@ai.mit.edu>
|
||||
Modified by Akim Demaille <demaille@inf.enst.fr> */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#include "argmatch.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <string.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(Text) gettext (Text)
|
||||
#else
|
||||
# define _(Text) Text
|
||||
#endif
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "error.h"
|
||||
#include "quotearg.h"
|
||||
#include "quote.h"
|
||||
#include "unlocked-io.h"
|
||||
|
||||
/* When reporting an invalid argument, show nonprinting characters
|
||||
by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
|
||||
literal_quoting_style. */
|
||||
#ifndef ARGMATCH_QUOTING_STYLE
|
||||
# define ARGMATCH_QUOTING_STYLE escape_quoting_style
|
||||
# define ARGMATCH_QUOTING_STYLE locale_quoting_style
|
||||
#endif
|
||||
|
||||
/* The following test is to work around the gross typo in
|
||||
systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
|
||||
is defined to 0, not 1. */
|
||||
#if !EXIT_FAILURE
|
||||
# undef EXIT_FAILURE
|
||||
#ifndef EXIT_FAILURE
|
||||
# define EXIT_FAILURE 1
|
||||
#endif
|
||||
|
||||
@@ -78,7 +74,6 @@ argmatch_exit_fn argmatch_die = __argmatch_die;
|
||||
null-terminated array ARGLIST, return the index in ARGLIST
|
||||
of the matched element, else -1 if it does not match any element
|
||||
or -2 if it is ambiguous (is a prefix of more than one element).
|
||||
If SENSITIVE, comparison is case sensitive.
|
||||
|
||||
If VALLIST is none null, use it to resolve ambiguities limited to
|
||||
synonyms, i.e., for
|
||||
@@ -86,10 +81,9 @@ argmatch_exit_fn argmatch_die = __argmatch_die;
|
||||
"no", "nope" -> 1
|
||||
"y" is a valid argument, for `0', and "n" for `1'. */
|
||||
|
||||
static int
|
||||
__argmatch_internal (const char *arg, const char *const *arglist,
|
||||
const char *vallist, size_t valsize,
|
||||
int case_sensitive)
|
||||
int
|
||||
argmatch (const char *arg, const char *const *arglist,
|
||||
const char *vallist, size_t valsize)
|
||||
{
|
||||
int i; /* Temporary index in ARGLIST. */
|
||||
size_t arglen; /* Length of ARG. */
|
||||
@@ -101,9 +95,7 @@ __argmatch_internal (const char *arg, const char *const *arglist,
|
||||
/* Test all elements for either exact match or abbreviated matches. */
|
||||
for (i = 0; arglist[i]; i++)
|
||||
{
|
||||
if (case_sensitive
|
||||
? !strncmp (arglist[i], arg, arglen)
|
||||
: !strncasecmp (arglist[i], arg, arglen))
|
||||
if (!strncmp (arglist[i], arg, arglen))
|
||||
{
|
||||
if (strlen (arglist[i]) == arglen)
|
||||
/* Exact match found. */
|
||||
@@ -131,22 +123,6 @@ __argmatch_internal (const char *arg, const char *const *arglist,
|
||||
return matchind;
|
||||
}
|
||||
|
||||
/* argmatch - case sensitive version */
|
||||
int
|
||||
argmatch (const char *arg, const char *const *arglist,
|
||||
const char *vallist, size_t valsize)
|
||||
{
|
||||
return __argmatch_internal (arg, arglist, vallist, valsize, 1);
|
||||
}
|
||||
|
||||
/* argcasematch - case insensitive version */
|
||||
int
|
||||
argcasematch (const char *arg, const char *const *arglist,
|
||||
const char *vallist, size_t valsize)
|
||||
{
|
||||
return __argmatch_internal (arg, arglist, vallist, valsize, 0);
|
||||
}
|
||||
|
||||
/* Error reporting for argmatch.
|
||||
CONTEXT is a description of the type of entity that was being matched.
|
||||
VALUE is the invalid value that was given.
|
||||
@@ -155,21 +131,12 @@ argcasematch (const char *arg, const char *const *arglist,
|
||||
void
|
||||
argmatch_invalid (const char *context, const char *value, int problem)
|
||||
{
|
||||
enum quoting_style saved_quoting_style;
|
||||
char const *format;
|
||||
char const *format = (problem == -1
|
||||
? _("invalid argument %s for %s")
|
||||
: _("ambiguous argument %s for %s"));
|
||||
|
||||
/* Make sure to have a good quoting style to report errors.
|
||||
literal is insane here. */
|
||||
saved_quoting_style = get_quoting_style (NULL);
|
||||
set_quoting_style (NULL, ARGMATCH_QUOTING_STYLE);
|
||||
|
||||
format = (problem == -1
|
||||
? _("invalid argument `%s' for `%s'")
|
||||
: _("ambiguous argument `%s' for `%s'"));
|
||||
|
||||
error (0, 0, format, quotearg (value), context);
|
||||
|
||||
set_quoting_style (NULL, saved_quoting_style);
|
||||
error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
|
||||
quote_n (1, context));
|
||||
}
|
||||
|
||||
/* List the valid arguments for argmatch.
|
||||
@@ -210,12 +177,9 @@ int
|
||||
__xargmatch_internal (const char *context,
|
||||
const char *arg, const char *const *arglist,
|
||||
const char *vallist, size_t valsize,
|
||||
int case_sensitive,
|
||||
argmatch_exit_fn exit_fn)
|
||||
{
|
||||
int res = __argmatch_internal (arg, arglist,
|
||||
vallist, valsize,
|
||||
case_sensitive);
|
||||
int res = argmatch (arg, arglist, vallist, valsize);
|
||||
if (res >= 0)
|
||||
/* Success. */
|
||||
return res;
|
||||
@@ -301,12 +265,12 @@ main (int argc, const char *const *argv)
|
||||
}
|
||||
|
||||
if ((cp = getenv ("VERSION_CONTROL")))
|
||||
backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
|
||||
backup_args, backup_vals);
|
||||
backup_type = XARGMATCH ("$VERSION_CONTROL", cp,
|
||||
backup_args, backup_vals);
|
||||
|
||||
if (argc == 2)
|
||||
backup_type = XARGCASEMATCH (program_name, argv[1],
|
||||
backup_args, backup_vals);
|
||||
backup_type = XARGMATCH (program_name, argv[1],
|
||||
backup_args, backup_vals);
|
||||
|
||||
printf ("The version control is `%s'\n",
|
||||
ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
|
||||
|
||||
119
lib/error.c
119
lib/error.c
@@ -1,22 +1,18 @@
|
||||
/* Error handler for noninteractive utilities
|
||||
Copyright (C) 1990-1998, 2000, 2001 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library. Its master source is NOT part of
|
||||
the C library, however. The master source lives in /gd/gnu/lib.
|
||||
Copyright (C) 1990-1998, 2000, 2001, 2002 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.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
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
|
||||
Lesser General Public License for more details.
|
||||
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 Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
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. */
|
||||
|
||||
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
|
||||
|
||||
@@ -25,7 +21,13 @@
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "gettext.h"
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <wchar.h>
|
||||
# define mbsrtowcs __mbsrtowcs
|
||||
@@ -53,6 +55,10 @@ void exit ();
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#if !_LIBC
|
||||
# include "unlocked-io.h"
|
||||
#endif
|
||||
|
||||
#ifndef _
|
||||
# define _(String) String
|
||||
#endif
|
||||
@@ -74,6 +80,7 @@ unsigned int error_message_count;
|
||||
|
||||
# define program_name program_invocation_name
|
||||
# include <errno.h>
|
||||
# include <libio/libioP.h>
|
||||
|
||||
/* In GNU libc we want do not want to use the common name `error' directly.
|
||||
Instead make it a weak alias. */
|
||||
@@ -87,27 +94,38 @@ extern void __error_at_line (int status, int errnum, const char *file_name,
|
||||
# define error_at_line __error_at_line
|
||||
|
||||
# ifdef USE_IN_LIBIO
|
||||
# include <libio/iolibio.h>
|
||||
# define fflush(s) _IO_fflush (s)
|
||||
# include <libio/iolibio.h>
|
||||
# define fflush(s) INTUSE(_IO_fflush) (s)
|
||||
# undef putc
|
||||
# define putc(c, fp) INTUSE(_IO_putc) (c, fp)
|
||||
# endif
|
||||
|
||||
#else /* not _LIBC */
|
||||
|
||||
# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
|
||||
# ifndef HAVE_DECL_STRERROR_R
|
||||
"this configure-time declaration test was not run"
|
||||
# endif
|
||||
char *strerror_r ();
|
||||
# endif
|
||||
|
||||
/* The calling program should define program_name and set it to the
|
||||
name of the executing program. */
|
||||
extern char *program_name;
|
||||
|
||||
# ifdef HAVE_STRERROR_R
|
||||
# if HAVE_STRERROR_R || defined strerror_r
|
||||
# define __strerror_r strerror_r
|
||||
# else
|
||||
# if HAVE_STRERROR
|
||||
# ifndef strerror /* On some systems, strerror is a macro */
|
||||
# ifndef HAVE_DECL_STRERROR
|
||||
"this configure-time declaration test was not run"
|
||||
# endif
|
||||
# if !HAVE_DECL_STRERROR
|
||||
char *strerror ();
|
||||
# endif
|
||||
# else
|
||||
static char *
|
||||
private_strerror (errnum)
|
||||
int errnum;
|
||||
private_strerror (int errnum)
|
||||
{
|
||||
extern char *sys_errlist[];
|
||||
extern int sys_nerr;
|
||||
@@ -118,9 +136,43 @@ private_strerror (errnum)
|
||||
}
|
||||
# define strerror private_strerror
|
||||
# endif /* HAVE_STRERROR */
|
||||
# endif /* HAVE_STRERROR_R */
|
||||
# endif /* HAVE_STRERROR_R || defined strerror_r */
|
||||
#endif /* not _LIBC */
|
||||
|
||||
static void
|
||||
print_errno_message (int errnum)
|
||||
{
|
||||
char const *s;
|
||||
|
||||
#if defined HAVE_STRERROR_R || _LIBC
|
||||
char errbuf[1024];
|
||||
# if STRERROR_R_CHAR_P || _LIBC
|
||||
s = __strerror_r (errnum, errbuf, sizeof errbuf);
|
||||
# else
|
||||
if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
|
||||
s = errbuf;
|
||||
else
|
||||
s = 0;
|
||||
# endif
|
||||
#else
|
||||
s = strerror (errnum);
|
||||
#endif
|
||||
|
||||
#if !_LIBC
|
||||
if (! s)
|
||||
s = _("Unknown system error");
|
||||
#endif
|
||||
|
||||
#if _LIBC && USE_IN_LIBIO
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
{
|
||||
__fwprintf (stderr, L": %s", s);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf (stderr, ": %s", s);
|
||||
}
|
||||
|
||||
#ifdef VA_START
|
||||
static void
|
||||
@@ -177,25 +229,12 @@ error_tail (int status, int errnum, const char *message, va_list args)
|
||||
|
||||
++error_message_count;
|
||||
if (errnum)
|
||||
{
|
||||
#if defined HAVE_STRERROR_R || _LIBC
|
||||
char errbuf[1024];
|
||||
char *s = __strerror_r (errnum, errbuf, sizeof errbuf);
|
||||
print_errno_message (errnum);
|
||||
# if _LIBC && USE_IN_LIBIO
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
__fwprintf (stderr, L": %s", s);
|
||||
else
|
||||
# endif
|
||||
fprintf (stderr, ": %s", s);
|
||||
#else
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
#endif
|
||||
}
|
||||
#if _LIBC && USE_IN_LIBIO
|
||||
if (_IO_fwide (stderr, 0) > 0)
|
||||
putwc (L'\n', stderr);
|
||||
else
|
||||
#endif
|
||||
# endif
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
@@ -252,7 +291,7 @@ error (status, errnum, message, va_alist)
|
||||
|
||||
++error_message_count;
|
||||
if (errnum)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
print_errno_message (errnum);
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
@@ -343,7 +382,7 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist)
|
||||
|
||||
++error_message_count;
|
||||
if (errnum)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
print_errno_message (errnum);
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
|
||||
222
lib/exclude.c
222
lib/exclude.c
@@ -1,5 +1,7 @@
|
||||
/* exclude.c -- exclude file names
|
||||
Copyright 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 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
|
||||
@@ -22,72 +24,205 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
#include <exclude.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#if HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#if HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#else
|
||||
# if HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void *xmalloc PARAMS ((size_t));
|
||||
void *xrealloc PARAMS ((void *, size_t));
|
||||
#include "exclude.h"
|
||||
#include "fnmatch.h"
|
||||
#include "unlocked-io.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Keep track of excluded file name patterns. */
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
/* Verify a requirement at compile-time (unlike assert, which is runtime). */
|
||||
#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
|
||||
|
||||
/* Non-GNU systems lack these options, so we don't need to check them. */
|
||||
#ifndef FNM_CASEFOLD
|
||||
# define FNM_CASEFOLD 0
|
||||
#endif
|
||||
#ifndef FNM_LEADING_DIR
|
||||
# define FNM_LEADING_DIR 0
|
||||
#endif
|
||||
|
||||
verify (EXCLUDE_macros_do_not_collide_with_FNM_macros,
|
||||
(((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
|
||||
& (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
|
||||
| FNM_CASEFOLD))
|
||||
== 0));
|
||||
|
||||
/* An exclude pattern-options pair. The options are fnmatch options
|
||||
ORed with EXCLUDE_* options. */
|
||||
|
||||
struct patopts
|
||||
{
|
||||
char const *pattern;
|
||||
int options;
|
||||
};
|
||||
|
||||
/* An exclude list, of pattern-options pairs. */
|
||||
|
||||
struct exclude
|
||||
{
|
||||
char const **exclude;
|
||||
int exclude_alloc;
|
||||
int exclude_count;
|
||||
struct patopts *exclude;
|
||||
size_t exclude_alloc;
|
||||
size_t exclude_count;
|
||||
};
|
||||
|
||||
/* Return a newly allocated and empty exclude list. */
|
||||
|
||||
struct exclude *
|
||||
new_exclude (void)
|
||||
{
|
||||
struct exclude *ex = (struct exclude *) xmalloc (sizeof (struct exclude));
|
||||
struct exclude *ex = xmalloc (sizeof *ex);
|
||||
ex->exclude_count = 0;
|
||||
ex->exclude_alloc = 64;
|
||||
ex->exclude = (char const **) xmalloc (ex->exclude_alloc * sizeof (char *));
|
||||
ex->exclude_alloc = (1 << 6); /* This must be a power of 2. */
|
||||
ex->exclude = xmalloc (ex->exclude_alloc * sizeof ex->exclude[0]);
|
||||
return ex;
|
||||
}
|
||||
|
||||
int
|
||||
excluded_filename (struct exclude const *ex, char const *f)
|
||||
{
|
||||
char const * const *exclude = ex->exclude;
|
||||
int exclude_count = ex->exclude_count;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < exclude_count; i++)
|
||||
if (fnmatch (exclude[i], f, 0) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Free the storage associated with an exclude list. */
|
||||
|
||||
void
|
||||
add_exclude (struct exclude *ex, char const *pattern)
|
||||
free_exclude (struct exclude *ex)
|
||||
{
|
||||
if (ex->exclude_alloc <= ex->exclude_count)
|
||||
ex->exclude = (char const **) xrealloc (ex->exclude,
|
||||
((ex->exclude_alloc *= 2)
|
||||
* sizeof (char *)));
|
||||
|
||||
ex->exclude[ex->exclude_count++] = pattern;
|
||||
free (ex->exclude);
|
||||
free (ex);
|
||||
}
|
||||
|
||||
int
|
||||
add_exclude_file (struct exclude *ex, char const *filename, char line_end)
|
||||
/* Return zero if PATTERN matches F, obeying OPTIONS, except that
|
||||
(unlike fnmatch) wildcards are disabled in PATTERN. */
|
||||
|
||||
static int
|
||||
fnmatch_no_wildcards (char const *pattern, char const *f, int options)
|
||||
{
|
||||
int use_stdin = filename[0] == '-' && !filename[1];
|
||||
if (! (options & FNM_LEADING_DIR))
|
||||
return ((options & FNM_CASEFOLD)
|
||||
? strcasecmp (pattern, f)
|
||||
: strcmp (pattern, f));
|
||||
else
|
||||
{
|
||||
size_t patlen = strlen (pattern);
|
||||
int r = ((options & FNM_CASEFOLD)
|
||||
? strncasecmp (pattern, f, patlen)
|
||||
: strncmp (pattern, f, patlen));
|
||||
if (! r)
|
||||
{
|
||||
r = f[patlen];
|
||||
if (r == '/')
|
||||
r = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if EX excludes F. */
|
||||
|
||||
bool
|
||||
excluded_filename (struct exclude const *ex, char const *f)
|
||||
{
|
||||
size_t exclude_count = ex->exclude_count;
|
||||
|
||||
/* If no options are given, the default is to include. */
|
||||
if (exclude_count == 0)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
struct patopts const *exclude = ex->exclude;
|
||||
size_t i;
|
||||
|
||||
/* Otherwise, the default is the opposite of the first option. */
|
||||
bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
|
||||
|
||||
/* Scan through the options, seeing whether they change F from
|
||||
excluded to included or vice versa. */
|
||||
for (i = 0; i < exclude_count; i++)
|
||||
{
|
||||
char const *pattern = exclude[i].pattern;
|
||||
int options = exclude[i].options;
|
||||
if (excluded == !! (options & EXCLUDE_INCLUDE))
|
||||
{
|
||||
int (*matcher) (char const *, char const *, int) =
|
||||
(options & EXCLUDE_WILDCARDS
|
||||
? fnmatch
|
||||
: fnmatch_no_wildcards);
|
||||
bool matched = ((*matcher) (pattern, f, options) == 0);
|
||||
char const *p;
|
||||
|
||||
if (! (options & EXCLUDE_ANCHORED))
|
||||
for (p = f; *p && ! matched; p++)
|
||||
if (*p == '/' && p[1] != '/')
|
||||
matched = ((*matcher) (pattern, p + 1, options) == 0);
|
||||
|
||||
excluded ^= matched;
|
||||
}
|
||||
}
|
||||
|
||||
return excluded;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append to EX the exclusion PATTERN with OPTIONS. */
|
||||
|
||||
void
|
||||
add_exclude (struct exclude *ex, char const *pattern, int options)
|
||||
{
|
||||
struct patopts *patopts;
|
||||
|
||||
if (ex->exclude_alloc <= ex->exclude_count)
|
||||
{
|
||||
size_t s = 2 * ex->exclude_alloc;
|
||||
if (! (0 < s && s <= SIZE_MAX / sizeof ex->exclude[0]))
|
||||
xalloc_die ();
|
||||
ex->exclude_alloc = s;
|
||||
ex->exclude = xrealloc (ex->exclude, s * sizeof ex->exclude[0]);
|
||||
}
|
||||
|
||||
patopts = &ex->exclude[ex->exclude_count++];
|
||||
patopts->pattern = pattern;
|
||||
patopts->options = options;
|
||||
}
|
||||
|
||||
/* Use ADD_FUNC to append to EX the patterns in FILENAME, each with
|
||||
OPTIONS. LINE_END terminates each pattern in the file. Return -1
|
||||
on failure, 0 on success. */
|
||||
|
||||
int
|
||||
add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
|
||||
struct exclude *ex, char const *filename, int options,
|
||||
char line_end)
|
||||
{
|
||||
bool use_stdin = filename[0] == '-' && !filename[1];
|
||||
FILE *in;
|
||||
char *buf;
|
||||
char *p;
|
||||
char const *pattern;
|
||||
char const *lim;
|
||||
size_t buf_alloc = 1024;
|
||||
size_t buf_alloc = (1 << 10); /* This must be a power of two. */
|
||||
size_t buf_count = 0;
|
||||
int c;
|
||||
int e = 0;
|
||||
@@ -103,22 +238,27 @@ add_exclude_file (struct exclude *ex, char const *filename, char line_end)
|
||||
{
|
||||
buf[buf_count++] = c;
|
||||
if (buf_count == buf_alloc)
|
||||
buf = xrealloc (buf, buf_alloc *= 2);
|
||||
{
|
||||
buf_alloc *= 2;
|
||||
if (! buf_alloc)
|
||||
xalloc_die ();
|
||||
buf = xrealloc (buf, buf_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
buf = xrealloc (buf, buf_count + 1);
|
||||
|
||||
if (ferror (in))
|
||||
e = errno;
|
||||
|
||||
if (!use_stdin && fclose (in) != 0)
|
||||
e = errno;
|
||||
|
||||
buf = xrealloc (buf, buf_count + 1);
|
||||
|
||||
for (pattern = p = buf, lim = buf + buf_count; p <= lim; p++)
|
||||
if (p < lim ? *p == line_end : buf < p && p[-1])
|
||||
{
|
||||
*p = '\0';
|
||||
add_exclude (ex, pattern);
|
||||
(*add_func) (ex, pattern, options);
|
||||
pattern = p + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* exclude.h -- declarations for excluding file names
|
||||
Copyright 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1997, 1999, 2001, 2002, 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
|
||||
@@ -18,17 +20,24 @@
|
||||
|
||||
/* Written by Paul Eggert <eggert@twinsun.com> */
|
||||
|
||||
#ifndef PARAMS
|
||||
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
|
||||
# define PARAMS(Args) Args
|
||||
# else
|
||||
# define PARAMS(Args) ()
|
||||
# endif
|
||||
#endif
|
||||
/* Exclude options, which can be ORed with fnmatch options. */
|
||||
|
||||
/* Patterns must match the start of file names, instead of matching
|
||||
anywhere after a '/'. */
|
||||
#define EXCLUDE_ANCHORED (1 << 30)
|
||||
|
||||
/* Include instead of exclude. */
|
||||
#define EXCLUDE_INCLUDE (1 << 29)
|
||||
|
||||
/* '?', '*', '[', and '\\' are special in patterns. Without this
|
||||
option, these characters are ordinary and fnmatch is not used. */
|
||||
#define EXCLUDE_WILDCARDS (1 << 28)
|
||||
|
||||
struct exclude;
|
||||
|
||||
struct exclude *new_exclude PARAMS ((void));
|
||||
void add_exclude PARAMS ((struct exclude *, char const *));
|
||||
int add_exclude_file PARAMS ((struct exclude *, char const *, char));
|
||||
int excluded_filename PARAMS ((struct exclude const *, char const *));
|
||||
struct exclude *new_exclude (void);
|
||||
void free_exclude (struct exclude *);
|
||||
void add_exclude (struct exclude *, char const *, int);
|
||||
int add_exclude_file (void (*) (struct exclude *, char const *, int),
|
||||
struct exclude *, char const *, int, char);
|
||||
bool excluded_filename (struct exclude const *, char const *);
|
||||
|
||||
525
lib/fnmatch.c
525
lib/fnmatch.c
@@ -1,4 +1,5 @@
|
||||
/* Copyright 1991, 1992, 1993, 1996, 1997, 2000 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2002 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
|
||||
@@ -10,9 +11,9 @@
|
||||
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. */
|
||||
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>
|
||||
@@ -23,208 +24,362 @@
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
# define HAVE_ALLOCA 1
|
||||
#else
|
||||
# if defined HAVE_ALLOCA_H || defined _LIBC
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
# pragma alloca
|
||||
# else
|
||||
# ifndef alloca
|
||||
char *alloca ();
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ! defined __builtin_expect && __GNUC__ < 3
|
||||
# define __builtin_expect(expr, expected) (expr)
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined STDC_HEADERS || !defined isascii
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#if HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#else
|
||||
# define IN_CTYPE_DOMAIN(c) isascii (c)
|
||||
# if HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stddef.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
|
||||
|
||||
/* For platform which support the ISO C amendement 1 functionality we
|
||||
support user defined character classes. */
|
||||
#if defined _LIBC || WIDE_CHAR_SUPPORT
|
||||
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
|
||||
# include <wchar.h>
|
||||
# include <wctype.h>
|
||||
#endif
|
||||
|
||||
/* We need some of the locale data (the collation sequence information)
|
||||
but there is no interface to get this information in general. Therefore
|
||||
we support a correct implementation only in glibc. */
|
||||
#ifdef _LIBC
|
||||
# include "../locale/localeinfo.h"
|
||||
# include "../locale/elem-hash.h"
|
||||
# include "../locale/coll-lookup.h"
|
||||
# include <shlib-compat.h>
|
||||
|
||||
# define CONCAT(a,b) __CONCAT(a,b)
|
||||
# define mbsinit __mbsinit
|
||||
# define mbsrtowcs __mbsrtowcs
|
||||
# define fnmatch __fnmatch
|
||||
extern int fnmatch (const char *pattern, const char *string, int flags);
|
||||
#endif
|
||||
|
||||
/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */
|
||||
#define NO_LEADING_PERIOD(flags) \
|
||||
((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, are not
|
||||
actually compiling the library itself, and have not detected a bug
|
||||
in the library. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
#if defined _LIBC || !defined __GNU_LIBRARY__ || !HAVE_FNMATCH_GNU
|
||||
|
||||
|
||||
#ifndef errno
|
||||
# if defined STDC_HEADERS || !defined isascii
|
||||
# define ISASCII(c) 1
|
||||
# else
|
||||
# define ISASCII(c) isascii(c)
|
||||
# endif
|
||||
|
||||
# ifdef isblank
|
||||
# define ISBLANK(c) (ISASCII (c) && isblank (c))
|
||||
# else
|
||||
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
|
||||
# endif
|
||||
# ifdef isgraph
|
||||
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
|
||||
# else
|
||||
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
|
||||
# endif
|
||||
|
||||
# define ISPRINT(c) (ISASCII (c) && isprint (c))
|
||||
# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
|
||||
# define ISALNUM(c) (ISASCII (c) && isalnum (c))
|
||||
# define ISALPHA(c) (ISASCII (c) && isalpha (c))
|
||||
# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
|
||||
# define ISLOWER(c) (ISASCII (c) && islower (c))
|
||||
# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
|
||||
# define ISSPACE(c) (ISASCII (c) && isspace (c))
|
||||
# define ISUPPER(c) (ISASCII (c) && isupper (c))
|
||||
# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
|
||||
|
||||
# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
|
||||
|
||||
# if defined _LIBC || WIDE_CHAR_SUPPORT
|
||||
/* The GNU C library provides support for user-defined character classes
|
||||
and the functions from ISO C amendement 1. */
|
||||
# ifdef CHARCLASS_NAME_MAX
|
||||
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
|
||||
# else
|
||||
/* This shouldn't happen but some implementation might still have this
|
||||
problem. Use a reasonable default value. */
|
||||
# define CHAR_CLASS_MAX_LENGTH 256
|
||||
# endif
|
||||
|
||||
# ifdef _LIBC
|
||||
# define IS_CHAR_CLASS(string) __wctype (string)
|
||||
# else
|
||||
# define IS_CHAR_CLASS(string) wctype (string)
|
||||
# endif
|
||||
|
||||
# ifdef _LIBC
|
||||
# define ISWCTYPE(WC, WT) __iswctype (WC, WT)
|
||||
# else
|
||||
# define ISWCTYPE(WC, WT) iswctype (WC, WT)
|
||||
# endif
|
||||
|
||||
# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
|
||||
/* In this case we are implementing the multibyte character handling. */
|
||||
# define HANDLE_MULTIBYTE 1
|
||||
# endif
|
||||
|
||||
# else
|
||||
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
|
||||
|
||||
# define IS_CHAR_CLASS(string) \
|
||||
(STREQ (string, "alpha") || STREQ (string, "upper") \
|
||||
|| STREQ (string, "lower") || STREQ (string, "digit") \
|
||||
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \
|
||||
|| STREQ (string, "space") || STREQ (string, "print") \
|
||||
|| STREQ (string, "punct") || STREQ (string, "graph") \
|
||||
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
|
||||
# endif
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
whose names are inconsistent. */
|
||||
|
||||
# if !defined _LIBC && !defined getenv && !HAVE_DECL_GETENV
|
||||
extern char *getenv ();
|
||||
# endif
|
||||
|
||||
# ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
# endif
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, nonzero if not. */
|
||||
int
|
||||
fnmatch (const char *pattern, const char *string, int flags)
|
||||
{
|
||||
register const char *p = pattern, *n = string;
|
||||
register char c;
|
||||
/* Global variable. */
|
||||
static int posixly_correct;
|
||||
|
||||
# ifndef internal_function
|
||||
/* Inside GNU libc we mark some function in a special way. In other
|
||||
environments simply ignore the marking. */
|
||||
# define internal_function
|
||||
# endif
|
||||
|
||||
/* Note that this evaluates C many times. */
|
||||
#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER ((unsigned char) (c)) \
|
||||
? tolower ((unsigned char) (c)) \
|
||||
: (c))
|
||||
# ifdef _LIBC
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
|
||||
# else
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
|
||||
# endif
|
||||
# define CHAR char
|
||||
# define UCHAR unsigned char
|
||||
# define INT int
|
||||
# define FCT internal_fnmatch
|
||||
# define EXT ext_match
|
||||
# define END end_pattern
|
||||
# define L(CS) CS
|
||||
# ifdef _LIBC
|
||||
# define BTOWC(C) __btowc (C)
|
||||
# else
|
||||
# define BTOWC(C) btowc (C)
|
||||
# endif
|
||||
# define STRLEN(S) strlen (S)
|
||||
# define STRCAT(D, S) strcat (D, S)
|
||||
# ifdef _LIBC
|
||||
# define MEMPCPY(D, S, N) __mempcpy (D, S, N)
|
||||
# else
|
||||
# if HAVE_MEMPCPY
|
||||
# define MEMPCPY(D, S, N) mempcpy (D, S, N)
|
||||
# else
|
||||
# define MEMPCPY(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
|
||||
# endif
|
||||
# endif
|
||||
# define MEMCHR(S, C, N) memchr (S, C, N)
|
||||
# define STRCOLL(S1, S2) strcoll (S1, S2)
|
||||
# include "fnmatch_loop.c"
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
|
||||
# if HANDLE_MULTIBYTE
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c))
|
||||
# define CHAR wchar_t
|
||||
# define UCHAR wint_t
|
||||
# define INT wint_t
|
||||
# define FCT internal_fnwmatch
|
||||
# define EXT ext_wmatch
|
||||
# define END end_wpattern
|
||||
# define L(CS) L##CS
|
||||
# define BTOWC(C) (C)
|
||||
# ifdef _LIBC
|
||||
# define STRLEN(S) __wcslen (S)
|
||||
# define STRCAT(D, S) __wcscat (D, S)
|
||||
# define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
|
||||
# else
|
||||
# define STRLEN(S) wcslen (S)
|
||||
# define STRCAT(D, S) wcscat (D, S)
|
||||
# if HAVE_WMEMPCPY
|
||||
# define MEMPCPY(D, S, N) wmempcpy (D, S, N)
|
||||
# else
|
||||
# define MEMPCPY(D, S, N) (wmemcpy (D, S, N) + (N))
|
||||
# endif
|
||||
# endif
|
||||
# define MEMCHR(S, C, N) wmemchr (S, C, N)
|
||||
# define STRCOLL(S1, S2) wcscoll (S1, S2)
|
||||
# define WIDE_CHAR_VERSION 1
|
||||
|
||||
# undef IS_CHAR_CLASS
|
||||
/* We have to convert the wide character string in a multibyte string. But
|
||||
we know that the character class names consist of alphanumeric characters
|
||||
from the portable character set, and since the wide character encoding
|
||||
for a member of the portable character set is the same code point as
|
||||
its single-byte encoding, we can use a simplified method to convert the
|
||||
string to a multibyte character string. */
|
||||
static wctype_t
|
||||
is_char_class (const wchar_t *wcs)
|
||||
{
|
||||
char s[CHAR_CLASS_MAX_LENGTH + 1];
|
||||
char *cp = s;
|
||||
|
||||
do
|
||||
{
|
||||
c = FOLD (c);
|
||||
|
||||
switch (c)
|
||||
/* Test for a printable character from the portable character set. */
|
||||
# ifdef _LIBC
|
||||
if (*wcs < 0x20 || *wcs > 0x7e
|
||||
|| *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
|
||||
return (wctype_t) 0;
|
||||
# else
|
||||
switch (*wcs)
|
||||
{
|
||||
case '?':
|
||||
if (*n == '\0')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_FILE_NAME) && *n == '/')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
|
||||
return FNM_NOMATCH;
|
||||
case L' ': case L'!': case L'"': case L'#': case L'%':
|
||||
case L'&': case L'\'': case L'(': case L')': case L'*':
|
||||
case L'+': case L',': case L'-': case L'.': case L'/':
|
||||
case L'0': case L'1': case L'2': case L'3': case L'4':
|
||||
case L'5': case L'6': case L'7': case L'8': case L'9':
|
||||
case L':': case L';': case L'<': case L'=': case L'>':
|
||||
case L'?':
|
||||
case L'A': case L'B': case L'C': case L'D': case L'E':
|
||||
case L'F': case L'G': case L'H': case L'I': case L'J':
|
||||
case L'K': case L'L': case L'M': case L'N': case L'O':
|
||||
case L'P': case L'Q': case L'R': case L'S': case L'T':
|
||||
case L'U': case L'V': case L'W': case L'X': case L'Y':
|
||||
case L'Z':
|
||||
case L'[': case L'\\': case L']': case L'^': case L'_':
|
||||
case L'a': case L'b': case L'c': case L'd': case L'e':
|
||||
case L'f': case L'g': case L'h': case L'i': case L'j':
|
||||
case L'k': case L'l': case L'm': case L'n': case L'o':
|
||||
case L'p': case L'q': case L'r': case L's': case L't':
|
||||
case L'u': case L'v': case L'w': case L'x': case L'y':
|
||||
case L'z': case L'{': case L'|': case L'}': case L'~':
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE))
|
||||
{
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
/* Trailing \ loses. */
|
||||
return FNM_NOMATCH;
|
||||
c = FOLD (c);
|
||||
}
|
||||
if (FOLD (*n) != c)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
for (c = *p++; c == '?' || c == '*'; c = *p++)
|
||||
{
|
||||
if (c == '?')
|
||||
{
|
||||
/* A ? needs to match one character. */
|
||||
if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME)))
|
||||
/* There isn't another character; no match. */
|
||||
return FNM_NOMATCH;
|
||||
else
|
||||
/* One character of the string is consumed in matching
|
||||
this ? wildcard, so *??? won't match if there are
|
||||
less than three characters. */
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '\0')
|
||||
{
|
||||
if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME)
|
||||
for (; *n != '\0'; n++)
|
||||
if (*n == '/')
|
||||
return FNM_NOMATCH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
|
||||
c1 = FOLD (c1);
|
||||
for (--p; *n != '\0'; ++n)
|
||||
if ((c == '[' || FOLD (*n) == c1) &&
|
||||
fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
|
||||
return 0;
|
||||
else if (*n == '/' && (flags & FNM_FILE_NAME))
|
||||
break;
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
case '[':
|
||||
{
|
||||
/* Nonzero if the sense of the character class is inverted. */
|
||||
register int not;
|
||||
|
||||
if (*n == '\0')
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
not = (*p == '!' || *p == '^');
|
||||
if (not)
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;)
|
||||
{
|
||||
register char cstart = c, cend = c;
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return FNM_NOMATCH;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
cstart = cend = FOLD (cstart);
|
||||
|
||||
if (c == '\0')
|
||||
/* [ (unterminated) loses. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
if ((flags & FNM_FILE_NAME) && c == '/')
|
||||
/* [/] can never match. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if (c == '-' && *p != ']')
|
||||
{
|
||||
cend = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && cend == '\\')
|
||||
cend = *p++;
|
||||
if (cend == '\0')
|
||||
return FNM_NOMATCH;
|
||||
cend = FOLD (cend);
|
||||
|
||||
c = *p++;
|
||||
}
|
||||
|
||||
if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
|
||||
goto matched;
|
||||
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
if (!not)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
matched:;
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
while (c != ']')
|
||||
{
|
||||
if (c == '\0')
|
||||
/* [... (unterminated) loses. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
c = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return FNM_NOMATCH;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
if (not)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (c != FOLD (*n))
|
||||
return FNM_NOMATCH;
|
||||
return (wctype_t) 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
++n;
|
||||
/* Avoid overrunning the buffer. */
|
||||
if (cp == s + CHAR_CLASS_MAX_LENGTH)
|
||||
return (wctype_t) 0;
|
||||
|
||||
*cp++ = (char) *wcs++;
|
||||
}
|
||||
while (*wcs != L'\0');
|
||||
|
||||
if (*n == '\0')
|
||||
return 0;
|
||||
*cp = '\0';
|
||||
|
||||
if ((flags & FNM_LEADING_DIR) && *n == '/')
|
||||
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
|
||||
return 0;
|
||||
|
||||
return FNM_NOMATCH;
|
||||
|
||||
#undef FOLD
|
||||
# ifdef _LIBC
|
||||
return __wctype (s);
|
||||
# else
|
||||
return wctype (s);
|
||||
# endif
|
||||
}
|
||||
# define IS_CHAR_CLASS(string) is_char_class (string)
|
||||
|
||||
# include "fnmatch_loop.c"
|
||||
# endif
|
||||
|
||||
|
||||
int
|
||||
fnmatch (pattern, string, flags)
|
||||
const char *pattern;
|
||||
const char *string;
|
||||
int flags;
|
||||
{
|
||||
# if HANDLE_MULTIBYTE
|
||||
if (__builtin_expect (MB_CUR_MAX, 1) != 1)
|
||||
{
|
||||
mbstate_t ps;
|
||||
size_t n;
|
||||
wchar_t *wpattern;
|
||||
wchar_t *wstring;
|
||||
|
||||
/* Convert the strings into wide characters. */
|
||||
memset (&ps, '\0', sizeof (ps));
|
||||
n = mbsrtowcs (NULL, &pattern, 0, &ps);
|
||||
if (__builtin_expect (n, 0) == (size_t) -1)
|
||||
/* Something wrong.
|
||||
XXX Do we have to set `errno' to something which mbsrtows hasn't
|
||||
already done? */
|
||||
return -1;
|
||||
wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
|
||||
assert (mbsinit (&ps));
|
||||
(void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
|
||||
|
||||
assert (mbsinit (&ps));
|
||||
n = mbsrtowcs (NULL, &string, 0, &ps);
|
||||
if (__builtin_expect (n, 0) == (size_t) -1)
|
||||
/* Something wrong.
|
||||
XXX Do we have to set `errno' to something which mbsrtows hasn't
|
||||
already done? */
|
||||
return -1;
|
||||
wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
|
||||
assert (mbsinit (&ps));
|
||||
(void) mbsrtowcs (wstring, &string, n + 1, &ps);
|
||||
|
||||
return internal_fnwmatch (wpattern, wstring, wstring + n,
|
||||
flags & FNM_PERIOD, flags);
|
||||
}
|
||||
# endif /* mbstate_t and mbsrtowcs or _LIBC. */
|
||||
|
||||
return internal_fnmatch (pattern, string, string + strlen (string),
|
||||
flags & FNM_PERIOD, flags);
|
||||
}
|
||||
|
||||
# ifdef _LIBC
|
||||
# undef fnmatch
|
||||
versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
|
||||
# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
|
||||
strong_alias (__fnmatch, __fnmatch_old)
|
||||
compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif /* _LIBC or not __GNU_LIBRARY__. */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* full-write.c -- an interface to write that retries after interrupts
|
||||
/* An interface to read and write that retries (if necessary) until complete.
|
||||
|
||||
Copyright 1993, 1994, 1997, 1998, 1999, 2000, 2001 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright (C) 1993, 1994, 1997-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
|
||||
@@ -15,20 +14,17 @@
|
||||
|
||||
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.
|
||||
|
||||
Written by Paul Eggert. */
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "full-write.h"
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
/* Specification. */
|
||||
#ifdef FULL_READ
|
||||
# include "full-read.h"
|
||||
#else
|
||||
# include "full-write.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
@@ -36,32 +32,54 @@
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted
|
||||
or if partial writes occur. Return the number of bytes successfully
|
||||
written, setting errno if that is less than LEN. */
|
||||
|
||||
size_t
|
||||
full_write (int desc, const char *ptr, size_t len)
|
||||
{
|
||||
size_t total_written = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
ssize_t written = write (desc, ptr, len);
|
||||
if (written <= 0)
|
||||
{
|
||||
/* Some buggy drivers return 0 when you fall off a device's end. */
|
||||
if (written == 0)
|
||||
errno = ENOSPC;
|
||||
#ifdef EINTR
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
#ifdef FULL_READ
|
||||
# include "safe-read.h"
|
||||
# define safe_rw safe_read
|
||||
# define full_rw full_read
|
||||
# undef const
|
||||
# define const /* empty */
|
||||
#else
|
||||
# include "safe-write.h"
|
||||
# define safe_rw safe_write
|
||||
# define full_rw full_write
|
||||
#endif
|
||||
|
||||
#ifdef FULL_READ
|
||||
/* Set errno to zero upon EOF. */
|
||||
# define ZERO_BYTE_TRANSFER_ERRNO 0
|
||||
#else
|
||||
/* Some buggy drivers return 0 when one tries to write beyond
|
||||
a device's end. (Example: Linux 1.2.13 on /dev/fd0.)
|
||||
Set errno to ENOSPC so they get a sensible diagnostic. */
|
||||
# define ZERO_BYTE_TRANSFER_ERRNO ENOSPC
|
||||
#endif
|
||||
|
||||
/* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if
|
||||
interrupted or if a partial write(read) occurs. Return the number
|
||||
of bytes transferred.
|
||||
When writing, set errno if fewer than COUNT bytes are written.
|
||||
When reading, if fewer than COUNT bytes are read, you must examine
|
||||
errno to distinguish failure from EOF (errno == 0). */
|
||||
size_t
|
||||
full_rw (int fd, const void *buf, size_t count)
|
||||
{
|
||||
size_t total = 0;
|
||||
const char *ptr = buf;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
size_t n_rw = safe_rw (fd, ptr, count);
|
||||
if (n_rw == (size_t) -1)
|
||||
break;
|
||||
if (n_rw == 0)
|
||||
{
|
||||
errno = ZERO_BYTE_TRANSFER_ERRNO;
|
||||
break;
|
||||
}
|
||||
total_written += written;
|
||||
ptr += written;
|
||||
len -= written;
|
||||
total += n_rw;
|
||||
ptr += n_rw;
|
||||
count -= n_rw;
|
||||
}
|
||||
return total_written;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
#ifndef PARAMS
|
||||
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
|
||||
# define PARAMS(Args) Args
|
||||
# else
|
||||
# define PARAMS(Args) ()
|
||||
# endif
|
||||
#endif
|
||||
/* An interface to write() that writes all it is asked to write.
|
||||
|
||||
size_t full_write PARAMS ((int, const char *, size_t));
|
||||
Copyright (C) 2002 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. */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted
|
||||
or if partial writes occur. Return the number of bytes successfully
|
||||
written, setting errno if that is less than COUNT. */
|
||||
extern size_t full_write (int fd, const void *buf, size_t count);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%{
|
||||
/* Parse a string into an internal time stamp.
|
||||
Copyright 1999, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2000, 2002, 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
|
||||
@@ -27,11 +27,10 @@
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
/* Since the code of getdate.y is not included in the Emacs executable
|
||||
itself, there is no need to #define static in this file. Even if
|
||||
the code were included in the Emacs executable, it probably
|
||||
@@ -63,10 +62,9 @@
|
||||
- Its arg may be any int or unsigned int; it need not be an unsigned char.
|
||||
- It's guaranteed to evaluate its argument exactly once.
|
||||
- It's typically faster.
|
||||
Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
|
||||
only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
|
||||
it's important to use the locale's definition of `digit' even when the
|
||||
host does not conform to Posix. */
|
||||
POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
|
||||
ISDIGIT_LOCALE unless it's important to use the locale's definition
|
||||
of `digit' even when the host does not conform to POSIX. */
|
||||
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
|
||||
|
||||
#if STDC_HEADERS || HAVE_STRING_H
|
||||
@@ -378,19 +376,19 @@ relunit:
|
||||
| tSNUMBER tDAY_UNIT
|
||||
{ PC.rel_day += $1.value * $2; }
|
||||
| tDAY_UNIT
|
||||
{ PC.rel_day += $1 }
|
||||
{ PC.rel_day += $1; }
|
||||
| tUNUMBER tHOUR_UNIT
|
||||
{ PC.rel_hour += $1.value * $2; }
|
||||
| tSNUMBER tHOUR_UNIT
|
||||
{ PC.rel_hour += $1.value * $2; }
|
||||
| tHOUR_UNIT
|
||||
{ PC.rel_hour += $1 }
|
||||
{ PC.rel_hour += $1; }
|
||||
| tUNUMBER tMINUTE_UNIT
|
||||
{ PC.rel_minutes += $1.value * $2; }
|
||||
| tSNUMBER tMINUTE_UNIT
|
||||
{ PC.rel_minutes += $1.value * $2; }
|
||||
| tMINUTE_UNIT
|
||||
{ PC.rel_minutes += $1 }
|
||||
{ PC.rel_minutes += $1; }
|
||||
| tUNUMBER tSEC_UNIT
|
||||
{ PC.rel_seconds += $1.value * $2; }
|
||||
| tSNUMBER tSEC_UNIT
|
||||
@@ -448,6 +446,7 @@ o_merid:
|
||||
may define-away `const'. We want the prototype for get_date to have
|
||||
the same signature as the function definition. */
|
||||
#include "getdate.h"
|
||||
#include "unlocked-io.h"
|
||||
|
||||
#ifndef gmtime
|
||||
struct tm *gmtime ();
|
||||
@@ -908,7 +907,7 @@ get_date (const char *p, const time_t *now)
|
||||
pc.local_zones_seen = 0;
|
||||
pc.zones_seen = 0;
|
||||
|
||||
#if HAVE_TM_ZONE
|
||||
#if HAVE_STRUCT_TM_TM_ZONE
|
||||
pc.local_time_zone_table[0].name = tmp->tm_zone;
|
||||
pc.local_time_zone_table[0].type = tLOCAL_ZONE;
|
||||
pc.local_time_zone_table[0].value = tmp->tm_isdst;
|
||||
|
||||
69
lib/human.c
69
lib/human.c
@@ -1,5 +1,7 @@
|
||||
/* human.c -- print human readable file size
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1996, 1997, 1998, 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
|
||||
@@ -26,12 +28,19 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifndef CHAR_BIT
|
||||
# define CHAR_BIT 8
|
||||
#endif
|
||||
#if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
@@ -59,16 +68,34 @@ char *getenv ();
|
||||
static const char suffixes[] =
|
||||
{
|
||||
0, /* not used */
|
||||
'k', /* kilo */
|
||||
'M', /* Mega */
|
||||
'G', /* Giga */
|
||||
'T', /* Tera */
|
||||
'P', /* Peta */
|
||||
'E', /* Exa */
|
||||
'Z', /* Zetta */
|
||||
'Y' /* Yotta */
|
||||
'K', /* kibi ('k' for kilo is a special case) */
|
||||
'M', /* mega or mebi */
|
||||
'G', /* giga or gibi */
|
||||
'T', /* tera or tebi */
|
||||
'P', /* peta or pebi */
|
||||
'E', /* exa or exbi */
|
||||
'Z', /* zetta or 2**70 */
|
||||
'Y' /* yotta or 2**80 */
|
||||
};
|
||||
|
||||
/* Generate into P[-1] (and possibly P[-2]) the proper suffix for
|
||||
POWER and BASE. Return the address of the generated suffix. */
|
||||
static char *
|
||||
generate_suffix_backwards (char *p, int power, int base)
|
||||
{
|
||||
char letter = suffixes[power];
|
||||
|
||||
if (base == 1000)
|
||||
{
|
||||
*--p = 'B';
|
||||
if (power == 1)
|
||||
letter = 'k';
|
||||
}
|
||||
|
||||
*--p = letter;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* If INEXACT_STYLE is not human_round_to_even, and if easily
|
||||
possible, adjust VALUE according to the style. */
|
||||
static double
|
||||
@@ -106,7 +133,7 @@ human_readable (uintmax_t n, char *buf,
|
||||
Use INEXACT_STYLE to determine whether to take the ceiling or floor
|
||||
of any result that cannot be expressed exactly.
|
||||
|
||||
If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
|
||||
If OUTPUT_BLOCK_SIZE is negative, use a format like "127K" if
|
||||
possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
|
||||
ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
|
||||
1000 or 1024; it must be at least 2. Most people visually process
|
||||
@@ -114,9 +141,10 @@ human_readable (uintmax_t n, char *buf,
|
||||
more prone to misinterpretation. Hence, converting to an
|
||||
abbreviated form usually improves readability. Use a suffix
|
||||
indicating which power is being used. For example, assuming
|
||||
-OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
|
||||
-OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3K,
|
||||
133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
|
||||
than -OUTPUT_BLOCK_SIZE aren't modified. */
|
||||
than -OUTPUT_BLOCK_SIZE aren't modified. If -OUTPUT_BLOCK_SIZE is
|
||||
1024, append a "B" after any size letter. */
|
||||
|
||||
char *
|
||||
human_readable_inexact (uintmax_t n, char *buf,
|
||||
@@ -186,6 +214,8 @@ human_readable_inexact (uintmax_t n, char *buf,
|
||||
sprintf (buf, "%.0f", adjust_value (inexact_style, damt));
|
||||
else
|
||||
{
|
||||
char suffix[3];
|
||||
char const *psuffix;
|
||||
double e = 1;
|
||||
power = 0;
|
||||
|
||||
@@ -198,12 +228,13 @@ human_readable_inexact (uintmax_t n, char *buf,
|
||||
|
||||
damt /= e;
|
||||
|
||||
sprintf (buf, "%.1f%c", adjust_value (inexact_style, damt),
|
||||
suffixes[power]);
|
||||
if (4 < strlen (buf))
|
||||
sprintf (buf, "%.0f%c",
|
||||
adjust_value (inexact_style, damt * 10) / 10,
|
||||
suffixes[power]);
|
||||
suffix[2] = '\0';
|
||||
psuffix = generate_suffix_backwards (suffix + 2, power, base);
|
||||
sprintf (buf, "%.1f%s",
|
||||
adjust_value (inexact_style, damt), psuffix);
|
||||
if (4 + (base == 1000) < strlen (buf))
|
||||
sprintf (buf, "%.0f%s",
|
||||
adjust_value (inexact_style, damt * 10) / 10, psuffix);
|
||||
}
|
||||
|
||||
return buf;
|
||||
@@ -229,7 +260,7 @@ human_readable_inexact (uintmax_t n, char *buf,
|
||||
}
|
||||
while (base <= amt && power < sizeof suffixes - 1);
|
||||
|
||||
*--p = suffixes[power];
|
||||
p = generate_suffix_backwards (p, power, base);
|
||||
|
||||
if (amt < 10)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* copysym.c -- Return a copyright symbol suitable for the current locale.
|
||||
/* Print a copyright notice suitable for the current locale.
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,65 +21,37 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "print-copyr.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if HAVE_ICONV
|
||||
# include <iconv.h>
|
||||
|
||||
# if ! USE_INCLUDED_LIBINTL && HAVE_LANGINFO_CODESET
|
||||
# include <langinfo.h>
|
||||
# endif
|
||||
|
||||
# if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "copysym.h"
|
||||
|
||||
/* Store into BUF (of size BUFSIZE) a representation of the copyright
|
||||
symbol (C-in-a-circle) that is a valid text string for the current
|
||||
locale. Return BUF if successful, and a pointer to some other
|
||||
string otherwise. */
|
||||
|
||||
char const *
|
||||
copyright_symbol (char *buf, size_t bufsize)
|
||||
{
|
||||
#if HAVE_ICONV
|
||||
char const *outcharset = getenv ("OUTPUT_CHARSET");
|
||||
|
||||
if (! (outcharset && *outcharset))
|
||||
{
|
||||
#if USE_INCLUDED_LIBINTL
|
||||
extern char const *locale_charset (void);
|
||||
outcharset = locale_charset ();
|
||||
#if ENABLE_NLS
|
||||
# include "unicodeio.h"
|
||||
#else
|
||||
# if HAVE_LANGINFO_CODESET
|
||||
outcharset = nl_langinfo (CODESET);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (*outcharset)
|
||||
{
|
||||
iconv_t conv = iconv_open (outcharset, "UTF-8");
|
||||
|
||||
if (conv != (iconv_t) -1)
|
||||
{
|
||||
static char const copyright_utf_8[] = "\302\251";
|
||||
char ICONV_CONST *inptr = (char ICONV_CONST *) ©right_utf_8;
|
||||
size_t inleft = sizeof copyright_utf_8;
|
||||
char *outptr = buf;
|
||||
size_t chars = iconv (conv, &inptr, &inleft, &outptr, &bufsize);
|
||||
|
||||
iconv_close (conv);
|
||||
|
||||
if (chars != (size_t) -1)
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
# define unicode_to_mb(code, callback, error_callback, callback_arg) \
|
||||
error_callback (code, callback_arg)
|
||||
#endif
|
||||
|
||||
/* "(C)" is the best we can do in ASCII. */
|
||||
return "(C)";
|
||||
#define COPYRIGHT_SIGN 0x00A9
|
||||
|
||||
/* Print "(C)". */
|
||||
|
||||
static int
|
||||
print_parenthesized_c (unsigned int code, void *callback_arg)
|
||||
{
|
||||
FILE *stream = callback_arg;
|
||||
return fputs ("(C)", stream);
|
||||
}
|
||||
|
||||
/* Print "Copyright (C) " followed by NOTICE and then a newline,
|
||||
transliterating "(C)" to an actual copyright sign (C-in-a-circle)
|
||||
if possible. */
|
||||
|
||||
void
|
||||
print_copyright (char const *notice)
|
||||
{
|
||||
fputs ("Copyright ", stdout);
|
||||
unicode_to_mb (COPYRIGHT_SIGN, print_unicode_char, print_parenthesized_c,
|
||||
stdout);
|
||||
fputc (' ', stdout);
|
||||
puts (notice);
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
char const *copyright_symbol PARAMS((char *, size_t));
|
||||
void print_copyright PARAMS((char const *));
|
||||
|
||||
645
lib/quotearg.c
645
lib/quotearg.c
@@ -1,5 +1,5 @@
|
||||
/* quotearg.c - quote arguments for output
|
||||
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -21,21 +21,22 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_STDDEF_H
|
||||
# include <stddef.h> /* For the definition of size_t on windows w/MSVC. */
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <quotearg.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
|
||||
# define ISASCII(c) 1
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(text) gettext (text)
|
||||
#else
|
||||
# define ISASCII(c) isascii (c)
|
||||
#endif
|
||||
#ifdef isgraph
|
||||
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
|
||||
#else
|
||||
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
|
||||
# define _(text) text
|
||||
#endif
|
||||
#define N_(text) text
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
@@ -43,9 +44,21 @@
|
||||
#ifndef CHAR_BIT
|
||||
# define CHAR_BIT 8
|
||||
#endif
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
#ifndef UCHAR_MAX
|
||||
# define UCHAR_MAX ((unsigned char) -1)
|
||||
#endif
|
||||
#ifndef UINT_MAX
|
||||
# define UINT_MAX ((unsigned int) -1)
|
||||
#endif
|
||||
|
||||
#if HAVE_C_BACKSLASH_A
|
||||
# define ALERT_CHAR '\a'
|
||||
#else
|
||||
# define ALERT_CHAR '\7'
|
||||
#endif
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
@@ -55,17 +68,55 @@
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_WCHAR_H
|
||||
|
||||
/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared. */
|
||||
# include <stdio.h>
|
||||
# include <time.h>
|
||||
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
#if !HAVE_MBRTOWC
|
||||
/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the
|
||||
other macros are defined only for documentation and to satisfy C
|
||||
syntax. */
|
||||
# undef MB_CUR_MAX
|
||||
# define MB_CUR_MAX 1
|
||||
# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
|
||||
# define mbsinit(ps) 1
|
||||
# define iswprint(wc) ISPRINT ((unsigned char) (wc))
|
||||
#endif
|
||||
|
||||
#ifndef iswprint
|
||||
# if HAVE_WCTYPE_H
|
||||
# include <wctype.h>
|
||||
# endif
|
||||
# if !defined iswprint && !HAVE_ISWPRINT
|
||||
# define iswprint(wc) 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define INT_BITS (sizeof (int) * CHAR_BIT)
|
||||
|
||||
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# define IN_CTYPE_DOMAIN(c) isascii(c)
|
||||
#endif
|
||||
|
||||
/* Undefine to protect against the definition in wctype.h of solaris2.6. */
|
||||
#undef ISPRINT
|
||||
#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
|
||||
|
||||
struct quoting_options
|
||||
{
|
||||
/* Basic quoting style. */
|
||||
enum quoting_style style;
|
||||
|
||||
/* Quote the chararacters indicated by this bit vector even if the
|
||||
/* Quote the characters indicated by this bit vector even if the
|
||||
quoting style would not normally require them to be quoted. */
|
||||
int quote_these_too[((UCHAR_MAX + 1) / INT_BITS
|
||||
+ ((UCHAR_MAX + 1) % INT_BITS != 0))];
|
||||
int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
|
||||
};
|
||||
|
||||
/* Names of quoting styles. */
|
||||
@@ -76,17 +127,21 @@ char const *const quoting_style_args[] =
|
||||
"shell-always",
|
||||
"c",
|
||||
"escape",
|
||||
"locale",
|
||||
"clocale",
|
||||
0
|
||||
};
|
||||
|
||||
/* Correspondances to quoting style names. */
|
||||
/* Correspondences to quoting style names. */
|
||||
enum quoting_style const quoting_style_vals[] =
|
||||
{
|
||||
literal_quoting_style,
|
||||
shell_quoting_style,
|
||||
shell_always_quoting_style,
|
||||
c_quoting_style,
|
||||
escape_quoting_style
|
||||
escape_quoting_style,
|
||||
locale_quoting_style,
|
||||
clocale_quoting_style
|
||||
};
|
||||
|
||||
/* The default quoting options. */
|
||||
@@ -135,6 +190,335 @@ set_char_quoting (struct quoting_options *o, char c, int i)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* MSGID approximates a quotation mark. Return its translation if it
|
||||
has one; otherwise, return either it or "\"", depending on S. */
|
||||
static char const *
|
||||
gettext_quote (char const *msgid, enum quoting_style s)
|
||||
{
|
||||
char const *translation = _(msgid);
|
||||
if (translation == msgid && s == clocale_quoting_style)
|
||||
translation = "\"";
|
||||
return translation;
|
||||
}
|
||||
|
||||
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
|
||||
argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
|
||||
non-quoting-style part of O to control quoting.
|
||||
Terminate the output with a null character, and return the written
|
||||
size of the output, not counting the terminating null.
|
||||
If BUFFERSIZE is too small to store the output string, return the
|
||||
value that would have been returned had BUFFERSIZE been large enough.
|
||||
If ARGSIZE is -1, use the string length of the argument for ARGSIZE.
|
||||
|
||||
This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
|
||||
ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting
|
||||
style specified by O, and O may not be null. */
|
||||
|
||||
static size_t
|
||||
quotearg_buffer_restyled (char *buffer, size_t buffersize,
|
||||
char const *arg, size_t argsize,
|
||||
enum quoting_style quoting_style,
|
||||
struct quoting_options const *o)
|
||||
{
|
||||
size_t i;
|
||||
size_t len = 0;
|
||||
char const *quote_string = 0;
|
||||
size_t quote_string_len = 0;
|
||||
int backslash_escapes = 0;
|
||||
int unibyte_locale = MB_CUR_MAX == 1;
|
||||
|
||||
#define STORE(c) \
|
||||
do \
|
||||
{ \
|
||||
if (len < buffersize) \
|
||||
buffer[len] = (c); \
|
||||
len++; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
switch (quoting_style)
|
||||
{
|
||||
case c_quoting_style:
|
||||
STORE ('"');
|
||||
backslash_escapes = 1;
|
||||
quote_string = "\"";
|
||||
quote_string_len = 1;
|
||||
break;
|
||||
|
||||
case escape_quoting_style:
|
||||
backslash_escapes = 1;
|
||||
break;
|
||||
|
||||
case locale_quoting_style:
|
||||
case clocale_quoting_style:
|
||||
{
|
||||
/* Get translations for open and closing quotation marks.
|
||||
|
||||
The message catalog should translate "`" to a left
|
||||
quotation mark suitable for the locale, and similarly for
|
||||
"'". If the catalog has no translation,
|
||||
locale_quoting_style quotes `like this', and
|
||||
clocale_quoting_style quotes "like this".
|
||||
|
||||
For example, an American English Unicode locale should
|
||||
translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
|
||||
should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
|
||||
MARK). A British English Unicode locale should instead
|
||||
translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
|
||||
U+2019 (RIGHT SINGLE QUOTATION MARK), respectively. */
|
||||
|
||||
char const *left = gettext_quote (N_("`"), quoting_style);
|
||||
char const *right = gettext_quote (N_("'"), quoting_style);
|
||||
for (quote_string = left; *quote_string; quote_string++)
|
||||
STORE (*quote_string);
|
||||
backslash_escapes = 1;
|
||||
quote_string = right;
|
||||
quote_string_len = strlen (quote_string);
|
||||
}
|
||||
break;
|
||||
|
||||
case shell_always_quoting_style:
|
||||
STORE ('\'');
|
||||
quote_string = "'";
|
||||
quote_string_len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize); i++)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned char esc;
|
||||
|
||||
if (backslash_escapes
|
||||
&& quote_string_len
|
||||
&& i + quote_string_len <= argsize
|
||||
&& memcmp (arg + i, quote_string, quote_string_len) == 0)
|
||||
STORE ('\\');
|
||||
|
||||
c = arg[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
if (backslash_escapes)
|
||||
{
|
||||
STORE ('\\');
|
||||
STORE ('0');
|
||||
STORE ('0');
|
||||
c = '0';
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
switch (quoting_style)
|
||||
{
|
||||
case shell_quoting_style:
|
||||
goto use_shell_always_quoting_style;
|
||||
|
||||
case c_quoting_style:
|
||||
if (i + 2 < argsize && arg[i + 1] == '?')
|
||||
switch (arg[i + 2])
|
||||
{
|
||||
case '!': case '\'':
|
||||
case '(': case ')': case '-': case '/':
|
||||
case '<': case '=': case '>':
|
||||
/* Escape the second '?' in what would otherwise be
|
||||
a trigraph. */
|
||||
i += 2;
|
||||
c = arg[i + 2];
|
||||
STORE ('?');
|
||||
STORE ('\\');
|
||||
STORE ('?');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ALERT_CHAR: esc = 'a'; goto c_escape;
|
||||
case '\b': esc = 'b'; goto c_escape;
|
||||
case '\f': esc = 'f'; goto c_escape;
|
||||
case '\n': esc = 'n'; goto c_and_shell_escape;
|
||||
case '\r': esc = 'r'; goto c_and_shell_escape;
|
||||
case '\t': esc = 't'; goto c_and_shell_escape;
|
||||
case '\v': esc = 'v'; goto c_escape;
|
||||
case '\\': esc = c; goto c_and_shell_escape;
|
||||
|
||||
c_and_shell_escape:
|
||||
if (quoting_style == shell_quoting_style)
|
||||
goto use_shell_always_quoting_style;
|
||||
c_escape:
|
||||
if (backslash_escapes)
|
||||
{
|
||||
c = esc;
|
||||
goto store_escape;
|
||||
}
|
||||
break;
|
||||
|
||||
case '#': case '~':
|
||||
if (i != 0)
|
||||
break;
|
||||
/* Fall through. */
|
||||
case ' ':
|
||||
case '!': /* special in bash */
|
||||
case '"': case '$': case '&':
|
||||
case '(': case ')': case '*': case ';':
|
||||
case '<': case '>': case '[':
|
||||
case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
|
||||
case '`': case '|':
|
||||
/* A shell special character. In theory, '$' and '`' could
|
||||
be the first bytes of multibyte characters, which means
|
||||
we should check them with mbrtowc, but in practice this
|
||||
doesn't happen so it's not worth worrying about. */
|
||||
if (quoting_style == shell_quoting_style)
|
||||
goto use_shell_always_quoting_style;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
switch (quoting_style)
|
||||
{
|
||||
case shell_quoting_style:
|
||||
goto use_shell_always_quoting_style;
|
||||
|
||||
case shell_always_quoting_style:
|
||||
STORE ('\'');
|
||||
STORE ('\\');
|
||||
STORE ('\'');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%': case '+': case ',': case '-': case '.': case '/':
|
||||
case '0': case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9': case ':': case '=':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
|
||||
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
|
||||
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
|
||||
case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
|
||||
case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
|
||||
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
|
||||
case 'o': case 'p': case 'q': case 'r': case 's': case 't':
|
||||
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
|
||||
case '{': case '}':
|
||||
/* These characters don't cause problems, no matter what the
|
||||
quoting style is. They cannot start multibyte sequences. */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* If we have a multibyte sequence, copy it until we reach
|
||||
its end, find an error, or come back to the initial shift
|
||||
state. For C-like styles, if the sequence has
|
||||
unprintable characters, escape the whole sequence, since
|
||||
we can't easily escape single characters within it. */
|
||||
{
|
||||
/* Length of multibyte sequence found so far. */
|
||||
size_t m;
|
||||
|
||||
int printable;
|
||||
|
||||
if (unibyte_locale)
|
||||
{
|
||||
m = 1;
|
||||
printable = ISPRINT (c);
|
||||
}
|
||||
else
|
||||
{
|
||||
mbstate_t mbstate;
|
||||
memset (&mbstate, 0, sizeof mbstate);
|
||||
|
||||
m = 0;
|
||||
printable = 1;
|
||||
if (argsize == (size_t) -1)
|
||||
argsize = strlen (arg);
|
||||
|
||||
do
|
||||
{
|
||||
wchar_t w;
|
||||
size_t bytes = mbrtowc (&w, &arg[i + m],
|
||||
argsize - (i + m), &mbstate);
|
||||
if (bytes == 0)
|
||||
break;
|
||||
else if (bytes == (size_t) -1)
|
||||
{
|
||||
printable = 0;
|
||||
break;
|
||||
}
|
||||
else if (bytes == (size_t) -2)
|
||||
{
|
||||
printable = 0;
|
||||
while (i + m < argsize && arg[i + m])
|
||||
m++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! iswprint (w))
|
||||
printable = 0;
|
||||
m += bytes;
|
||||
}
|
||||
}
|
||||
while (! mbsinit (&mbstate));
|
||||
}
|
||||
|
||||
if (1 < m || (backslash_escapes && ! printable))
|
||||
{
|
||||
/* Output a multibyte sequence, or an escaped
|
||||
unprintable unibyte character. */
|
||||
size_t ilim = i + m;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (backslash_escapes && ! printable)
|
||||
{
|
||||
STORE ('\\');
|
||||
STORE ('0' + (c >> 6));
|
||||
STORE ('0' + ((c >> 3) & 7));
|
||||
c = '0' + (c & 7);
|
||||
}
|
||||
if (ilim <= i + 1)
|
||||
break;
|
||||
STORE (c);
|
||||
c = arg[++i];
|
||||
}
|
||||
|
||||
goto store_c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! (backslash_escapes
|
||||
&& o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
|
||||
goto store_c;
|
||||
|
||||
store_escape:
|
||||
STORE ('\\');
|
||||
|
||||
store_c:
|
||||
STORE (c);
|
||||
}
|
||||
|
||||
if (quote_string)
|
||||
for (; *quote_string; quote_string++)
|
||||
STORE (*quote_string);
|
||||
|
||||
if (len < buffersize)
|
||||
buffer[len] = '\0';
|
||||
return len;
|
||||
|
||||
use_shell_always_quoting_style:
|
||||
return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
|
||||
shell_always_quoting_style, o);
|
||||
}
|
||||
|
||||
/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
|
||||
argument ARG (of size ARGSIZE), using O to control quoting.
|
||||
If O is null, use the default.
|
||||
@@ -148,191 +532,67 @@ quotearg_buffer (char *buffer, size_t buffersize,
|
||||
char const *arg, size_t argsize,
|
||||
struct quoting_options const *o)
|
||||
{
|
||||
unsigned char c;
|
||||
size_t i;
|
||||
size_t len;
|
||||
int quote_mark;
|
||||
struct quoting_options const *p = o ? o : &default_quoting_options;
|
||||
enum quoting_style quoting_style = p->style;
|
||||
#define STORE(c) \
|
||||
do \
|
||||
{ \
|
||||
if (len < buffersize) \
|
||||
buffer[len] = (c); \
|
||||
len++; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
switch (quoting_style)
|
||||
{
|
||||
case shell_quoting_style:
|
||||
if (! (argsize == (size_t) -1 ? arg[0] == '\0' : argsize == 0))
|
||||
{
|
||||
switch (arg[0])
|
||||
{
|
||||
case '#': case '~':
|
||||
break;
|
||||
|
||||
default:
|
||||
len = 0;
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
if (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize)
|
||||
goto done;
|
||||
|
||||
c = arg[i];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\t': case '\n': case ' ':
|
||||
case '!': /* special in csh */
|
||||
case '"': case '$': case '&': case '\'':
|
||||
case '(': case ')': case '*': case ';':
|
||||
case '<': case '>': case '?': case '[': case '\\':
|
||||
case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
|
||||
case '`': case '|':
|
||||
goto needs_quoting;
|
||||
}
|
||||
|
||||
if (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))
|
||||
goto needs_quoting;
|
||||
|
||||
STORE (c);
|
||||
}
|
||||
|
||||
needs_quoting:;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case shell_always_quoting_style:
|
||||
quote_mark = '\'';
|
||||
break;
|
||||
|
||||
case c_quoting_style:
|
||||
quote_mark = '"';
|
||||
break;
|
||||
|
||||
default:
|
||||
quote_mark = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
|
||||
if (quote_mark)
|
||||
STORE (quote_mark);
|
||||
|
||||
for (i = 0; ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize); i++)
|
||||
{
|
||||
c = arg[i];
|
||||
|
||||
switch (quoting_style)
|
||||
{
|
||||
case literal_quoting_style:
|
||||
break;
|
||||
|
||||
case shell_quoting_style:
|
||||
case shell_always_quoting_style:
|
||||
if (c == '\'')
|
||||
{
|
||||
STORE ('\'');
|
||||
STORE ('\\');
|
||||
STORE ('\'');
|
||||
}
|
||||
break;
|
||||
|
||||
case c_quoting_style:
|
||||
case escape_quoting_style:
|
||||
switch (c)
|
||||
{
|
||||
case '?': /* Do not generate trigraphs. */
|
||||
case '\\': goto store_escape;
|
||||
/* Not all C compilers know what \a means. */
|
||||
case 7 : c = 'a'; goto store_escape;
|
||||
case '\b': c = 'b'; goto store_escape;
|
||||
case '\f': c = 'f'; goto store_escape;
|
||||
case '\n': c = 'n'; goto store_escape;
|
||||
case '\r': c = 'r'; goto store_escape;
|
||||
case '\t': c = 't'; goto store_escape;
|
||||
case '\v': c = 'v'; goto store_escape;
|
||||
|
||||
case '"':
|
||||
if (quoting_style == c_quoting_style)
|
||||
goto store_escape;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!ISGRAPH (c))
|
||||
{
|
||||
STORE ('\\');
|
||||
STORE ('0' + (c >> 6));
|
||||
STORE ('0' + ((c >> 3) & 7));
|
||||
c = '0' + (c & 7);
|
||||
goto store_c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (! (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
|
||||
goto store_c;
|
||||
|
||||
store_escape:
|
||||
STORE ('\\');
|
||||
}
|
||||
|
||||
store_c:
|
||||
STORE (c);
|
||||
}
|
||||
|
||||
if (quote_mark)
|
||||
STORE (quote_mark);
|
||||
|
||||
done:
|
||||
if (len < buffersize)
|
||||
buffer[len] = '\0';
|
||||
return len;
|
||||
return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
|
||||
p->style, p);
|
||||
}
|
||||
|
||||
/* Use storage slot N to return a quoted version of the string ARG.
|
||||
/* Use storage slot N to return a quoted version of argument ARG.
|
||||
ARG is of size ARGSIZE, but if that is -1, ARG is a null-terminated string.
|
||||
OPTIONS specifies the quoting options.
|
||||
The returned value points to static storage that can be
|
||||
reused by the next call to this function with the same value of N.
|
||||
N must be nonnegative. N is deliberately declared with type `int'
|
||||
N must be nonnegative. N is deliberately declared with type "int"
|
||||
to allow for future extensions (using negative values). */
|
||||
static char *
|
||||
quotearg_n_options (int n, char const *arg,
|
||||
quotearg_n_options (int n, char const *arg, size_t argsize,
|
||||
struct quoting_options const *options)
|
||||
{
|
||||
static unsigned int nslots;
|
||||
static struct slotvec
|
||||
/* Preallocate a slot 0 buffer, so that the caller can always quote
|
||||
one small component of a "memory exhausted" message in slot 0. */
|
||||
static char slot0[256];
|
||||
static unsigned int nslots = 1;
|
||||
unsigned int n0 = n;
|
||||
struct slotvec
|
||||
{
|
||||
size_t size;
|
||||
char *val;
|
||||
} *slotvec;
|
||||
};
|
||||
static struct slotvec slotvec0 = {sizeof slot0, slot0};
|
||||
static struct slotvec *slotvec = &slotvec0;
|
||||
|
||||
if (nslots <= n)
|
||||
if (n < 0)
|
||||
abort ();
|
||||
|
||||
if (nslots <= n0)
|
||||
{
|
||||
int n1 = n + 1;
|
||||
size_t s = n1 * sizeof (struct slotvec);
|
||||
if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
|
||||
abort ();
|
||||
unsigned int n1 = n0 + 1;
|
||||
size_t s = n1 * sizeof *slotvec;
|
||||
|
||||
if (SIZE_MAX / UINT_MAX <= sizeof *slotvec
|
||||
&& n1 != s / sizeof *slotvec)
|
||||
xalloc_die ();
|
||||
|
||||
if (slotvec == &slotvec0)
|
||||
{
|
||||
slotvec = (struct slotvec *) xmalloc (sizeof *slotvec);
|
||||
*slotvec = slotvec0;
|
||||
}
|
||||
slotvec = (struct slotvec *) xrealloc (slotvec, s);
|
||||
memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
|
||||
nslots = n;
|
||||
memset (slotvec + nslots, 0, (n1 - nslots) * sizeof *slotvec);
|
||||
nslots = n1;
|
||||
}
|
||||
|
||||
{
|
||||
size_t size = slotvec[n].size;
|
||||
char *val = slotvec[n].val;
|
||||
size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
|
||||
size_t qsize = quotearg_buffer (val, size, arg, argsize, options);
|
||||
|
||||
if (size <= qsize)
|
||||
{
|
||||
slotvec[n].size = size = qsize + 1;
|
||||
slotvec[n].val = val = xrealloc (val, size);
|
||||
quotearg_buffer (val, size, arg, (size_t) -1, options);
|
||||
slotvec[n].val = val = xrealloc (val == slot0 ? 0 : val, size);
|
||||
quotearg_buffer (val, size, arg, argsize, options);
|
||||
}
|
||||
|
||||
return val;
|
||||
@@ -340,9 +600,9 @@ quotearg_n_options (int n, char const *arg,
|
||||
}
|
||||
|
||||
char *
|
||||
quotearg_n (unsigned int n, char const *arg)
|
||||
quotearg_n (int n, char const *arg)
|
||||
{
|
||||
return quotearg_n_options (n, arg, &default_quoting_options);
|
||||
return quotearg_n_options (n, arg, (size_t) -1, &default_quoting_options);
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -351,13 +611,44 @@ quotearg (char const *arg)
|
||||
return quotearg_n (0, arg);
|
||||
}
|
||||
|
||||
/* Return quoting options for STYLE, with no extra quoting. */
|
||||
static struct quoting_options
|
||||
quoting_options_from_style (enum quoting_style style)
|
||||
{
|
||||
struct quoting_options o;
|
||||
o.style = style;
|
||||
memset (o.quote_these_too, 0, sizeof o.quote_these_too);
|
||||
return o;
|
||||
}
|
||||
|
||||
char *
|
||||
quotearg_n_style (int n, enum quoting_style s, char const *arg)
|
||||
{
|
||||
struct quoting_options const o = quoting_options_from_style (s);
|
||||
return quotearg_n_options (n, arg, (size_t) -1, &o);
|
||||
}
|
||||
|
||||
char *
|
||||
quotearg_n_style_mem (int n, enum quoting_style s,
|
||||
char const *arg, size_t argsize)
|
||||
{
|
||||
struct quoting_options const o = quoting_options_from_style (s);
|
||||
return quotearg_n_options (n, arg, argsize, &o);
|
||||
}
|
||||
|
||||
char *
|
||||
quotearg_style (enum quoting_style s, char const *arg)
|
||||
{
|
||||
return quotearg_n_style (0, s, arg);
|
||||
}
|
||||
|
||||
char *
|
||||
quotearg_char (char const *arg, char ch)
|
||||
{
|
||||
struct quoting_options options;
|
||||
options = default_quoting_options;
|
||||
set_char_quoting (&options, ch, 1);
|
||||
return quotearg_n_options (0, arg, &options);
|
||||
return quotearg_n_options (0, arg, (size_t) -1, &options);
|
||||
}
|
||||
|
||||
char *
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* Convert string representation of a number into an intmax_t value.
|
||||
Copyright 1999, 2001 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1999, 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
|
||||
@@ -65,7 +66,7 @@ long strtol PARAMS ((char const *, char **, int));
|
||||
# ifndef HAVE_DECL_STRTOLL
|
||||
"this configure-time declaration test was not run"
|
||||
# endif
|
||||
# if !HAVE_DECL_STRTOLL && HAVE_UNSIGNED_LONG_LONG
|
||||
# if !HAVE_DECL_STRTOLL && HAVE_LONG_LONG
|
||||
long long strtoll PARAMS ((char const *, char **, int));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
115
lib/unicodeio.c
115
lib/unicodeio.c
@@ -1,6 +1,6 @@
|
||||
/* Unicode character output to streams with locale dependent encoding.
|
||||
|
||||
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 2000-2002 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public License as published
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
/* Written by Bruno Haible <haible@clisp.cons.org>. */
|
||||
|
||||
/* Note: This file requires the locale_charset() function. See in
|
||||
libiconv-1.7/libcharset/INTEGRATE for how to obtain it. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
@@ -47,11 +50,13 @@ extern int errno;
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(Text) gettext (Text)
|
||||
#else
|
||||
# define _(Text) Text
|
||||
# define gettext(Text) Text
|
||||
#endif
|
||||
#define _(Text) gettext (Text)
|
||||
#define N_(Text) Text
|
||||
|
||||
/* Specification. */
|
||||
#include "unicodeio.h"
|
||||
|
||||
/* When we pass a Unicode character to iconv(), we must pass it in a
|
||||
@@ -106,12 +111,16 @@ utf8_wctomb (unsigned char *r, unsigned int wc)
|
||||
#define UTF8_NAME "UTF-8"
|
||||
|
||||
/* Converts the Unicode character CODE to its multibyte representation
|
||||
in the current locale and calls the CALLBACK on the resulting byte
|
||||
sequence.
|
||||
in the current locale and calls the SUCCESS callback on the resulting
|
||||
byte sequence. If an error occurs, invokes the FAILURE callback instead,
|
||||
passing it CODE and an English error string.
|
||||
Returns whatever the callback returned.
|
||||
Assumes that the locale doesn't change between two calls. */
|
||||
void
|
||||
long
|
||||
unicode_to_mb (unsigned int code,
|
||||
void (*callback) PARAMS((const char *buf, size_t buflen,
|
||||
long (*success) PARAMS ((const char *buf, size_t buflen,
|
||||
void *callback_arg)),
|
||||
long (*failure) PARAMS ((unsigned int code, const char *msg,
|
||||
void *callback_arg)),
|
||||
void *callback_arg)
|
||||
{
|
||||
@@ -135,31 +144,32 @@ unicode_to_mb (unsigned int code,
|
||||
{
|
||||
utf8_to_local = iconv_open (charset, UTF8_NAME);
|
||||
if (utf8_to_local == (iconv_t)(-1))
|
||||
{
|
||||
/* For an unknown encoding, assume ASCII. */
|
||||
utf8_to_local = iconv_open ("ASCII", UTF8_NAME);
|
||||
if (utf8_to_local == (iconv_t)(-1))
|
||||
error (1, 0,
|
||||
_("cannot convert U+%04X to local character set: iconv function not usable"),
|
||||
code);
|
||||
}
|
||||
/* For an unknown encoding, assume ASCII. */
|
||||
utf8_to_local = iconv_open ("ASCII", UTF8_NAME);
|
||||
}
|
||||
#endif
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/* Test whether the utf8_to_local converter is available at all. */
|
||||
if (!is_utf8)
|
||||
{
|
||||
#if HAVE_ICONV
|
||||
if (utf8_to_local == (iconv_t)(-1))
|
||||
return failure (code, N_("iconv function not usable"), callback_arg);
|
||||
#else
|
||||
return failure (code, N_("iconv function not available"), callback_arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Convert the character to UTF-8. */
|
||||
count = utf8_wctomb ((unsigned char *) inbuf, code);
|
||||
if (count < 0)
|
||||
error (1, 0, _("U+%04X: character out of range"), code);
|
||||
return failure (code, N_("character out of range"), callback_arg);
|
||||
|
||||
if (is_utf8)
|
||||
{
|
||||
callback (inbuf, count, callback_arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if HAVE_ICONV
|
||||
if (!is_utf8)
|
||||
{
|
||||
char outbuf[25];
|
||||
const char *inptr;
|
||||
size_t inbytesleft;
|
||||
@@ -182,8 +192,7 @@ unicode_to_mb (unsigned int code,
|
||||
|| (res > 0 && code != 0 && outptr - outbuf == 1 && *outbuf == '\0')
|
||||
# endif
|
||||
)
|
||||
error (1, res == (size_t)(-1) ? errno : 0,
|
||||
_("cannot convert U+%04X to local character set"), code);
|
||||
return failure (code, NULL, callback_arg);
|
||||
|
||||
/* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
|
||||
# if defined _LIBICONV_VERSION \
|
||||
@@ -192,33 +201,63 @@ unicode_to_mb (unsigned int code,
|
||||
/* Get back to the initial shift state. */
|
||||
res = iconv (utf8_to_local, NULL, NULL, &outptr, &outbytesleft);
|
||||
if (res == (size_t)(-1))
|
||||
error (1, errno, _("cannot convert U+%04X to local character set"),
|
||||
code);
|
||||
return failure (code, NULL, callback_arg);
|
||||
# endif
|
||||
|
||||
callback (outbuf, outptr - outbuf, callback_arg);
|
||||
#else
|
||||
error (1, 0,
|
||||
_("cannot convert U+%04X to local character set: iconv function not available"),
|
||||
code);
|
||||
#endif
|
||||
return success (outbuf, outptr - outbuf, callback_arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* At this point, is_utf8 is true, so no conversion is needed. */
|
||||
return success (inbuf, count, callback_arg);
|
||||
}
|
||||
|
||||
/* Simple callback that outputs the converted string.
|
||||
/* Simple success callback that outputs the converted string.
|
||||
The STREAM is passed as callback_arg. */
|
||||
static void
|
||||
fprintf_callback (const char *buf, size_t buflen, void *callback_arg)
|
||||
long
|
||||
fwrite_success_callback (const char *buf, size_t buflen, void *callback_arg)
|
||||
{
|
||||
FILE *stream = (FILE *) callback_arg;
|
||||
|
||||
fwrite (buf, 1, buflen, stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Simple failure callback that displays an error and exits. */
|
||||
static long
|
||||
exit_failure_callback (unsigned int code, const char *msg, void *callback_arg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
error (1, 0, _("cannot convert U+%04X to local character set"), code);
|
||||
else
|
||||
error (1, 0, _("cannot convert U+%04X to local character set: %s"), code,
|
||||
gettext (msg));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Simple failure callback that displays a fallback representation in plain
|
||||
ASCII, using the same notation as ISO C99 strings. */
|
||||
static long
|
||||
fallback_failure_callback (unsigned int code, const char *msg, void *callback_arg)
|
||||
{
|
||||
FILE *stream = (FILE *) callback_arg;
|
||||
|
||||
if (code < 0x10000)
|
||||
fprintf (stream, "\\u%04X", code);
|
||||
else
|
||||
fprintf (stream, "\\U%08X", code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Outputs the Unicode character CODE to the output stream STREAM.
|
||||
Assumes that the locale doesn't change between two calls. */
|
||||
Upon failure, exit if exit_on_error is true, otherwise output a fallback
|
||||
notation. */
|
||||
void
|
||||
print_unicode_char (FILE *stream, unsigned int code)
|
||||
print_unicode_char (FILE *stream, unsigned int code, int exit_on_error)
|
||||
{
|
||||
unicode_to_mb (code, fprintf_callback, stream);
|
||||
unicode_to_mb (code, fwrite_success_callback,
|
||||
exit_on_error
|
||||
? exit_failure_callback
|
||||
: fallback_failure_callback,
|
||||
stream);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
/* Unicode character output to streams with locale dependent encoding.
|
||||
|
||||
Copyright (C) 2000-2002 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library 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. */
|
||||
|
||||
#ifndef UNICODEIO_H
|
||||
# define UNICODEIO_H
|
||||
|
||||
@@ -11,16 +30,15 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* Converts the Unicode character CODE to its multibyte representation
|
||||
in the current locale and calls the CALLBACK on the resulting byte
|
||||
sequence. */
|
||||
extern void unicode_to_mb
|
||||
PARAMS ((unsigned int code,
|
||||
void (*callback) PARAMS ((const char *buf, size_t buflen,
|
||||
void *callback_arg)),
|
||||
void *callback_arg));
|
||||
/* Outputs the Unicode character CODE to the output stream STREAM.
|
||||
Upon failure, exit if exit_on_error is true, otherwise output a fallback
|
||||
notation. */
|
||||
extern void print_unicode_char PARAMS ((FILE *stream, unsigned int code,
|
||||
int exit_on_error));
|
||||
|
||||
/* Outputs the Unicode character CODE to the output stream STREAM. */
|
||||
extern void print_unicode_char PARAMS((FILE *stream, unsigned int code));
|
||||
/* Simple success callback that outputs the converted string.
|
||||
The STREAM is passed as callback_arg. */
|
||||
extern long fwrite_success_callback PARAMS ((const char *buf, size_t buflen,
|
||||
void *callback_arg));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
|
||||
@@ -78,19 +78,19 @@ extern int errno;
|
||||
|
||||
#include "xstrtol.h"
|
||||
|
||||
#ifndef strtol
|
||||
#if !HAVE_DECL_STRTOL && !defined strtol
|
||||
long int strtol ();
|
||||
#endif
|
||||
|
||||
#ifndef strtoul
|
||||
#if !HAVE_DECL_STRTOUL && !defined strtoul
|
||||
unsigned long int strtoul ();
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_STRTOIMAX
|
||||
#if !HAVE_DECL_STRTOIMAX && !defined strtoimax
|
||||
intmax_t strtoimax ();
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_STRTOUMAX
|
||||
#if !HAVE_DECL_STRTOUMAX && !defined strtoumax
|
||||
uintmax_t strtoumax ();
|
||||
#endif
|
||||
|
||||
|
||||
93
m4/.cvsignore
Normal file
93
m4/.cvsignore
Normal file
@@ -0,0 +1,93 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
alloca.m4
|
||||
backupfile.m4
|
||||
bison.m4
|
||||
chown.m4
|
||||
codeset.m4
|
||||
d-ino.m4
|
||||
dirname.m4
|
||||
dos.m4
|
||||
error.m4
|
||||
exclude.m4
|
||||
exitfail.m4
|
||||
extensions.m4
|
||||
fileblocks.m4
|
||||
fnmatch.m4
|
||||
ftruncate.m4
|
||||
getcwd.m4
|
||||
getdate.m4
|
||||
getline.m4
|
||||
getndelim2.m4
|
||||
getopt.m4
|
||||
gettext.m4
|
||||
glibc21.m4
|
||||
hash.m4
|
||||
human.m4
|
||||
iconv.m4
|
||||
intdiv0.m4
|
||||
intmax.m4
|
||||
intmax_t.m4
|
||||
inttypes-pri.m4
|
||||
inttypes.m4
|
||||
inttypes_h.m4
|
||||
isc-posix.m4
|
||||
lchown.m4
|
||||
lcmessage.m4
|
||||
lib-ld.m4
|
||||
lib-link.m4
|
||||
lib-prefix.m4
|
||||
longdouble.m4
|
||||
longlong.m4
|
||||
malloc.m4
|
||||
mbrtowc.m4
|
||||
mbstate_t.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
|
||||
safe-read.m4
|
||||
safe-write.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
signed.m4
|
||||
size_max.m4
|
||||
ssize_t.m4
|
||||
stdbool.m4
|
||||
stdint_h.m4
|
||||
strcase.m4
|
||||
strerror_r.m4
|
||||
strtoimax.m4
|
||||
strtol.m4
|
||||
strtoll.m4
|
||||
strtoul.m4
|
||||
strtoull.m4
|
||||
strtoumax.m4
|
||||
stpcpy.m4
|
||||
time_r.m4
|
||||
tm_gmtoff.m4
|
||||
uintmax_t.m4
|
||||
ulonglong.m4
|
||||
unlocked-io.m4
|
||||
utimbuf.m4
|
||||
utime.m4
|
||||
utimes-null.m4
|
||||
utimes.m4
|
||||
wchar_t.m4
|
||||
wint_t.m4
|
||||
xalloc.m4
|
||||
xgetcwd.m4
|
||||
xsize.m4
|
||||
xstrtol.m4
|
||||
xstrtoumax.m4
|
||||
@@ -1,34 +0,0 @@
|
||||
## Process this file with automake to produce Makefile.in -*-Makefile-*-
|
||||
|
||||
EXTRA_DIST = \
|
||||
c-bs-a.m4 \
|
||||
ccstdc.m4 \
|
||||
check-decl.m4 \
|
||||
codeset.m4 \
|
||||
d-ino.m4 \
|
||||
decl.m4 \
|
||||
error.m4 \
|
||||
fnmatch.m4 \
|
||||
getcwd.m4 \
|
||||
getline.m4 \
|
||||
gettext.m4 \
|
||||
glibc21.m4 \
|
||||
iconv.m4 \
|
||||
inttypes.m4 \
|
||||
isc-posix.m4 \
|
||||
jm-mktime.m4 \
|
||||
lcmessage.m4 \
|
||||
longlong.m4 \
|
||||
malloc.m4 \
|
||||
mbrtowc.m4 \
|
||||
mbstate_t.m4 \
|
||||
prereq.m4 \
|
||||
progtest.m4 \
|
||||
realloc.m4 \
|
||||
strerror_r.m4 \
|
||||
ulonglong.m4 \
|
||||
utimbuf.m4 \
|
||||
utime.m4 \
|
||||
utimes.m4 \
|
||||
xstrtoimax.m4 \
|
||||
xstrtoumax.m4
|
||||
@@ -1,4 +1,4 @@
|
||||
#serial 1
|
||||
#serial 2
|
||||
dnl Cloned from xstrtoumax.m4. Keep these files in sync.
|
||||
|
||||
# autoconf tests required for use of xstrtoimax.c
|
||||
@@ -9,7 +9,7 @@ AC_DEFUN([jm_AC_PREREQ_XSTRTOIMAX],
|
||||
AC_REQUIRE([jm_AC_TYPE_UINTMAX_T])
|
||||
AC_REQUIRE([jm_AC_TYPE_LONG_LONG])
|
||||
AC_REQUIRE([jm_AC_TYPE_UNSIGNED_LONG_LONG])
|
||||
AC_CHECK_DECLS([strtol, strtoll, strtoimax])
|
||||
AC_CHECK_DECLS([strtol, strtoul, strtoll, strtoimax, strtoumax])
|
||||
AC_CHECK_HEADERS(limits.h stdlib.h inttypes.h)
|
||||
|
||||
AC_CACHE_CHECK([whether <inttypes.h> defines strtoimax as a macro],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#serial 3
|
||||
#serial 4
|
||||
|
||||
# autoconf tests required for use of xstrtoumax.c
|
||||
|
||||
@@ -8,7 +8,7 @@ AC_DEFUN([jm_AC_PREREQ_XSTRTOUMAX],
|
||||
AC_REQUIRE([jm_AC_TYPE_UINTMAX_T])
|
||||
AC_REQUIRE([jm_AC_TYPE_LONG_LONG])
|
||||
AC_REQUIRE([jm_AC_TYPE_UNSIGNED_LONG_LONG])
|
||||
AC_CHECK_DECLS([strtoul, strtoull, strtoumax])
|
||||
AC_CHECK_DECLS([strtol, strtoul, strtoull, strtoimax, strtoumax])
|
||||
AC_CHECK_HEADERS(limits.h stdlib.h inttypes.h)
|
||||
|
||||
AC_CACHE_CHECK([whether <inttypes.h> defines strtoumax as a macro],
|
||||
|
||||
20
po/.cvsignore
Normal file
20
po/.cvsignore
Normal file
@@ -0,0 +1,20 @@
|
||||
index.html
|
||||
*.po
|
||||
LINGUAS
|
||||
Makefile.in.in
|
||||
Makevars.template
|
||||
Rules-quot
|
||||
boldquot.sed
|
||||
en@boldquot.header
|
||||
en@quot.header
|
||||
insert-header.sin
|
||||
quot.sed
|
||||
remove-potcdate.sin
|
||||
Makefile.in
|
||||
POTFILES
|
||||
Makefile
|
||||
tar.pot
|
||||
remove-potcdate.sed
|
||||
*.gmo
|
||||
*.mo
|
||||
stamp-po
|
||||
41
po/Makevars
Normal file
41
po/Makevars
Normal file
@@ -0,0 +1,41 @@
|
||||
# Makefile variables for PO directory in any package using GNU gettext.
|
||||
|
||||
# Usually the message domain is the same as the package name.
|
||||
DOMAIN = $(PACKAGE)
|
||||
|
||||
# These two variables depend on the location of this directory.
|
||||
subdir = po
|
||||
top_builddir = ..
|
||||
|
||||
# These options get passed to xgettext.
|
||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
|
||||
|
||||
# This is the copyright holder that gets inserted into the header of the
|
||||
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
|
||||
# package. (Note that the msgstr strings, extracted from the package's
|
||||
# sources, belong to the copyright holder of the package.) Translators are
|
||||
# expected to transfer the copyright for their translations to this person
|
||||
# or entity, or to disclaim their copyright. The empty string stands for
|
||||
# the public domain; in this case the translators are expected to disclaim
|
||||
# their copyright.
|
||||
COPYRIGHT_HOLDER = Free Software Foundation, Inc.
|
||||
|
||||
# This is the email address or URL to which the translators shall report
|
||||
# bugs in the untranslated strings:
|
||||
# - Strings which are not entire sentences, see the maintainer guidelines
|
||||
# in the GNU gettext documentation, section 'Preparing Strings'.
|
||||
# - Strings which use unclear terms or require additional context to be
|
||||
# understood.
|
||||
# - Strings which make invalid assumptions about notation of date, time or
|
||||
# money.
|
||||
# - Pluralisation problems.
|
||||
# - Incorrect English spelling.
|
||||
# - Incorrect formatting.
|
||||
# It can be your email address, or a mailing list address where translators
|
||||
# can write to without being subscribed, or the URL of a web page through
|
||||
# which the translators can contact you.
|
||||
MSGID_BUGS_ADDRESS = bug-tar@gnu.org
|
||||
|
||||
# This is the list of locale categories, beyond LC_MESSAGES, for which the
|
||||
# message catalogs shall be used. It is usually empty.
|
||||
EXTRA_LOCALE_CATEGORIES =
|
||||
@@ -1,14 +1,31 @@
|
||||
# List of files which contain translatable strings.
|
||||
# Copyright 1996, 1999 Free Software Foundation, Inc.
|
||||
|
||||
# Copyright (C) 1996, 1999, 2000, 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.
|
||||
|
||||
# Library files
|
||||
lib/argmatch.c
|
||||
lib/error.c
|
||||
lib/getopt.c
|
||||
lib/human.c
|
||||
lib/quotearg.c
|
||||
lib/xmalloc.c
|
||||
|
||||
# Package source files
|
||||
src/arith.c
|
||||
src/buffer.c
|
||||
src/common.h
|
||||
src/compare.c
|
||||
@@ -24,6 +41,4 @@ src/rmt.c
|
||||
src/rtapelib.c
|
||||
src/tar.c
|
||||
src/update.c
|
||||
|
||||
# Checking tools
|
||||
tests/genfile.c
|
||||
src/xheader.c
|
||||
|
||||
2
scripts/.cvsignore
Normal file
2
scripts/.cvsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
@@ -1,5 +1,6 @@
|
||||
# Makefile for GNU tar scripts.
|
||||
# Copyright (C) 1994 Free Software Foundation, Inc.
|
||||
|
||||
# Copyright (C) 1994, 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
|
||||
@@ -15,6 +16,4 @@
|
||||
## along with this program; if not, write to the Free Software Foundation,
|
||||
## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits
|
||||
|
||||
EXTRA_DIST = WARNING backup-specs dump-remind level-0 level-1 weekly.new
|
||||
|
||||
6
src/.cvsignore
Normal file
6
src/.cvsignore
Normal file
@@ -0,0 +1,6 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
localedir.h
|
||||
rmt
|
||||
tar
|
||||
.deps
|
||||
@@ -1,51 +1,57 @@
|
||||
# Makefile for GNU tar sources.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997 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.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
## This 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.
|
||||
|
||||
# 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.
|
||||
## 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.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits ansi2knr
|
||||
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
|
||||
tar_SOURCES = arith.c buffer.c compare.c create.c delete.c extract.c \
|
||||
incremen.c list.c mangle.c misc.c names.c open3.c rtapelib.c tar.c update.c
|
||||
tar_SOURCES = \
|
||||
buffer.c\
|
||||
compare.c\
|
||||
create.c\
|
||||
delete.c\
|
||||
extract.c\
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
list.c\
|
||||
mangle.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
rtapelib.c\
|
||||
sparse.c\
|
||||
system.c\
|
||||
tar.c\
|
||||
update.c\
|
||||
utf8.c
|
||||
|
||||
INCLUDES = -I../intl -I$(top_srcdir)/lib
|
||||
LDADD = ../lib/libtar.a @INTLLIBS@
|
||||
localedir = $(prefix)/@DATADIRNAME@/locale
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I$(top_srcdir)/lib -I../lib
|
||||
|
||||
tar.o: tar.c
|
||||
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c $(srcdir)/tar.c
|
||||
DISTCLEANFILES = localedir.h
|
||||
localedir.h : Makefile
|
||||
echo '#define LOCALEDIR "$(localedir)"' >$@
|
||||
rmt.o tar.o : localedir.h
|
||||
|
||||
tar._o: tar._c
|
||||
@rm -f _tar.c
|
||||
@ln tar._c _tar.c
|
||||
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c _tar.c
|
||||
@mv _tar.o $@
|
||||
@rm _tar.c
|
||||
LDADD = ../lib/libtar.a $(LIBINTL)
|
||||
|
||||
rmt.o: rmt.c
|
||||
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c $(srcdir)/rmt.c
|
||||
|
||||
rmt._o: rmt._c
|
||||
@rm -f _rmt.c
|
||||
@ln rmt._c _rmt.c
|
||||
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c _rmt.c
|
||||
@mv _rmt.o $@
|
||||
@rm _rmt.c
|
||||
rmt_LDADD = $(LDADD) $(LIB_SETSOCKOPT)
|
||||
tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
|
||||
835
src/buffer.c
835
src/buffer.c
File diff suppressed because it is too large
Load Diff
569
src/common.h
569
src/common.h
@@ -1,5 +1,7 @@
|
||||
/* Common declarations for the tar program.
|
||||
Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 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
|
||||
@@ -13,7 +15,7 @@
|
||||
|
||||
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 Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Declare the GNU tar archive format. */
|
||||
#include "tar.h"
|
||||
@@ -27,19 +29,11 @@
|
||||
#define UNAME_FIELD_SIZE 32
|
||||
#define GNAME_FIELD_SIZE 32
|
||||
|
||||
/* POSIX specified symbols currently unused are undefined here. */
|
||||
#undef TSUID
|
||||
#undef TSGID
|
||||
#undef TSVTX
|
||||
#undef TUREAD
|
||||
#undef TUWRITE
|
||||
#undef TUEXEC
|
||||
#undef TGREAD
|
||||
#undef TGWRITE
|
||||
#undef TGEXEC
|
||||
#undef TOREAD
|
||||
#undef TOWRITE
|
||||
#undef TOEXEC
|
||||
/* FIXME */
|
||||
#define MAXOCTAL11 017777777777L
|
||||
#define MAXOCTAL7 07777777
|
||||
|
||||
|
||||
|
||||
/* Some various global definitions. */
|
||||
|
||||
@@ -50,10 +44,10 @@
|
||||
# define TTY_NAME "/dev/tty"
|
||||
#endif
|
||||
|
||||
/* GLOBAL is defined to empty in `tar.c' only, and left alone in other `*.c'
|
||||
/* 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.
|
||||
GNU tar does depend on the system loader to preset all GLOBAL variables to
|
||||
neutral (or zero) values, explicit initialisation is usually not done. */
|
||||
neutral (or zero) values, explicit initialization is usually not done. */
|
||||
#ifndef GLOBAL
|
||||
# define GLOBAL extern
|
||||
#endif
|
||||
@@ -72,24 +66,33 @@ GLOBAL int exit_status;
|
||||
writes a message on stderr and aborts immediately, with another message
|
||||
line telling so. USAGE_ERROR works like FATAL_ERROR except that the
|
||||
other message line suggests trying --help. All four macros accept a
|
||||
single argument of the form ((0, errno, _("FORMAT"), Args...)). `errno'
|
||||
is `0' when the error is not being detected by the system. */
|
||||
single argument of the form ((0, errno, _("FORMAT"), Args...)). errno
|
||||
is zero when the error is not being detected by the system. */
|
||||
|
||||
#define WARN(Args) \
|
||||
error Args
|
||||
#define ERROR(Args) \
|
||||
(error Args, exit_status = TAREXIT_FAILURE)
|
||||
#define FATAL_ERROR(Args) \
|
||||
(error Args, error (TAREXIT_FAILURE, 0, \
|
||||
_("Error is not recoverable: exiting now")), 0)
|
||||
(error Args, fatal_exit ())
|
||||
#define USAGE_ERROR(Args) \
|
||||
(error Args, usage (TAREXIT_FAILURE), 0)
|
||||
(error Args, usage (TAREXIT_FAILURE))
|
||||
|
||||
#include "arith.h"
|
||||
#include <backupfile.h>
|
||||
#include <exclude.h>
|
||||
#include <full-write.h>
|
||||
#include <modechange.h>
|
||||
#include <quote.h>
|
||||
#include <safe-read.h>
|
||||
|
||||
/* Log base 2 of common values. */
|
||||
#define LG_8 3
|
||||
#define LG_64 6
|
||||
#define LG_256 8
|
||||
|
||||
/* Information gleaned from the command line. */
|
||||
|
||||
#include "arith.h"
|
||||
#include "modechange.h"
|
||||
|
||||
/* Name of this program. */
|
||||
GLOBAL const char *program_name;
|
||||
|
||||
@@ -121,10 +124,9 @@ GLOBAL char filename_terminator;
|
||||
not have _option in their name, even if their values is derived from
|
||||
option decoding, as these are especially important in tar. */
|
||||
GLOBAL int blocking_factor;
|
||||
GLOBAL int record_size;
|
||||
GLOBAL size_t record_size;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int absolute_names_option;
|
||||
GLOBAL bool absolute_names_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.
|
||||
@@ -132,54 +134,60 @@ GLOBAL int absolute_names_option;
|
||||
than newer_mtime_option. */
|
||||
GLOBAL int after_date_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int atime_preserve_option;
|
||||
GLOBAL bool atime_preserve_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int backup_option;
|
||||
GLOBAL bool backup_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int block_number_option;
|
||||
/* Type of backups being made. */
|
||||
GLOBAL enum backup_type backup_type;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int checkpoint_option;
|
||||
GLOBAL bool block_number_option;
|
||||
|
||||
GLOBAL bool checkpoint_option;
|
||||
|
||||
/* Specified name of compression program, or "gzip" as implied by -z. */
|
||||
GLOBAL const char *use_compress_program_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int dereference_option;
|
||||
GLOBAL bool dereference_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int exclude_option;
|
||||
/* Print a message if not all links are dumped */
|
||||
GLOBAL int check_links_option;
|
||||
|
||||
/* Patterns that match file names to be excluded. */
|
||||
GLOBAL struct exclude *excluded;
|
||||
|
||||
/* Specified file containing names to work on. */
|
||||
GLOBAL const char *files_from_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int force_local_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;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int ignore_failed_read_option;
|
||||
GLOBAL bool ignore_failed_read_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int ignore_zeros_option;
|
||||
GLOBAL bool ignore_zeros_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int incremental_option;
|
||||
GLOBAL bool incremental_option;
|
||||
|
||||
/* Specified name of script to run at end of each tape change. */
|
||||
GLOBAL const char *info_script_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int interactive_option;
|
||||
GLOBAL bool interactive_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int keep_old_files_option;
|
||||
/* If nonzero, extract only Nth occurrence of each named file */
|
||||
GLOBAL uintmax_t occurrence_option;
|
||||
|
||||
enum old_files
|
||||
{
|
||||
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 */
|
||||
};
|
||||
GLOBAL enum old_files old_files_option;
|
||||
|
||||
/* Specified file name for incremental list. */
|
||||
GLOBAL const char *listed_incremental_option;
|
||||
@@ -187,83 +195,69 @@ GLOBAL const char *listed_incremental_option;
|
||||
/* Specified mode change string. */
|
||||
GLOBAL struct mode_change *mode_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int multi_volume_option;
|
||||
GLOBAL bool multi_volume_option;
|
||||
|
||||
/* The same variable hold 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 a more recent timestamp
|
||||
get archived (also see after_date_option above). If left to zero, it may
|
||||
be interpreted as very low threshold, just usable as such. */
|
||||
/* 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;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int no_recurse_option;
|
||||
/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
|
||||
GLOBAL int recursion_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int numeric_owner_option;
|
||||
GLOBAL bool numeric_owner_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int one_file_system_option;
|
||||
GLOBAL bool one_file_system_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 uid_t owner_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int recursive_unlink_option;
|
||||
GLOBAL bool recursive_unlink_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int read_full_records_option;
|
||||
GLOBAL bool read_full_records_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int remove_files_option;
|
||||
GLOBAL bool remove_files_option;
|
||||
|
||||
/* Specified remote shell command. */
|
||||
GLOBAL const char *rsh_command_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int same_order_option;
|
||||
GLOBAL bool same_order_option;
|
||||
|
||||
/* Boolean value. */
|
||||
/* If positive, preserve ownership when extracting. */
|
||||
GLOBAL int same_owner_option;
|
||||
|
||||
/* Boolean value. */
|
||||
/* If positive, preserve permissions when extracting. */
|
||||
GLOBAL int same_permissions_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int show_omitted_dirs_option;
|
||||
/* When set, strip the given number of path elements from the file name
|
||||
before extracting */
|
||||
GLOBAL size_t strip_path_elements;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int sparse_option;
|
||||
GLOBAL bool show_omitted_dirs_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int starting_file_option;
|
||||
GLOBAL bool sparse_option;
|
||||
|
||||
GLOBAL bool starting_file_option;
|
||||
|
||||
/* Specified maximum byte length of each tape volume (multiple of 1024). */
|
||||
GLOBAL tarlong tape_length_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int to_stdout_option;
|
||||
GLOBAL bool to_stdout_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int totals_option;
|
||||
GLOBAL bool totals_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int touch_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int unlink_first_option;
|
||||
GLOBAL bool touch_option;
|
||||
|
||||
/* Count how many times the option has been set, multiple setting yields
|
||||
more verbose behavior. Value 0 means no verbosity, 1 means file name
|
||||
only, 2 means file name and all attributes. More than 2 is just like 2. */
|
||||
GLOBAL int verbose_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int verify_option;
|
||||
GLOBAL bool verify_option;
|
||||
|
||||
/* Specified name of file containing the volume number. */
|
||||
GLOBAL const char *volno_file_option;
|
||||
@@ -277,13 +271,17 @@ GLOBAL const char *volume_label_option;
|
||||
GLOBAL int archive;
|
||||
|
||||
/* Nonzero when outputting to /dev/null. */
|
||||
GLOBAL int dev_null_output;
|
||||
GLOBAL bool dev_null_output;
|
||||
|
||||
/* Name of file for the current archive entry. */
|
||||
GLOBAL char *current_file_name;
|
||||
/* Timestamp for when we started execution. */
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
GLOBAL struct timespec start_timespec;
|
||||
# define start_time (start_timespec.tv_sec)
|
||||
#else
|
||||
GLOBAL time_t start_time;
|
||||
#endif
|
||||
|
||||
/* Name of link for the current archive entry. */
|
||||
GLOBAL char *current_link_name;
|
||||
GLOBAL struct tar_stat_info current_stat_info;
|
||||
|
||||
/* List of tape drive names, number of such tape drives, allocated number,
|
||||
and current cursor in list. */
|
||||
@@ -292,32 +290,29 @@ GLOBAL int archive_names;
|
||||
GLOBAL int allocated_archive_names;
|
||||
GLOBAL const char **archive_name_cursor;
|
||||
|
||||
/* Output index file name. */
|
||||
GLOBAL char const *index_file_name;
|
||||
|
||||
/* Structure for keeping track of filenames and lists thereof. */
|
||||
struct name
|
||||
{
|
||||
struct name *next;
|
||||
short length; /* cached strlen(name) */
|
||||
char found; /* a matching file has been found */
|
||||
size_t length; /* cached strlen(name) */
|
||||
uintmax_t found_count; /* number of times a matching file has
|
||||
been found */
|
||||
int isdir;
|
||||
char firstch; /* first char is literally matched */
|
||||
char regexp; /* this name is a regexp, not literal */
|
||||
char *change_dir; /* set with the -C option */
|
||||
char *dir_contents; /* for incremental_option */
|
||||
int change_dir; /* set with the -C option */
|
||||
char const *dir_contents; /* for incremental_option */
|
||||
char fake; /* dummy entry */
|
||||
char name[1];
|
||||
};
|
||||
GLOBAL struct name *namelist; /* points to first name in list */
|
||||
GLOBAL struct name *namelast; /* points to last name in list */
|
||||
|
||||
/* Pointer to the start of the scratch space. */
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
int numbytes;
|
||||
};
|
||||
GLOBAL struct sp_array *sparsearray;
|
||||
/* Obnoxious test to see if dimwit is trying to dump the archive. */
|
||||
GLOBAL dev_t ar_dev;
|
||||
GLOBAL ino_t ar_ino;
|
||||
|
||||
/* Initial size of the sparsearray. */
|
||||
GLOBAL int sp_array_size;
|
||||
|
||||
/* Declarations for each module. */
|
||||
|
||||
@@ -336,58 +331,98 @@ extern enum access_mode access_mode;
|
||||
|
||||
extern FILE *stdlis;
|
||||
extern char *save_name;
|
||||
extern long save_sizeleft;
|
||||
extern long save_totsize;
|
||||
extern int write_archive_to_stdout;
|
||||
extern off_t save_sizeleft;
|
||||
extern off_t save_totsize;
|
||||
extern bool write_archive_to_stdout;
|
||||
|
||||
int available_space_after PARAMS ((union block *));
|
||||
long current_block_ordinal PARAMS ((void));
|
||||
void close_archive PARAMS ((void));
|
||||
void closeout_volume_number PARAMS ((void));
|
||||
union block *find_next_block PARAMS ((void));
|
||||
void flush_read PARAMS ((void));
|
||||
void flush_write PARAMS ((void));
|
||||
void flush_archive PARAMS ((void));
|
||||
void init_total_written PARAMS ((void));
|
||||
void init_volume_number PARAMS ((void));
|
||||
void open_archive PARAMS ((enum access_mode));
|
||||
void print_total_written PARAMS ((void));
|
||||
void reset_eof PARAMS ((void));
|
||||
void set_next_block_after PARAMS ((union block *));
|
||||
size_t available_space_after (union block *);
|
||||
off_t current_block_ordinal (void);
|
||||
void close_archive (void);
|
||||
void closeout_volume_number (void);
|
||||
union block *find_next_block (void);
|
||||
void flush_read (void);
|
||||
void flush_write (void);
|
||||
void flush_archive (void);
|
||||
void init_volume_number (void);
|
||||
void open_archive (enum access_mode);
|
||||
void print_total_written (void);
|
||||
void reset_eof (void);
|
||||
void set_next_block_after (union block *);
|
||||
void clear_read_error_count (void);
|
||||
void xclose (int fd);
|
||||
void archive_write_error (ssize_t) __attribute__ ((noreturn));
|
||||
void archive_read_error (void);
|
||||
|
||||
/* Module create.c. */
|
||||
|
||||
void create_archive PARAMS ((void));
|
||||
void dump_file PARAMS ((char *, int, int));
|
||||
void finish_header PARAMS ((union block *));
|
||||
void to_oct PARAMS ((long, int, char *));
|
||||
void write_eot PARAMS ((void));
|
||||
enum dump_status
|
||||
{
|
||||
dump_status_ok,
|
||||
dump_status_short,
|
||||
dump_status_fail,
|
||||
dump_status_not_implemented
|
||||
};
|
||||
|
||||
bool file_dumpable_p (struct tar_stat_info *stat);
|
||||
void create_archive (void);
|
||||
void pad_archive (off_t size_left);
|
||||
void dump_file (char *, int, dev_t);
|
||||
union block *start_header (struct tar_stat_info *st);
|
||||
void finish_header (struct tar_stat_info *, union block *, off_t);
|
||||
void simple_finish_header (union block *header);
|
||||
union block *start_private_header (const char *name, size_t size);
|
||||
void write_eot (void);
|
||||
void check_links (void);
|
||||
|
||||
#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
|
||||
#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
|
||||
#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
|
||||
#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
|
||||
#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
|
||||
#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where))
|
||||
#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
|
||||
#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
|
||||
#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
|
||||
#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf))
|
||||
|
||||
void gid_to_chars (gid_t, char *, size_t);
|
||||
void major_to_chars (major_t, char *, size_t);
|
||||
void minor_to_chars (minor_t, char *, size_t);
|
||||
void mode_to_chars (mode_t, char *, size_t);
|
||||
void off_to_chars (off_t, char *, size_t);
|
||||
void size_to_chars (size_t, char *, size_t);
|
||||
void time_to_chars (time_t, char *, size_t);
|
||||
void uid_to_chars (uid_t, char *, size_t);
|
||||
void uintmax_to_chars (uintmax_t, char *, size_t);
|
||||
void string_to_chars (char *, char *, size_t);
|
||||
|
||||
/* Module diffarch.c. */
|
||||
|
||||
extern int now_verifying;
|
||||
extern bool now_verifying;
|
||||
|
||||
void diff_archive PARAMS ((void));
|
||||
void diff_init PARAMS ((void));
|
||||
void verify_volume PARAMS ((void));
|
||||
void diff_archive (void);
|
||||
void diff_init (void);
|
||||
void verify_volume (void);
|
||||
|
||||
/* Module extract.c. */
|
||||
|
||||
void extr_init PARAMS ((void));
|
||||
void extract_archive PARAMS ((void));
|
||||
void apply_delayed_set_stat PARAMS ((void));
|
||||
extern bool we_are_root;
|
||||
void extr_init (void);
|
||||
void extract_archive (void);
|
||||
void extract_finish (void);
|
||||
void fatal_exit (void) __attribute__ ((noreturn));
|
||||
|
||||
/* Module delete.c. */
|
||||
|
||||
void delete_archive_members PARAMS ((void));
|
||||
void delete_archive_members (void);
|
||||
|
||||
/* Module incremen.c. */
|
||||
|
||||
void collect_and_sort_names PARAMS ((void));
|
||||
char *get_directory_contents PARAMS ((char *, int));
|
||||
void write_dir_file PARAMS ((void));
|
||||
void gnu_restore PARAMS ((int));
|
||||
void write_directory_file PARAMS ((void));
|
||||
char *get_directory_contents (char *, dev_t);
|
||||
void read_directory_file (void);
|
||||
void write_directory_file (void);
|
||||
void gnu_restore (char const *);
|
||||
|
||||
/* Module list.c. */
|
||||
|
||||
@@ -395,77 +430,227 @@ enum read_header
|
||||
{
|
||||
HEADER_STILL_UNREAD, /* for when read_header has not been called */
|
||||
HEADER_SUCCESS, /* header successfully read and checksummed */
|
||||
HEADER_SUCCESS_EXTENDED, /* likewise, but we got an extended header */
|
||||
HEADER_ZERO_BLOCK, /* zero block where header expected */
|
||||
HEADER_END_OF_FILE, /* true end of file while header expected */
|
||||
HEADER_FAILURE /* ill-formed header, or bad checksum */
|
||||
};
|
||||
|
||||
extern union block *current_header;
|
||||
extern struct stat current_stat;
|
||||
extern enum archive_format current_format;
|
||||
struct xheader
|
||||
{
|
||||
struct obstack *stk;
|
||||
size_t size;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
void decode_header PARAMS ((union block *, struct stat *,
|
||||
enum archive_format *, int));
|
||||
long from_oct PARAMS ((int, char *));
|
||||
void list_archive PARAMS ((void));
|
||||
void print_for_mkdir PARAMS ((char *, int, int));
|
||||
void print_header PARAMS ((void));
|
||||
void read_and PARAMS ((void (*do_) ()));
|
||||
enum read_header read_header PARAMS ((void));
|
||||
void skip_extended_headers PARAMS ((void));
|
||||
void skip_file PARAMS ((long));
|
||||
GLOBAL struct xheader extended_header;
|
||||
extern union block *current_header;
|
||||
extern enum archive_format current_format;
|
||||
extern size_t recent_long_name_blocks;
|
||||
extern size_t recent_long_link_blocks;
|
||||
|
||||
void decode_header (union block *, struct tar_stat_info *,
|
||||
enum archive_format *, int);
|
||||
#define STRINGIFY_BIGINT(i, b) \
|
||||
stringify_uintmax_t_backwards ((uintmax_t) (i), (b) + UINTMAX_STRSIZE_BOUND)
|
||||
char *stringify_uintmax_t_backwards (uintmax_t, char *);
|
||||
char const *tartime (time_t);
|
||||
|
||||
#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
|
||||
#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
|
||||
#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
|
||||
#define MODE_FROM_HEADER(where) mode_from_header (where, sizeof (where))
|
||||
#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
|
||||
#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where))
|
||||
#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
|
||||
#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
|
||||
#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
|
||||
|
||||
gid_t gid_from_header (const char *, size_t);
|
||||
major_t major_from_header (const char *, size_t);
|
||||
minor_t minor_from_header (const char *, size_t);
|
||||
mode_t mode_from_header (const char *, size_t);
|
||||
off_t off_from_header (const char *, size_t);
|
||||
size_t size_from_header (const char *, size_t);
|
||||
time_t time_from_header (const char *, size_t);
|
||||
uid_t uid_from_header (const char *, size_t);
|
||||
uintmax_t uintmax_from_header (const char *, size_t);
|
||||
|
||||
void list_archive (void);
|
||||
void print_for_mkdir (char *, int, mode_t);
|
||||
void print_header (struct tar_stat_info *, off_t);
|
||||
void read_and (void (*) (void));
|
||||
enum read_header read_header (bool);
|
||||
void skip_file (off_t);
|
||||
void skip_member (void);
|
||||
|
||||
/* Module mangle.c. */
|
||||
|
||||
void extract_mangle PARAMS ((void));
|
||||
void extract_mangle (void);
|
||||
|
||||
/* Module misc.c. */
|
||||
|
||||
void assign_string PARAMS ((char **, const char *));
|
||||
char *quote_copy_string PARAMS ((const char *));
|
||||
int unquote_string PARAMS ((char *));
|
||||
void assign_string (char **, const char *);
|
||||
char *quote_copy_string (const char *);
|
||||
int unquote_string (char *);
|
||||
|
||||
char *merge_sort PARAMS ((char *, int, int, int (*) (char *, char *)));
|
||||
size_t dot_dot_prefix_len (char const *);
|
||||
|
||||
int is_dot_or_dotdot PARAMS ((const char *));
|
||||
int remove_any_file PARAMS ((const char *, int));
|
||||
int maybe_backup_file PARAMS ((const char *, int));
|
||||
void undo_last_backup PARAMS ((void));
|
||||
enum remove_option
|
||||
{
|
||||
ORDINARY_REMOVE_OPTION,
|
||||
RECURSIVE_REMOVE_OPTION,
|
||||
WANT_DIRECTORY_REMOVE_OPTION
|
||||
};
|
||||
int remove_any_file (const char *, enum remove_option);
|
||||
bool maybe_backup_file (const char *, int);
|
||||
void undo_last_backup (void);
|
||||
|
||||
int deref_stat (bool, char const *, struct stat *);
|
||||
|
||||
int chdir_arg (char const *);
|
||||
void chdir_do (int);
|
||||
|
||||
void decode_mode (mode_t, char *);
|
||||
|
||||
void chdir_fatal (char const *) __attribute__ ((noreturn));
|
||||
void chmod_error_details (char const *, mode_t);
|
||||
void chown_error_details (char const *, uid_t, gid_t);
|
||||
void close_error (char const *);
|
||||
void close_warn (char const *);
|
||||
void close_diag (char const *name);
|
||||
void exec_fatal (char const *) __attribute__ ((noreturn));
|
||||
void link_error (char const *, char const *);
|
||||
void mkdir_error (char const *);
|
||||
void mkfifo_error (char const *);
|
||||
void mknod_error (char const *);
|
||||
void open_error (char const *);
|
||||
void open_fatal (char const *) __attribute__ ((noreturn));
|
||||
void open_warn (char const *);
|
||||
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_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 *);
|
||||
void readlink_warn (char const *);
|
||||
void readlink_diag (char const *name);
|
||||
void savedir_error (char const *);
|
||||
void savedir_warn (char const *);
|
||||
void savedir_diag (char const *name);
|
||||
void seek_error (char const *);
|
||||
void seek_error_details (char const *, off_t);
|
||||
void seek_warn (char const *);
|
||||
void seek_warn_details (char const *, off_t);
|
||||
void seek_diag_details (char const *, off_t);
|
||||
void stat_error (char const *);
|
||||
void stat_warn (char const *);
|
||||
void stat_diag (char const *name);
|
||||
void symlink_error (char const *, char const *);
|
||||
void truncate_error (char const *);
|
||||
void truncate_warn (char const *);
|
||||
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_fatal (char const *) __attribute__ ((noreturn));
|
||||
void write_fatal_details (char const *, ssize_t, size_t)
|
||||
__attribute__ ((noreturn));
|
||||
|
||||
pid_t xfork (void);
|
||||
void xpipe (int[2]);
|
||||
|
||||
/* Module names.c. */
|
||||
|
||||
void gid_to_gname PARAMS ((gid_t, char gname[GNAME_FIELD_SIZE]));
|
||||
int gname_to_gid PARAMS ((char gname[GNAME_FIELD_SIZE], gid_t *));
|
||||
void uid_to_uname PARAMS ((uid_t, char uname[UNAME_FIELD_SIZE]));
|
||||
int uname_to_uid PARAMS ((char uname[UNAME_FIELD_SIZE], uid_t *));
|
||||
extern struct name *gnu_list_name;
|
||||
|
||||
void init_names PARAMS ((void));
|
||||
void name_add PARAMS ((const char *));
|
||||
void name_init PARAMS ((int, char *const *));
|
||||
void name_term PARAMS ((void));
|
||||
char *name_next PARAMS ((int change_));
|
||||
void name_close PARAMS ((void));
|
||||
void name_gather PARAMS ((void));
|
||||
void addname PARAMS ((const char *));
|
||||
int name_match PARAMS ((const char *));
|
||||
void names_notfound PARAMS ((void));
|
||||
void name_expand PARAMS ((void));
|
||||
struct name *name_scan PARAMS ((const char *));
|
||||
char *name_from_list PARAMS ((void));
|
||||
void blank_name_list PARAMS ((void));
|
||||
char *new_name PARAMS ((const char *, const char *));
|
||||
void gid_to_gname (gid_t, char **gname);
|
||||
int gname_to_gid (char *gname, gid_t *);
|
||||
void uid_to_uname (uid_t, char **uname);
|
||||
int uname_to_uid (char *uname, uid_t *);
|
||||
|
||||
void add_exclude PARAMS ((char *));
|
||||
void add_exclude_file PARAMS ((const char *));
|
||||
int check_exclude PARAMS ((const char *));
|
||||
void init_names (void);
|
||||
void name_add (const char *);
|
||||
void name_init (int, char *const *);
|
||||
void name_term (void);
|
||||
char *name_next (int);
|
||||
void name_close (void);
|
||||
void name_gather (void);
|
||||
struct name *addname (char const *, int);
|
||||
int name_match (const char *);
|
||||
void names_notfound (void);
|
||||
void collect_and_sort_names (void);
|
||||
struct name *name_scan (const char *);
|
||||
char *name_from_list (void);
|
||||
void blank_name_list (void);
|
||||
char *new_name (const char *, const char *);
|
||||
char *safer_name_suffix (char const *, bool);
|
||||
size_t stripped_prefix_len (char const *file_name, size_t num);
|
||||
bool all_names_found (struct tar_stat_info *);
|
||||
|
||||
bool excluded_name (char const *);
|
||||
|
||||
void add_avoided_name (char const *);
|
||||
bool is_avoided_name (char const *);
|
||||
|
||||
bool contains_dot_dot (char const *);
|
||||
|
||||
#define ISFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
(c)->found_count == occurrence_option)
|
||||
#define WASFOUND(c) ((occurrence_option == 0) ? (c)->found_count : \
|
||||
(c)->found_count >= occurrence_option)
|
||||
|
||||
/* Module tar.c. */
|
||||
|
||||
int confirm PARAMS ((const char *, const char *));
|
||||
void request_stdin PARAMS ((const char *));
|
||||
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);
|
||||
|
||||
/* Module update.c. */
|
||||
|
||||
extern char *output_start;
|
||||
|
||||
void update_archive PARAMS ((void));
|
||||
void update_archive (void);
|
||||
|
||||
/* Module xheader.c. */
|
||||
|
||||
void xheader_decode (struct tar_stat_info *);
|
||||
void xheader_store (char const *, struct tar_stat_info const *, void *);
|
||||
void xheader_read (union block *, size_t);
|
||||
void xheader_finish (struct xheader *);
|
||||
void xheader_destroy (struct xheader *);
|
||||
char *xheader_xhdr_name (struct tar_stat_info *st);
|
||||
char *xheader_ghdr_name (void);
|
||||
|
||||
/* Module system.c */
|
||||
|
||||
void sys_stat_nanoseconds (struct tar_stat_info *stat);
|
||||
void sys_detect_dev_null_output (void);
|
||||
void sys_save_archive_dev_ino (void);
|
||||
void sys_drain_input_pipe (void);
|
||||
void sys_wait_for_child (pid_t);
|
||||
void sys_spawn_shell (void);
|
||||
bool sys_compare_uid (struct stat *a, struct stat *b);
|
||||
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);
|
||||
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);
|
||||
|
||||
697
src/compare.c
697
src/compare.c
File diff suppressed because it is too large
Load Diff
1640
src/create.c
1640
src/create.c
File diff suppressed because it is too large
Load Diff
433
src/delete.c
433
src/delete.c
@@ -1,5 +1,7 @@
|
||||
/* Delete entries from a tar archive.
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 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
|
||||
@@ -13,97 +15,95 @@
|
||||
|
||||
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 Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
|
||||
#include "common.h"
|
||||
#include "rmt.h"
|
||||
|
||||
static union block *new_record = NULL;
|
||||
static union block *save_record = NULL;
|
||||
static int records_read = 0;
|
||||
static int new_blocks = 0;
|
||||
static int blocks_needed = 0;
|
||||
static union block *new_record;
|
||||
static int new_blocks;
|
||||
static bool acting_as_filter;
|
||||
|
||||
/* FIXME: This module should not directly handle the following three
|
||||
variables, instead, this should be done in buffer.c only. */
|
||||
/* FIXME: This module should not directly handle the following
|
||||
variables, instead, the interface should be cleaned up. */
|
||||
extern union block *record_start;
|
||||
extern union block *record_end;
|
||||
extern union block *current_block;
|
||||
extern union block *recent_long_name;
|
||||
extern union block *recent_long_link;
|
||||
extern off_t records_read;
|
||||
extern off_t records_written;
|
||||
|
||||
/*-------------------------------------------------------------------------.
|
||||
| Move archive descriptor by COUNT records worth. If COUNT is positive we |
|
||||
| move forward, else we move negative. If its a tape, MTIOCTOP had better |
|
||||
| work. If its something else, we try to seek on it. If we can't seek, |
|
||||
| we loose! |
|
||||
`-------------------------------------------------------------------------*/
|
||||
/* The number of records skipped at the start of the archive, when
|
||||
passing over members that are not deleted. */
|
||||
static off_t records_skipped;
|
||||
|
||||
/* Move archive descriptor by COUNT records worth. If COUNT is
|
||||
positive we move forward, else we move negative. If it's a tape,
|
||||
MTIOCTOP had better work. If it's something else, we try to seek
|
||||
on it. If we can't seek, we lose! */
|
||||
static void
|
||||
move_archive (int count)
|
||||
move_archive (off_t count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop operation;
|
||||
int status;
|
||||
|
||||
if (count > 0)
|
||||
if (count < 0
|
||||
? (operation.mt_op = MTBSR,
|
||||
operation.mt_count = -count,
|
||||
operation.mt_count == -count)
|
||||
: (operation.mt_op = MTFSR,
|
||||
operation.mt_count = count,
|
||||
operation.mt_count == count))
|
||||
{
|
||||
operation.mt_op = MTFSR;
|
||||
operation.mt_count = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
operation.mt_op = MTBSR;
|
||||
operation.mt_count = -count;
|
||||
}
|
||||
if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
|
||||
return;
|
||||
|
||||
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
|
||||
status >= 0)
|
||||
return;
|
||||
|
||||
if (errno == EIO)
|
||||
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
|
||||
status >= 0)
|
||||
return;
|
||||
if (errno == EIO
|
||||
&& 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* MTIOCTOP */
|
||||
|
||||
{
|
||||
off_t position = rmtlseek (archive, 0L, 1);
|
||||
off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
|
||||
off_t increment = record_size * (off_t) count;
|
||||
off_t position = position0 + increment;
|
||||
|
||||
position += record_size * count;
|
||||
|
||||
if (rmtlseek (archive, position, 0) != position)
|
||||
FATAL_ERROR ((0, 0, _("Could not re-position archive file")));
|
||||
if (increment / count != record_size
|
||||
|| (position < position0) != (increment < 0)
|
||||
|| (position = position < 0 ? 0 : position,
|
||||
rmtlseek (archive, position, SEEK_SET) != position))
|
||||
seek_error_details (archive_name_array[0], position);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------.
|
||||
| Write out the record which has been filled. If MOVE_BACK_FLAG, |
|
||||
| backspace to where we started. |
|
||||
`----------------------------------------------------------------*/
|
||||
|
||||
/* Write out the record which has been filled. If MOVE_BACK_FLAG,
|
||||
backspace to where we started. */
|
||||
static void
|
||||
write_record (int move_back_flag)
|
||||
{
|
||||
save_record = record_start;
|
||||
union block *save_record = record_start;
|
||||
record_start = new_record;
|
||||
|
||||
if (archive == STDIN)
|
||||
if (acting_as_filter)
|
||||
{
|
||||
archive = STDOUT;
|
||||
archive = STDOUT_FILENO;
|
||||
flush_write ();
|
||||
archive = STDIN;
|
||||
archive = STDIN_FILENO;
|
||||
}
|
||||
else
|
||||
{
|
||||
move_archive (-(records_read + 1));
|
||||
move_archive ((records_written + records_skipped) - records_read);
|
||||
flush_write ();
|
||||
}
|
||||
|
||||
@@ -113,19 +113,39 @@ write_record (int move_back_flag)
|
||||
{
|
||||
/* Move the tape head back to where we were. */
|
||||
|
||||
if (archive != STDIN)
|
||||
move_archive (records_read);
|
||||
|
||||
records_read--;
|
||||
if (! acting_as_filter)
|
||||
move_archive (records_read - (records_written + records_skipped));
|
||||
}
|
||||
|
||||
blocks_needed = blocking_factor;
|
||||
new_blocks = 0;
|
||||
}
|
||||
|
||||
/*---.
|
||||
| ? |
|
||||
`---*/
|
||||
static void
|
||||
write_recent_blocks (union block *h, size_t blocks)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < blocks; i++)
|
||||
{
|
||||
new_record[new_blocks++] = h[i];
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_recent_bytes (char *data, size_t bytes)
|
||||
{
|
||||
size_t blocks = bytes / BLOCKSIZE;
|
||||
size_t rest = bytes - blocks * BLOCKSIZE;
|
||||
|
||||
write_recent_blocks ((union block *)data, blocks);
|
||||
memcpy (new_record[new_blocks].buffer, data + blocks * BLOCKSIZE, rest);
|
||||
if (rest < BLOCKSIZE)
|
||||
memset (new_record[new_blocks].buffer + rest, 0, BLOCKSIZE - rest);
|
||||
new_blocks++;
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
}
|
||||
|
||||
void
|
||||
delete_archive_members (void)
|
||||
@@ -135,16 +155,17 @@ delete_archive_members (void)
|
||||
|
||||
/* FIXME: Should clean the routine before cleaning these variables :-( */
|
||||
struct name *name;
|
||||
int blocks_to_skip = 0;
|
||||
int blocks_to_keep = 0;
|
||||
off_t blocks_to_skip = 0;
|
||||
off_t blocks_to_keep = 0;
|
||||
int kept_blocks_in_record;
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||
|
||||
while (logical_status == HEADER_STILL_UNREAD)
|
||||
do
|
||||
{
|
||||
enum read_header status = read_header ();
|
||||
enum read_header status = read_header (true);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
@@ -152,19 +173,30 @@ delete_archive_members (void)
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
if (name = name_scan (current_file_name), !name)
|
||||
if ((name = name_scan (current_stat_info.file_name)) == NULL)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) (current_stat.st_size));
|
||||
skip_member ();
|
||||
break;
|
||||
}
|
||||
name->found = 1;
|
||||
logical_status = HEADER_SUCCESS;
|
||||
name->found_count++;
|
||||
if (!ISFOUND(name))
|
||||
{
|
||||
skip_member ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
logical_status = status;
|
||||
break;
|
||||
|
||||
case HEADER_ZERO_BLOCK:
|
||||
if (ignore_zeros_option)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case HEADER_END_OF_FILE:
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
@@ -178,6 +210,7 @@ delete_archive_members (void)
|
||||
/* Fall through. */
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
@@ -193,144 +226,166 @@ delete_archive_members (void)
|
||||
|
||||
previous_status = status;
|
||||
}
|
||||
while (logical_status == HEADER_STILL_UNREAD);
|
||||
|
||||
if (logical_status != HEADER_SUCCESS)
|
||||
records_skipped = records_read - 1;
|
||||
new_record = xmalloc (record_size);
|
||||
|
||||
if (logical_status == HEADER_SUCCESS
|
||||
|| logical_status == HEADER_SUCCESS_EXTENDED)
|
||||
{
|
||||
write_eot ();
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
return;
|
||||
}
|
||||
write_archive_to_stdout = false;
|
||||
|
||||
write_archive_to_stdout = 0;
|
||||
new_record = (union block *) xmalloc ((size_t) record_size);
|
||||
/* Save away blocks before this one in this record. */
|
||||
|
||||
/* Save away blocks before this one in this record. */
|
||||
new_blocks = current_block - record_start;
|
||||
if (new_blocks)
|
||||
memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
|
||||
|
||||
new_blocks = current_block - record_start;
|
||||
blocks_needed = blocking_factor - new_blocks;
|
||||
if (new_blocks)
|
||||
memcpy ((void *) new_record, (void *) record_start,
|
||||
(size_t) (new_blocks * BLOCKSIZE));
|
||||
|
||||
#if 0
|
||||
/* FIXME: Old code, before the goto was inserted. To be redesigned. */
|
||||
set_next_block_after (current_header);
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file ((long) (current_stat.st_size));
|
||||
#endif
|
||||
logical_status = HEADER_STILL_UNREAD;
|
||||
goto flush_file;
|
||||
|
||||
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
|
||||
"delete.c", line 223: warning: loop not entered at top
|
||||
Reported by Bruno Haible. */
|
||||
while (1)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
/* Fill in a record. */
|
||||
|
||||
if (current_block == record_end)
|
||||
if (logical_status == HEADER_SUCCESS)
|
||||
{
|
||||
flush_archive ();
|
||||
records_read++;
|
||||
}
|
||||
status = read_header ();
|
||||
|
||||
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
|
||||
{
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
memset (new_record[new_blocks].buffer, 0,
|
||||
(size_t) (BLOCKSIZE * blocks_needed));
|
||||
new_blocks += blocks_needed;
|
||||
blocks_needed = 0;
|
||||
write_record (0);
|
||||
break;
|
||||
/* FIXME: Pheew! This is crufty code! */
|
||||
logical_status = HEADER_STILL_UNREAD;
|
||||
goto flush_file;
|
||||
}
|
||||
|
||||
if (status == HEADER_FAILURE)
|
||||
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
|
||||
"delete.c", line 223: warning: loop not entered at top
|
||||
Reported by Bruno Haible. */
|
||||
while (1)
|
||||
{
|
||||
ERROR ((0, 0, _("Deleting non-header from archive")));
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
enum read_header status;
|
||||
|
||||
/* Found another header. */
|
||||
|
||||
if (name = name_scan (current_file_name), name)
|
||||
{
|
||||
name->found = 1;
|
||||
flush_file:
|
||||
set_next_block_after (current_header);
|
||||
blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
|
||||
while (record_end - current_block <= blocks_to_skip)
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
flush_archive ();
|
||||
records_read++;
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
blocks_to_skip = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Copy header. */
|
||||
|
||||
new_record[new_blocks] = *current_header;
|
||||
new_blocks++;
|
||||
blocks_needed--;
|
||||
blocks_to_keep
|
||||
= (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
set_next_block_after (current_header);
|
||||
if (blocks_needed == 0)
|
||||
write_record (1);
|
||||
|
||||
/* Copy data. */
|
||||
|
||||
kept_blocks_in_record = record_end - current_block;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
|
||||
while (blocks_to_keep)
|
||||
{
|
||||
int count;
|
||||
/* Fill in a record. */
|
||||
|
||||
if (current_block == record_end)
|
||||
flush_archive ();
|
||||
status = read_header (false);
|
||||
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
|
||||
{
|
||||
flush_read ();
|
||||
records_read++;
|
||||
current_block = record_start;
|
||||
kept_blocks_in_record = blocking_factor;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
|
||||
{
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
}
|
||||
count = kept_blocks_in_record;
|
||||
if (count > blocks_needed)
|
||||
count = blocks_needed;
|
||||
|
||||
memcpy ((void *) (new_record + new_blocks),
|
||||
(void *) current_block,
|
||||
(size_t) (count * BLOCKSIZE));
|
||||
new_blocks += count;
|
||||
blocks_needed -= count;
|
||||
current_block += count;
|
||||
blocks_to_keep -= count;
|
||||
kept_blocks_in_record -= count;
|
||||
if (status == HEADER_FAILURE)
|
||||
{
|
||||
ERROR ((0, 0, _("Deleting non-header from archive")));
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blocks_needed == 0)
|
||||
/* Found another header. */
|
||||
|
||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
name->found_count++;
|
||||
if (ISFOUND(name))
|
||||
{
|
||||
flush_file:
|
||||
set_next_block_after (current_header);
|
||||
blocks_to_skip = (current_stat_info.stat.st_size
|
||||
+ BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
|
||||
while (record_end - current_block <= blocks_to_skip)
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
flush_archive ();
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
blocks_to_skip = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Copy header. */
|
||||
|
||||
if (extended_header.size)
|
||||
{
|
||||
write_recent_bytes (extended_header.buffer,
|
||||
extended_header.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
write_recent_blocks (recent_long_name, recent_long_name_blocks);
|
||||
write_recent_blocks (recent_long_link, recent_long_link_blocks);
|
||||
}
|
||||
new_record[new_blocks] = *current_header;
|
||||
new_blocks++;
|
||||
blocks_to_keep
|
||||
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
set_next_block_after (current_header);
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
|
||||
/* Copy data. */
|
||||
|
||||
kept_blocks_in_record = record_end - current_block;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
|
||||
while (blocks_to_keep)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (current_block == record_end)
|
||||
{
|
||||
flush_read ();
|
||||
current_block = record_start;
|
||||
kept_blocks_in_record = blocking_factor;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
}
|
||||
count = kept_blocks_in_record;
|
||||
if (blocking_factor - new_blocks < count)
|
||||
count = blocking_factor - new_blocks;
|
||||
|
||||
if (! count)
|
||||
abort ();
|
||||
|
||||
memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
|
||||
new_blocks += count;
|
||||
current_block += count;
|
||||
blocks_to_keep -= count;
|
||||
kept_blocks_in_record -= count;
|
||||
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write_eot ();
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
free (new_record);
|
||||
|
||||
if (! acting_as_filter && ! _isrmt (archive))
|
||||
{
|
||||
if (sys_truncate (archive))
|
||||
truncate_warn (archive_name_array[0]);
|
||||
}
|
||||
|
||||
close_archive ();
|
||||
names_notfound ();
|
||||
}
|
||||
|
||||
459
src/extract.c
459
src/extract.c
@@ -1,7 +1,7 @@
|
||||
/* Extract files from a tar archive.
|
||||
|
||||
Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2003 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-11-19.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "system.h"
|
||||
#include <quotearg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
@@ -34,7 +35,7 @@ struct utimbuf
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int we_are_root; /* true if our effective uid == 0 */
|
||||
bool we_are_root; /* true if our effective uid == 0 */
|
||||
static mode_t newdir_umask; /* umask when creating new directories */
|
||||
static mode_t current_umask; /* current umask (which is set to 0 if -p) */
|
||||
|
||||
@@ -129,14 +130,15 @@ extr_init (void)
|
||||
}
|
||||
|
||||
/* If restoring permissions, restore the mode for FILE_NAME from
|
||||
information given in *STAT_INFO (where *CURRENT_STAT_INFO gives
|
||||
the current status if CURRENT_STAT_INFO is nonzero); otherwise invert the
|
||||
information given in *STAT_INFO (where *CUR_INFO gives
|
||||
the current status if CUR_INFO is nonzero); otherwise invert the
|
||||
INVERT_PERMISSIONS bits from the file's current permissions.
|
||||
PERMSTATUS specifies the status of the file's permissions.
|
||||
TYPEFLAG specifies the type of the file. */
|
||||
static void
|
||||
set_mode (char const *file_name, struct stat const *stat_info,
|
||||
struct stat const *current_stat_info,
|
||||
set_mode (char const *file_name,
|
||||
struct stat const *stat_info,
|
||||
struct stat const *cur_info,
|
||||
mode_t invert_permissions, enum permstatus permstatus,
|
||||
char typeflag)
|
||||
{
|
||||
@@ -168,16 +170,16 @@ set_mode (char const *file_name, struct stat const *stat_info,
|
||||
that we created, so there's no point optimizing this code for
|
||||
other cases. */
|
||||
struct stat st;
|
||||
if (! current_stat_info)
|
||||
if (! cur_info)
|
||||
{
|
||||
if (stat (file_name, &st) != 0)
|
||||
{
|
||||
stat_error (file_name);
|
||||
return;
|
||||
}
|
||||
current_stat_info = &st;
|
||||
cur_info = &st;
|
||||
}
|
||||
mode = current_stat_info->st_mode ^ invert_permissions;
|
||||
mode = cur_info->st_mode ^ invert_permissions;
|
||||
}
|
||||
|
||||
if (chmod (file_name, mode) != 0)
|
||||
@@ -189,14 +191,17 @@ static void
|
||||
check_time (char const *file_name, time_t t)
|
||||
{
|
||||
time_t now;
|
||||
if (start_time < t && (now = time (0)) < t)
|
||||
if (t <= 0)
|
||||
WARN ((0, 0, _("%s: implausibly old time stamp %s"),
|
||||
file_name, tartime (t)));
|
||||
else if (start_time < t && (now = time (0)) < t)
|
||||
WARN ((0, 0, _("%s: time stamp %s is %lu s in the future"),
|
||||
file_name, tartime (t), (unsigned long) (t - now)));
|
||||
}
|
||||
|
||||
/* Restore stat attributes (owner, group, mode and times) for
|
||||
FILE_NAME, using information given in *STAT_INFO.
|
||||
If CURRENT_STAT_INFO is nonzero, *CURRENT_STAT_INFO is the
|
||||
If CUR_INFO is nonzero, *CUR_INFO is the
|
||||
file's currernt status.
|
||||
If not restoring permissions, invert the
|
||||
INVERT_PERMISSIONS bits from the file's current permissions.
|
||||
@@ -209,8 +214,9 @@ check_time (char const *file_name, time_t t)
|
||||
punt for the rest. Sigh! */
|
||||
|
||||
static void
|
||||
set_stat (char const *file_name, struct stat const *stat_info,
|
||||
struct stat const *current_stat_info,
|
||||
set_stat (char const *file_name,
|
||||
struct stat const *stat_info,
|
||||
struct stat const *cur_info,
|
||||
mode_t invert_permissions, enum permstatus permstatus,
|
||||
char typeflag)
|
||||
{
|
||||
@@ -240,8 +246,8 @@ set_stat (char const *file_name, struct stat const *stat_info,
|
||||
utime_error (file_name);
|
||||
else
|
||||
{
|
||||
check_time (file_name, stat_info->st_atime);
|
||||
check_time (file_name, stat_info->st_mtime);
|
||||
check_time (file_name, utimbuf.actime);
|
||||
check_time (file_name, utimbuf.modtime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +255,7 @@ set_stat (char const *file_name, struct stat const *stat_info,
|
||||
done, it is not possible anymore to change file permissions, so we
|
||||
have to set permissions prior to possibly giving files away. */
|
||||
|
||||
set_mode (file_name, stat_info, current_stat_info,
|
||||
set_mode (file_name, stat_info, cur_info,
|
||||
invert_permissions, permstatus, typeflag);
|
||||
}
|
||||
|
||||
@@ -329,9 +335,9 @@ repair_delayed_set_stat (char const *dir_name,
|
||||
if (st.st_dev == dir_stat_info->st_dev
|
||||
&& st.st_ino == dir_stat_info->st_ino)
|
||||
{
|
||||
data->stat_info = current_stat;
|
||||
data->invert_permissions = (MODE_RWX
|
||||
& (current_stat.st_mode ^ st.st_mode));
|
||||
data->stat_info = current_stat_info.stat;
|
||||
data->invert_permissions =
|
||||
(MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode));
|
||||
data->permstatus = ARCHIVED_PERMSTATUS;
|
||||
return;
|
||||
}
|
||||
@@ -385,7 +391,7 @@ make_directories (char *file_name)
|
||||
invert_permissions is zero, because
|
||||
repair_delayed_set_stat may need to update the struct. */
|
||||
delay_set_stat (file_name,
|
||||
¤t_stat /* ignored */,
|
||||
¤t_stat_info.stat /* ignored */,
|
||||
invert_permissions, INTERDIR_PERMSTATUS);
|
||||
|
||||
print_for_mkdir (file_name, cursor - file_name, mode);
|
||||
@@ -397,13 +403,13 @@ make_directories (char *file_name)
|
||||
|
||||
*cursor = '/';
|
||||
|
||||
if (errno == EEXIST
|
||||
#if MSDOS
|
||||
/* Turbo C mkdir gives a funny errno. */
|
||||
|| errno == EACCES
|
||||
#endif
|
||||
)
|
||||
/* Directory already exists. */
|
||||
if (errno == EEXIST)
|
||||
continue; /* Directory already exists. */
|
||||
else if ((errno == ENOSYS /* Automounted dirs on Solaris return
|
||||
this. Reported by Warren Hyde
|
||||
<Warren.Hyde@motorola.com> */
|
||||
|| ERRNO_IS_EACCES) /* Turbo C mkdir gives a funny errno. */
|
||||
&& access (file_name, W_OK) == 0)
|
||||
continue;
|
||||
|
||||
/* Some other error in the mkdir. We return to the caller. */
|
||||
@@ -417,7 +423,7 @@ make_directories (char *file_name)
|
||||
Return zero if extraction should not proceed. */
|
||||
|
||||
static int
|
||||
prepare_to_extract (char const *file_name)
|
||||
prepare_to_extract (char const *file_name, bool directory)
|
||||
{
|
||||
if (to_stdout_option)
|
||||
return 0;
|
||||
@@ -454,6 +460,7 @@ maybe_recoverable (char *file_name, int *interdir_made)
|
||||
return 0;
|
||||
|
||||
case DEFAULT_OLD_FILES:
|
||||
case NO_OVERWRITE_DIR_OLD_FILES:
|
||||
case OVERWRITE_OLD_FILES:
|
||||
{
|
||||
int r = remove_any_file (file_name, 0);
|
||||
@@ -479,61 +486,6 @@ maybe_recoverable (char *file_name, int *interdir_made)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name)
|
||||
{
|
||||
int sparse_ind = 0;
|
||||
|
||||
/* assuming sizeleft is initially totalsize */
|
||||
|
||||
while (*sizeleft > 0)
|
||||
{
|
||||
size_t written;
|
||||
size_t count;
|
||||
union block *data_block = find_next_block ();
|
||||
if (! data_block)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return;
|
||||
}
|
||||
if (lseek (fd, sparsearray[sparse_ind].offset, SEEK_SET) < 0)
|
||||
{
|
||||
seek_error_details (name, sparsearray[sparse_ind].offset);
|
||||
return;
|
||||
}
|
||||
written = sparsearray[sparse_ind++].numbytes;
|
||||
while (written > BLOCKSIZE)
|
||||
{
|
||||
count = full_write (fd, data_block->buffer, BLOCKSIZE);
|
||||
written -= count;
|
||||
*sizeleft -= count;
|
||||
if (count != BLOCKSIZE)
|
||||
{
|
||||
write_error_details (name, count, BLOCKSIZE);
|
||||
return;
|
||||
}
|
||||
set_next_block_after (data_block);
|
||||
data_block = find_next_block ();
|
||||
if (! data_block)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
count = full_write (fd, data_block->buffer, written);
|
||||
*sizeleft -= count;
|
||||
|
||||
if (count != written)
|
||||
{
|
||||
write_error_details (name, count, written);
|
||||
return;
|
||||
}
|
||||
|
||||
set_next_block_after (data_block);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix the statuses of all directories whose statuses need fixing, and
|
||||
which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is
|
||||
nonzero, do this for all such directories; otherwise, stop at the
|
||||
@@ -550,7 +502,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
|
||||
struct delayed_set_stat *data = delayed_set_stat_head;
|
||||
bool skip_this_one = 0;
|
||||
struct stat st;
|
||||
struct stat const *current_stat_info = 0;
|
||||
struct stat const *cur_info = 0;
|
||||
|
||||
check_for_renamed_directories |= data->after_symlinks;
|
||||
|
||||
@@ -564,7 +516,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
|
||||
|
||||
if (check_for_renamed_directories)
|
||||
{
|
||||
current_stat_info = &st;
|
||||
cur_info = &st;
|
||||
if (stat (data->file_name, &st) != 0)
|
||||
{
|
||||
stat_error (data->file_name);
|
||||
@@ -581,7 +533,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
|
||||
}
|
||||
|
||||
if (! skip_this_one)
|
||||
set_stat (data->file_name, &data->stat_info, current_stat_info,
|
||||
set_stat (data->file_name, &data->stat_info, cur_info,
|
||||
data->invert_permissions, data->permstatus, DIRTYPE);
|
||||
|
||||
delayed_set_stat_head = data->next;
|
||||
@@ -597,23 +549,19 @@ extract_archive (void)
|
||||
int fd;
|
||||
int status;
|
||||
size_t count;
|
||||
size_t name_length;
|
||||
size_t written;
|
||||
int openflag;
|
||||
mode_t mode;
|
||||
off_t size;
|
||||
size_t skipcrud;
|
||||
int counter;
|
||||
off_t file_size;
|
||||
int interdir_made = 0;
|
||||
char typeflag;
|
||||
union block *exhdr;
|
||||
|
||||
#define CURRENT_FILE_NAME (skipcrud + current_file_name)
|
||||
char *file_name;
|
||||
|
||||
set_next_block_after (current_header);
|
||||
decode_header (current_header, ¤t_stat, ¤t_format, 1);
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
|
||||
|
||||
if (interactive_option && !confirm ("extract", current_file_name))
|
||||
if (interactive_option && !confirm ("extract", current_stat_info.file_name))
|
||||
{
|
||||
skip_member ();
|
||||
return;
|
||||
@@ -622,48 +570,30 @@ extract_archive (void)
|
||||
/* Print the block from current_header and current_stat. */
|
||||
|
||||
if (verbose_option)
|
||||
print_header ();
|
||||
print_header (¤t_stat_info, -1);
|
||||
|
||||
/* Check for fully specified file names and other atrocities. */
|
||||
|
||||
skipcrud = 0;
|
||||
if (! absolute_names_option)
|
||||
file_name = safer_name_suffix (current_stat_info.file_name, false);
|
||||
if (strip_path_elements)
|
||||
{
|
||||
if (contains_dot_dot (CURRENT_FILE_NAME))
|
||||
size_t prefix_len = stripped_prefix_len (file_name, strip_path_elements);
|
||||
if (prefix_len == (size_t) -1)
|
||||
{
|
||||
ERROR ((0, 0, _("%s: Member name contains `..'"),
|
||||
quotearg_colon (CURRENT_FILE_NAME)));
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
|
||||
skipcrud = FILESYSTEM_PREFIX_LEN (current_file_name);
|
||||
while (ISSLASH (CURRENT_FILE_NAME[0]))
|
||||
skipcrud++;
|
||||
|
||||
if (skipcrud)
|
||||
{
|
||||
static int warned_once;
|
||||
|
||||
if (!warned_once)
|
||||
{
|
||||
warned_once = 1;
|
||||
WARN ((0, 0, _("Removing leading `%.*s' from member names"),
|
||||
(int) skipcrud, current_file_name));
|
||||
}
|
||||
}
|
||||
file_name += prefix_len;
|
||||
}
|
||||
|
||||
apply_nonancestor_delayed_set_stat (CURRENT_FILE_NAME, 0);
|
||||
|
||||
apply_nonancestor_delayed_set_stat (file_name, 0);
|
||||
|
||||
/* Take a safety backup of a previously existing file. */
|
||||
|
||||
if (backup_option && !to_stdout_option)
|
||||
if (!maybe_backup_file (CURRENT_FILE_NAME, 0))
|
||||
if (!maybe_backup_file (file_name, 0))
|
||||
{
|
||||
int e = errno;
|
||||
ERROR ((0, e, _("%s: Was unable to backup this file"),
|
||||
quotearg_colon (CURRENT_FILE_NAME)));
|
||||
quotearg_colon (file_name)));
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
@@ -671,82 +601,14 @@ 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;
|
||||
|
||||
switch (typeflag)
|
||||
{
|
||||
/* JK - What we want to do if the file is sparse is loop through
|
||||
the array of sparse structures in the header and read in and
|
||||
translate the character strings representing 1) the offset at
|
||||
which to write and 2) how many bytes to write into numbers,
|
||||
which we store into the scratch array, "sparsearray". This
|
||||
array makes our life easier the same way it did in creating the
|
||||
tar file that had to deal with a sparse file.
|
||||
|
||||
After we read in the first five (at most) sparse structures, we
|
||||
check to see if the file has an extended header, i.e., if more
|
||||
sparse structures are needed to describe the contents of the new
|
||||
file. If so, we read in the extended headers and continue to
|
||||
store their contents into the sparsearray. */
|
||||
|
||||
case GNUTYPE_SPARSE:
|
||||
sp_array_size = 10;
|
||||
sparsearray =
|
||||
xmalloc (sp_array_size * sizeof (struct sp_array));
|
||||
|
||||
for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
|
||||
{
|
||||
struct sparse const *s = ¤t_header->oldgnu_header.sp[counter];
|
||||
sparsearray[counter].offset = OFF_FROM_HEADER (s->offset);
|
||||
sparsearray[counter].numbytes = SIZE_FROM_HEADER (s->numbytes);
|
||||
if (!sparsearray[counter].numbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
{
|
||||
/* Read in the list of extended headers and translate them
|
||||
into the sparsearray as before. Note that this
|
||||
invalidates current_header. */
|
||||
|
||||
/* static */ int ind = SPARSES_IN_OLDGNU_HEADER;
|
||||
|
||||
while (1)
|
||||
{
|
||||
exhdr = find_next_block ();
|
||||
if (! exhdr)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return;
|
||||
}
|
||||
for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
|
||||
{
|
||||
struct sparse const *s = &exhdr->sparse_header.sp[counter];
|
||||
if (counter + ind > sp_array_size - 1)
|
||||
{
|
||||
/* Realloc the scratch area since we've run out of
|
||||
room. */
|
||||
|
||||
sp_array_size *= 2;
|
||||
sparsearray =
|
||||
xrealloc (sparsearray,
|
||||
sp_array_size * sizeof (struct sp_array));
|
||||
}
|
||||
if (s->numbytes[0] == 0)
|
||||
break;
|
||||
sparsearray[counter + ind].offset =
|
||||
OFF_FROM_HEADER (s->offset);
|
||||
sparsearray[counter + ind].numbytes =
|
||||
SIZE_FROM_HEADER (s->numbytes);
|
||||
}
|
||||
if (!exhdr->sparse_header.isextended)
|
||||
break;
|
||||
else
|
||||
{
|
||||
ind += SPARSES_IN_SPARSE_HEADER;
|
||||
set_next_block_after (exhdr);
|
||||
}
|
||||
}
|
||||
set_next_block_after (exhdr);
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case AREGTYPE:
|
||||
@@ -756,9 +618,7 @@ extract_archive (void)
|
||||
/* Appears to be a file. But BSD tar uses the convention that a slash
|
||||
suffix means a directory. */
|
||||
|
||||
name_length = strlen (CURRENT_FILE_NAME);
|
||||
if (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
|
||||
&& CURRENT_FILE_NAME[name_length - 1] == '/')
|
||||
if (current_stat_info.had_trailing_slash)
|
||||
goto really_dir;
|
||||
|
||||
/* FIXME: deal with protection issues. */
|
||||
@@ -768,7 +628,7 @@ extract_archive (void)
|
||||
| (old_files_option == OVERWRITE_OLD_FILES
|
||||
? O_TRUNC
|
||||
: O_EXCL));
|
||||
mode = current_stat.st_mode & MODE_RWX & ~ current_umask;
|
||||
mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
|
||||
|
||||
if (to_stdout_option)
|
||||
{
|
||||
@@ -776,7 +636,7 @@ extract_archive (void)
|
||||
goto extract_file;
|
||||
}
|
||||
|
||||
if (! prepare_to_extract (CURRENT_FILE_NAME))
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
{
|
||||
skip_member ();
|
||||
if (backup_option)
|
||||
@@ -789,10 +649,9 @@ extract_archive (void)
|
||||
the open call that creates them. */
|
||||
|
||||
if (typeflag == CONTTYPE)
|
||||
fd = open (CURRENT_FILE_NAME, openflag | O_CTG,
|
||||
mode, current_stat.st_size);
|
||||
fd = open (file_name, openflag | O_CTG, mode, current_stat_info.stat.st_size);
|
||||
else
|
||||
fd = open (CURRENT_FILE_NAME, openflag, mode);
|
||||
fd = open (file_name, openflag, mode);
|
||||
|
||||
#else /* not O_CTG */
|
||||
if (typeflag == CONTTYPE)
|
||||
@@ -805,16 +664,16 @@ extract_archive (void)
|
||||
WARN ((0, 0, _("Extracting contiguous files as regular files")));
|
||||
}
|
||||
}
|
||||
fd = open (CURRENT_FILE_NAME, openflag, mode);
|
||||
fd = open (file_name, openflag, mode);
|
||||
|
||||
#endif /* not O_CTG */
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (maybe_recoverable (file_name, &interdir_made))
|
||||
goto again_file;
|
||||
|
||||
open_error (CURRENT_FILE_NAME);
|
||||
open_error (file_name);
|
||||
skip_member ();
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
@@ -824,29 +683,15 @@ extract_archive (void)
|
||||
extract_file:
|
||||
if (typeflag == GNUTYPE_SPARSE)
|
||||
{
|
||||
char *name;
|
||||
size_t name_length_bis;
|
||||
|
||||
/* Kludge alert. NAME is assigned to header.name because
|
||||
during the extraction, the space that contains the header
|
||||
will get scribbled on, and the name will get munged, so any
|
||||
error messages that happen to contain the filename will look
|
||||
REAL interesting unless we do this. */
|
||||
|
||||
name_length_bis = strlen (CURRENT_FILE_NAME) + 1;
|
||||
name = xmalloc (name_length_bis);
|
||||
memcpy (name, CURRENT_FILE_NAME, name_length_bis);
|
||||
size = current_stat.st_size;
|
||||
extract_sparse_file (fd, &size, current_stat.st_size, name);
|
||||
free (sparsearray);
|
||||
sparse_extract_file (fd, ¤t_stat_info, &size);
|
||||
}
|
||||
else
|
||||
for (size = current_stat.st_size; size > 0; )
|
||||
for (size = current_stat_info.stat.st_size; size > 0; )
|
||||
{
|
||||
if (multi_volume_option)
|
||||
{
|
||||
assign_string (&save_name, current_file_name);
|
||||
save_totsize = current_stat.st_size;
|
||||
assign_string (&save_name, current_stat_info.file_name);
|
||||
save_totsize = current_stat_info.stat.st_size;
|
||||
save_sizeleft = size;
|
||||
}
|
||||
|
||||
@@ -873,7 +718,7 @@ extract_archive (void)
|
||||
(data_block->buffer + written - 1));
|
||||
if (count != written)
|
||||
{
|
||||
write_error_details (CURRENT_FILE_NAME, count, written);
|
||||
write_error_details (file_name, count, written);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -892,12 +737,12 @@ extract_archive (void)
|
||||
status = close (fd);
|
||||
if (status < 0)
|
||||
{
|
||||
close_error (CURRENT_FILE_NAME);
|
||||
close_error (file_name);
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
}
|
||||
|
||||
set_stat (CURRENT_FILE_NAME, ¤t_stat, 0, 0,
|
||||
set_stat (file_name, ¤t_stat_info.stat, 0, 0,
|
||||
(old_files_option == OVERWRITE_OLD_FILES
|
||||
? UNKNOWN_PERMSTATUS
|
||||
: ARCHIVED_PERMSTATUS),
|
||||
@@ -906,23 +751,23 @@ extract_archive (void)
|
||||
|
||||
case SYMTYPE:
|
||||
#ifdef HAVE_SYMLINK
|
||||
if (! prepare_to_extract (CURRENT_FILE_NAME))
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
break;
|
||||
|
||||
if (absolute_names_option
|
||||
|| ! (ISSLASH (current_link_name
|
||||
[FILESYSTEM_PREFIX_LEN (current_link_name)])
|
||||
|| contains_dot_dot (current_link_name)))
|
||||
|| ! (ISSLASH (current_stat_info.link_name
|
||||
[FILESYSTEM_PREFIX_LEN (current_stat_info.link_name)])
|
||||
|| contains_dot_dot (current_stat_info.link_name)))
|
||||
{
|
||||
while (status = symlink (current_link_name, CURRENT_FILE_NAME),
|
||||
while (status = symlink (current_stat_info.link_name, file_name),
|
||||
status != 0)
|
||||
if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (!maybe_recoverable (file_name, &interdir_made))
|
||||
break;
|
||||
|
||||
if (status == 0)
|
||||
set_stat (CURRENT_FILE_NAME, ¤t_stat, 0, 0, 0, SYMTYPE);
|
||||
set_stat (file_name, ¤t_stat_info.stat, 0, 0, 0, SYMTYPE);
|
||||
else
|
||||
symlink_error (current_link_name, CURRENT_FILE_NAME);
|
||||
symlink_error (current_stat_info.link_name, file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -931,56 +776,60 @@ extract_archive (void)
|
||||
will be replaced after other extraction is done. */
|
||||
struct stat st;
|
||||
|
||||
while (fd = open (CURRENT_FILE_NAME, O_WRONLY | O_CREAT | O_EXCL, 0),
|
||||
while (fd = open (file_name, O_WRONLY | O_CREAT | O_EXCL, 0),
|
||||
fd < 0)
|
||||
if (! maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (! maybe_recoverable (file_name, &interdir_made))
|
||||
break;
|
||||
|
||||
status = -1;
|
||||
if (fd < 0)
|
||||
open_error (CURRENT_FILE_NAME);
|
||||
open_error (file_name);
|
||||
else if (fstat (fd, &st) != 0)
|
||||
{
|
||||
stat_error (CURRENT_FILE_NAME);
|
||||
stat_error (file_name);
|
||||
close (fd);
|
||||
}
|
||||
else if (close (fd) != 0)
|
||||
close_error (CURRENT_FILE_NAME);
|
||||
close_error (file_name);
|
||||
else
|
||||
{
|
||||
struct delayed_set_stat *h;
|
||||
struct delayed_symlink *p =
|
||||
xmalloc (offsetof (struct delayed_symlink, target)
|
||||
+ strlen (current_link_name) + 1);
|
||||
+ strlen (current_stat_info.link_name) + 1);
|
||||
p->next = delayed_symlink_head;
|
||||
delayed_symlink_head = p;
|
||||
p->dev = st.st_dev;
|
||||
p->ino = st.st_ino;
|
||||
p->mtime = st.st_mtime;
|
||||
p->uid = current_stat.st_uid;
|
||||
p->gid = current_stat.st_gid;
|
||||
p->uid = current_stat_info.stat.st_uid;
|
||||
p->gid = current_stat_info.stat.st_gid;
|
||||
p->sources = xmalloc (offsetof (struct string_list, string)
|
||||
+ strlen (CURRENT_FILE_NAME) + 1);
|
||||
+ strlen (file_name) + 1);
|
||||
p->sources->next = 0;
|
||||
strcpy (p->sources->string, CURRENT_FILE_NAME);
|
||||
strcpy (p->target, current_link_name);
|
||||
strcpy (p->sources->string, file_name);
|
||||
strcpy (p->target, current_stat_info.link_name);
|
||||
|
||||
h = delayed_set_stat_head;
|
||||
if (h && ! h->after_symlinks
|
||||
&& strncmp (CURRENT_FILE_NAME, h->file_name, h->file_name_len) == 0
|
||||
&& ISSLASH (CURRENT_FILE_NAME[h->file_name_len])
|
||||
&& (base_name (CURRENT_FILE_NAME)
|
||||
== CURRENT_FILE_NAME + h->file_name_len + 1))
|
||||
&& strncmp (file_name, h->file_name, h->file_name_len) == 0
|
||||
&& ISSLASH (file_name[h->file_name_len])
|
||||
&& (base_name (file_name)
|
||||
== file_name + h->file_name_len + 1))
|
||||
{
|
||||
h->after_symlinks = 1;
|
||||
|
||||
if (stat (h->file_name, &st) != 0)
|
||||
stat_error (h->file_name);
|
||||
else
|
||||
do
|
||||
{
|
||||
h->stat_info.st_dev = st.st_dev;
|
||||
h->stat_info.st_ino = st.st_ino;
|
||||
h->after_symlinks = 1;
|
||||
|
||||
if (stat (h->file_name, &st) != 0)
|
||||
stat_error (h->file_name);
|
||||
else
|
||||
{
|
||||
h->stat_info.st_dev = st.st_dev;
|
||||
h->stat_info.st_ino = st.st_ino;
|
||||
}
|
||||
}
|
||||
while ((h = h->next) && ! h->after_symlinks);
|
||||
}
|
||||
|
||||
status = 0;
|
||||
@@ -1007,22 +856,24 @@ extract_archive (void)
|
||||
#endif
|
||||
|
||||
case LNKTYPE:
|
||||
if (! prepare_to_extract (CURRENT_FILE_NAME))
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
break;
|
||||
|
||||
again_link:
|
||||
{
|
||||
char const *link_name = safer_name_suffix (current_stat_info.link_name,
|
||||
true);
|
||||
struct stat st1, st2;
|
||||
int e;
|
||||
|
||||
/* MSDOS does not implement links. However, djgpp's link() actually
|
||||
copies the file. */
|
||||
status = link (current_link_name, CURRENT_FILE_NAME);
|
||||
status = link (link_name, file_name);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
struct delayed_symlink *ds = delayed_symlink_head;
|
||||
if (ds && stat (current_link_name, &st1) == 0)
|
||||
if (ds && stat (link_name, &st1) == 0)
|
||||
for (; ds; ds = ds->next)
|
||||
if (ds->dev == st1.st_dev
|
||||
&& ds->ino == st1.st_ino
|
||||
@@ -1030,27 +881,27 @@ extract_archive (void)
|
||||
{
|
||||
struct string_list *p =
|
||||
xmalloc (offsetof (struct string_list, string)
|
||||
+ strlen (CURRENT_FILE_NAME) + 1);
|
||||
strcpy (p->string, CURRENT_FILE_NAME);
|
||||
+ strlen (file_name) + 1);
|
||||
strcpy (p->string, file_name);
|
||||
p->next = ds->sources;
|
||||
ds->sources = p;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (maybe_recoverable (file_name, &interdir_made))
|
||||
goto again_link;
|
||||
|
||||
if (incremental_option && errno == EEXIST)
|
||||
break;
|
||||
e = errno;
|
||||
if (stat (current_link_name, &st1) == 0
|
||||
&& stat (CURRENT_FILE_NAME, &st2) == 0
|
||||
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 (current_link_name, CURRENT_FILE_NAME);
|
||||
link_error (link_name, file_name);
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
}
|
||||
@@ -1058,52 +909,52 @@ extract_archive (void)
|
||||
|
||||
#if S_IFCHR
|
||||
case CHRTYPE:
|
||||
current_stat.st_mode |= S_IFCHR;
|
||||
current_stat_info.stat.st_mode |= S_IFCHR;
|
||||
goto make_node;
|
||||
#endif
|
||||
|
||||
#if S_IFBLK
|
||||
case BLKTYPE:
|
||||
current_stat.st_mode |= S_IFBLK;
|
||||
current_stat_info.stat.st_mode |= S_IFBLK;
|
||||
#endif
|
||||
|
||||
#if S_IFCHR || S_IFBLK
|
||||
make_node:
|
||||
if (! prepare_to_extract (CURRENT_FILE_NAME))
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
break;
|
||||
|
||||
status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
|
||||
current_stat.st_rdev);
|
||||
status = mknod (file_name, current_stat_info.stat.st_mode,
|
||||
current_stat_info.stat.st_rdev);
|
||||
if (status != 0)
|
||||
{
|
||||
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (maybe_recoverable (file_name, &interdir_made))
|
||||
goto make_node;
|
||||
mknod_error (CURRENT_FILE_NAME);
|
||||
mknod_error (file_name);
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
break;
|
||||
};
|
||||
set_stat (CURRENT_FILE_NAME, ¤t_stat, 0, 0,
|
||||
set_stat (file_name, ¤t_stat_info.stat, 0, 0,
|
||||
ARCHIVED_PERMSTATUS, typeflag);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if HAVE_MKFIFO || defined mkfifo
|
||||
case FIFOTYPE:
|
||||
if (! prepare_to_extract (CURRENT_FILE_NAME))
|
||||
if (! prepare_to_extract (file_name, 0))
|
||||
break;
|
||||
|
||||
while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
|
||||
while (status = mkfifo (file_name, current_stat_info.stat.st_mode),
|
||||
status != 0)
|
||||
if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (!maybe_recoverable (file_name, &interdir_made))
|
||||
break;
|
||||
|
||||
if (status == 0)
|
||||
set_stat (CURRENT_FILE_NAME, ¤t_stat, 0, 0,
|
||||
set_stat (file_name, ¤t_stat_info.stat, NULL, 0,
|
||||
ARCHIVED_PERMSTATUS, typeflag);
|
||||
else
|
||||
{
|
||||
mkfifo_error (CURRENT_FILE_NAME);
|
||||
mkfifo_error (file_name);
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
}
|
||||
@@ -1112,46 +963,43 @@ extract_archive (void)
|
||||
|
||||
case DIRTYPE:
|
||||
case GNUTYPE_DUMPDIR:
|
||||
name_length = strlen (CURRENT_FILE_NAME);
|
||||
|
||||
really_dir:
|
||||
/* Remove any redundant trailing "/"s. */
|
||||
while (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
|
||||
&& CURRENT_FILE_NAME[name_length - 1] == '/')
|
||||
name_length--;
|
||||
CURRENT_FILE_NAME[name_length] = '\0';
|
||||
|
||||
if (incremental_option)
|
||||
{
|
||||
/* Read the entry and delete files that aren't listed in the
|
||||
archive. */
|
||||
|
||||
gnu_restore (skipcrud);
|
||||
gnu_restore (file_name);
|
||||
}
|
||||
else if (typeflag == GNUTYPE_DUMPDIR)
|
||||
skip_member ();
|
||||
|
||||
if (! prepare_to_extract (CURRENT_FILE_NAME))
|
||||
break;
|
||||
|
||||
mode = ((current_stat.st_mode
|
||||
mode = ((current_stat_info.stat.st_mode
|
||||
| (we_are_root ? 0 : MODE_WXUSR))
|
||||
& MODE_RWX);
|
||||
|
||||
status = prepare_to_extract (file_name, 1);
|
||||
if (status == 0)
|
||||
break;
|
||||
if (status < 0)
|
||||
goto directory_exists;
|
||||
|
||||
again_dir:
|
||||
status = mkdir (CURRENT_FILE_NAME, mode);
|
||||
status = mkdir (file_name, mode);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
if (errno == EEXIST
|
||||
&& (interdir_made || old_files_option == OVERWRITE_OLD_FILES))
|
||||
&& (interdir_made
|
||||
|| old_files_option == DEFAULT_OLD_FILES
|
||||
|| old_files_option == OVERWRITE_OLD_FILES))
|
||||
{
|
||||
struct stat st;
|
||||
if (stat (CURRENT_FILE_NAME, &st) == 0)
|
||||
if (stat (file_name, &st) == 0)
|
||||
{
|
||||
if (interdir_made)
|
||||
{
|
||||
repair_delayed_set_stat (CURRENT_FILE_NAME, &st);
|
||||
repair_delayed_set_stat (file_name, &st);
|
||||
break;
|
||||
}
|
||||
if (S_ISDIR (st.st_mode))
|
||||
@@ -1163,12 +1011,12 @@ extract_archive (void)
|
||||
errno = EEXIST;
|
||||
}
|
||||
|
||||
if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
|
||||
if (maybe_recoverable (file_name, &interdir_made))
|
||||
goto again_dir;
|
||||
|
||||
if (errno != EEXIST)
|
||||
{
|
||||
mkdir_error (CURRENT_FILE_NAME);
|
||||
mkdir_error (file_name);
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
break;
|
||||
@@ -1177,9 +1025,10 @@ extract_archive (void)
|
||||
|
||||
directory_exists:
|
||||
if (status == 0
|
||||
|| old_files_option == DEFAULT_OLD_FILES
|
||||
|| old_files_option == OVERWRITE_OLD_FILES)
|
||||
delay_set_stat (CURRENT_FILE_NAME, ¤t_stat,
|
||||
MODE_RWX & (mode ^ current_stat.st_mode),
|
||||
delay_set_stat (file_name, ¤t_stat_info.stat,
|
||||
MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
|
||||
(status == 0
|
||||
? ARCHIVED_PERMSTATUS
|
||||
: UNKNOWN_PERMSTATUS));
|
||||
@@ -1187,7 +1036,7 @@ extract_archive (void)
|
||||
|
||||
case GNUTYPE_VOLHDR:
|
||||
if (verbose_option)
|
||||
fprintf (stdlis, _("Reading %s\n"), quote (current_file_name));
|
||||
fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name));
|
||||
break;
|
||||
|
||||
case GNUTYPE_NAMES:
|
||||
@@ -1197,7 +1046,7 @@ extract_archive (void)
|
||||
case GNUTYPE_MULTIVOL:
|
||||
ERROR ((0, 0,
|
||||
_("%s: Cannot extract -- file is continued from another volume"),
|
||||
quotearg_colon (current_file_name)));
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
skip_member ();
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
@@ -1214,11 +1063,9 @@ extract_archive (void)
|
||||
default:
|
||||
WARN ((0, 0,
|
||||
_("%s: Unknown file type '%c', extracted as normal file"),
|
||||
quotearg_colon (CURRENT_FILE_NAME), typeflag));
|
||||
quotearg_colon (file_name), typeflag));
|
||||
goto again_file;
|
||||
}
|
||||
|
||||
#undef CURRENT_FILE_NAME
|
||||
}
|
||||
|
||||
/* Extract the symbolic links whose final extraction were delayed. */
|
||||
|
||||
946
src/incremen.c
946
src/incremen.c
File diff suppressed because it is too large
Load Diff
350
src/list.c
350
src/list.c
@@ -1,7 +1,7 @@
|
||||
/* List a tar archive, with support routines for reading a tar archive.
|
||||
|
||||
Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2003 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1985-08-26.
|
||||
|
||||
@@ -30,11 +30,14 @@
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
union block *current_header; /* points to current archive header */
|
||||
struct stat current_stat; /* stat struct corresponding */
|
||||
enum archive_format current_format; /* recognized format */
|
||||
union block *recent_long_name; /* recent long name header and contents */
|
||||
union block *recent_long_link; /* likewise, for long link */
|
||||
size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
|
||||
size_t recent_long_link_blocks; /* likewise, for long link */
|
||||
|
||||
static uintmax_t from_header PARAMS ((const char *, size_t, const char *,
|
||||
uintmax_t, uintmax_t));
|
||||
static uintmax_t from_header (const char *, size_t, const char *,
|
||||
uintmax_t, uintmax_t);
|
||||
|
||||
/* Base 64 digits; see Internet RFC 2045 Table 1. */
|
||||
static char const base_64_digits[64] =
|
||||
@@ -61,7 +64,7 @@ base64_init (void)
|
||||
|
||||
/* Main loop for reading an archive. */
|
||||
void
|
||||
read_and (void (*do_something) ())
|
||||
read_and (void (*do_something) (void))
|
||||
{
|
||||
enum read_header status = HEADER_STILL_UNREAD;
|
||||
enum read_header prev_status;
|
||||
@@ -70,13 +73,17 @@ read_and (void (*do_something) ())
|
||||
name_gather ();
|
||||
open_archive (ACCESS_READ);
|
||||
|
||||
while (1)
|
||||
do
|
||||
{
|
||||
prev_status = status;
|
||||
status = read_header ();
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
xheader_destroy (&extended_header);
|
||||
|
||||
status = read_header (false);
|
||||
switch (status)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
@@ -84,14 +91,14 @@ read_and (void (*do_something) ())
|
||||
/* Valid header. We should decode next field (mode) first.
|
||||
Ensure incoming names are null terminated. */
|
||||
|
||||
if (! name_match (current_file_name)
|
||||
if (! name_match (current_stat_info.file_name)
|
||||
|| (newer_mtime_option != TYPE_MINIMUM (time_t)
|
||||
/* FIXME: We get mtime now, and again later; this causes
|
||||
duplicate diagnostics if header.mtime is bogus. */
|
||||
&& ((current_stat.st_mtime
|
||||
&& ((current_stat_info.stat.st_mtime
|
||||
= TIME_FROM_HEADER (current_header->header.mtime))
|
||||
< newer_mtime_option))
|
||||
|| excluded_name (current_file_name))
|
||||
|| excluded_name (current_stat_info.file_name))
|
||||
{
|
||||
switch (current_header->header.typeflag)
|
||||
{
|
||||
@@ -99,17 +106,17 @@ read_and (void (*do_something) ())
|
||||
case GNUTYPE_MULTIVOL:
|
||||
case GNUTYPE_NAMES:
|
||||
break;
|
||||
|
||||
|
||||
case DIRTYPE:
|
||||
if (show_omitted_dirs_option)
|
||||
WARN ((0, 0, _("%s: Omitting"),
|
||||
quotearg_colon (current_file_name)));
|
||||
quotearg_colon (current_stat_info.file_name)));
|
||||
/* Fall through. */
|
||||
default:
|
||||
skip_member ();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*do_something) ();
|
||||
continue;
|
||||
@@ -123,10 +130,19 @@ read_and (void (*do_something) ())
|
||||
}
|
||||
|
||||
set_next_block_after (current_header);
|
||||
|
||||
if (!ignore_zeros_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
status = read_header (false);
|
||||
if (status == HEADER_ZERO_BLOCK)
|
||||
break;
|
||||
WARN ((0, 0, _("A lone zero block at %s"),
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
|
||||
}
|
||||
status = prev_status;
|
||||
if (ignore_zeros_option)
|
||||
continue;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
if (block_number_option)
|
||||
@@ -156,11 +172,15 @@ read_and (void (*do_something) ())
|
||||
case HEADER_FAILURE:
|
||||
/* We are in the middle of a cascade of errors. */
|
||||
break;
|
||||
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (!all_names_found (¤t_stat_info));
|
||||
|
||||
close_archive ();
|
||||
names_notfound (); /* print names not found */
|
||||
@@ -172,12 +192,9 @@ list_archive (void)
|
||||
{
|
||||
/* Print the header block. */
|
||||
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, 0);
|
||||
if (verbose_option)
|
||||
{
|
||||
if (verbose_option > 1)
|
||||
decode_header (current_header, ¤t_stat, ¤t_format, 0);
|
||||
print_header ();
|
||||
}
|
||||
print_header (¤t_stat_info, -1);
|
||||
|
||||
if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
|
||||
{
|
||||
@@ -188,10 +205,10 @@ list_archive (void)
|
||||
set_next_block_after (current_header);
|
||||
if (multi_volume_option)
|
||||
{
|
||||
assign_string (&save_name, current_file_name);
|
||||
save_totsize = current_stat.st_size;
|
||||
assign_string (&save_name, current_stat_info.file_name);
|
||||
save_totsize = current_stat_info.stat.st_size;
|
||||
}
|
||||
for (size = current_stat.st_size; size > 0; size -= written)
|
||||
for (size = current_stat_info.stat.st_size; size > 0; size -= written)
|
||||
{
|
||||
if (multi_volume_option)
|
||||
save_sizeleft = size;
|
||||
@@ -210,7 +227,7 @@ list_archive (void)
|
||||
(data_block->buffer + written - 1));
|
||||
if (check != written)
|
||||
{
|
||||
write_error_details (current_file_name, check, written);
|
||||
write_error_details (current_stat_info.file_name, check, written);
|
||||
skip_file (size - written);
|
||||
break;
|
||||
}
|
||||
@@ -224,7 +241,7 @@ list_archive (void)
|
||||
}
|
||||
|
||||
if (multi_volume_option)
|
||||
assign_string (&save_name, current_file_name);
|
||||
assign_string (&save_name, current_stat_info.file_name);
|
||||
|
||||
skip_member ();
|
||||
|
||||
@@ -234,11 +251,14 @@ list_archive (void)
|
||||
|
||||
/* 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.st_size.
|
||||
current_stat_info.stat.st_size.
|
||||
|
||||
Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
|
||||
block full of zeros (EOF marker).
|
||||
|
||||
If RAW_EXTENDED_HEADERS is nonzero, do not automagically fold the
|
||||
GNU long name and link headers into later headers.
|
||||
|
||||
You must always set_next_block_after(current_header) to skip past
|
||||
the header which this routine reads. */
|
||||
|
||||
@@ -252,7 +272,7 @@ list_archive (void)
|
||||
computes two checksums -- signed and unsigned. */
|
||||
|
||||
enum read_header
|
||||
read_header (void)
|
||||
read_header (bool raw_extended_headers)
|
||||
{
|
||||
size_t i;
|
||||
int unsigned_sum; /* the POSIX one :-) */
|
||||
@@ -261,11 +281,14 @@ read_header (void)
|
||||
uintmax_t parsed_sum;
|
||||
char *p;
|
||||
union block *header;
|
||||
char **longp;
|
||||
union block *header_copy;
|
||||
char *bp;
|
||||
union block *data_block;
|
||||
size_t size, written;
|
||||
static char *next_long_name, *next_long_link;
|
||||
union block *next_long_name = 0;
|
||||
union block *next_long_link = 0;
|
||||
size_t next_long_name_blocks;
|
||||
size_t next_long_link_blocks;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -311,43 +334,75 @@ read_header (void)
|
||||
/* Good block. Decode file size and return. */
|
||||
|
||||
if (header->header.typeflag == LNKTYPE)
|
||||
current_stat.st_size = 0; /* links 0 size on tape */
|
||||
current_stat_info.stat.st_size = 0; /* links 0 size on tape */
|
||||
else
|
||||
current_stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
current_stat_info.stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK
|
||||
|| header->header.typeflag == XHDTYPE
|
||||
|| header->header.typeflag == XGLTYPE)
|
||||
{
|
||||
longp = ((header->header.typeflag == GNUTYPE_LONGNAME)
|
||||
? &next_long_name
|
||||
: &next_long_link);
|
||||
|
||||
set_next_block_after (header);
|
||||
if (*longp)
|
||||
free (*longp);
|
||||
size = current_stat.st_size;
|
||||
if (size != current_stat.st_size)
|
||||
xalloc_die ();
|
||||
bp = *longp = xmalloc (size);
|
||||
|
||||
for (; size > 0; size -= written)
|
||||
if (raw_extended_headers)
|
||||
return HEADER_SUCCESS_EXTENDED;
|
||||
else if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
||||
{
|
||||
data_block = find_next_block ();
|
||||
if (! data_block)
|
||||
size_t name_size = current_stat_info.stat.st_size;
|
||||
size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE;
|
||||
if (name_size != current_stat_info.stat.st_size
|
||||
|| size < name_size)
|
||||
xalloc_die ();
|
||||
|
||||
header_copy = xmalloc (size + 1);
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
break;
|
||||
if (next_long_name)
|
||||
free (next_long_name);
|
||||
next_long_name = header_copy;
|
||||
next_long_name_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
written = available_space_after (data_block);
|
||||
if (written > size)
|
||||
written = size;
|
||||
else
|
||||
{
|
||||
if (next_long_link)
|
||||
free (next_long_link);
|
||||
next_long_link = header_copy;
|
||||
next_long_link_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
|
||||
set_next_block_after (header);
|
||||
*header_copy = *header;
|
||||
bp = header_copy->buffer + BLOCKSIZE;
|
||||
|
||||
memcpy (bp, data_block->buffer, written);
|
||||
bp += written;
|
||||
set_next_block_after ((union block *)
|
||||
(data_block->buffer + written - 1));
|
||||
for (size -= BLOCKSIZE; size > 0; size -= written)
|
||||
{
|
||||
data_block = find_next_block ();
|
||||
if (! data_block)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
break;
|
||||
}
|
||||
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 *)
|
||||
(data_block->buffer + written - 1));
|
||||
}
|
||||
|
||||
*bp = '\0';
|
||||
}
|
||||
|
||||
else if (header->header.typeflag == XHDTYPE)
|
||||
xheader_read (header, OFF_FROM_HEADER (header->header.size));
|
||||
else if (header->header.typeflag == XGLTYPE)
|
||||
{
|
||||
xheader_read (header, OFF_FROM_HEADER (header->header.size));
|
||||
xheader_decode_global ();
|
||||
}
|
||||
|
||||
/* Loop! */
|
||||
|
||||
}
|
||||
@@ -357,8 +412,16 @@ read_header (void)
|
||||
struct posix_header const *h = ¤t_header->header;
|
||||
char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
|
||||
|
||||
name = next_long_name;
|
||||
if (! name)
|
||||
if (recent_long_name)
|
||||
free (recent_long_name);
|
||||
|
||||
if (next_long_name)
|
||||
{
|
||||
name = next_long_name->buffer + BLOCKSIZE;
|
||||
recent_long_name = next_long_name;
|
||||
recent_long_name_blocks = next_long_name_blocks;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Accept file names as specified by POSIX.1-1996
|
||||
section 10.1.1. */
|
||||
@@ -379,33 +442,39 @@ read_header (void)
|
||||
memcpy (np, h->name, sizeof h->name);
|
||||
np[sizeof h->name] = '\0';
|
||||
name = namebuf;
|
||||
recent_long_name = 0;
|
||||
recent_long_name_blocks = 0;
|
||||
}
|
||||
assign_string (¤t_file_name, name);
|
||||
if (next_long_name)
|
||||
assign_string (¤t_stat_info.orig_file_name, name);
|
||||
assign_string (¤t_stat_info.file_name, name);
|
||||
current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name);
|
||||
|
||||
if (recent_long_link)
|
||||
free (recent_long_link);
|
||||
|
||||
if (next_long_link)
|
||||
{
|
||||
free (next_long_name);
|
||||
next_long_name = 0;
|
||||
name = next_long_link->buffer + BLOCKSIZE;
|
||||
recent_long_link = next_long_link;
|
||||
recent_long_link_blocks = next_long_link_blocks;
|
||||
}
|
||||
|
||||
name = next_long_link;
|
||||
if (! name)
|
||||
else
|
||||
{
|
||||
memcpy (namebuf, h->linkname, sizeof h->linkname);
|
||||
namebuf[sizeof h->linkname] = '\0';
|
||||
name = namebuf;
|
||||
recent_long_link = 0;
|
||||
recent_long_link_blocks = 0;
|
||||
}
|
||||
assign_string (¤t_link_name, name);
|
||||
if (next_long_link)
|
||||
{
|
||||
free (next_long_link);
|
||||
next_long_link = 0;
|
||||
}
|
||||
assign_string (¤t_stat_info.link_name, name);
|
||||
|
||||
return HEADER_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
|
||||
|
||||
/* Decode things from a file HEADER block into STAT_INFO, also setting
|
||||
*FORMAT_POINTER depending on the header block format. If
|
||||
DO_USER_GROUP, decode the user/group information (this is useful
|
||||
@@ -420,68 +489,90 @@ read_header (void)
|
||||
should decode it without uid/gid before calling a routine,
|
||||
e.g. print_header, that assumes decoded data. */
|
||||
void
|
||||
decode_header (union block *header, struct stat *stat_info,
|
||||
decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
enum archive_format *format_pointer, int do_user_group)
|
||||
{
|
||||
enum archive_format format;
|
||||
|
||||
if (strcmp (header->header.magic, TMAGIC) == 0)
|
||||
format = POSIX_FORMAT;
|
||||
{
|
||||
if (header->star_header.prefix[130] == 0
|
||||
&& ISOCTAL (header->star_header.atime[0])
|
||||
&& header->star_header.atime[11] == ' '
|
||||
&& ISOCTAL (header->star_header.ctime[0])
|
||||
&& header->star_header.ctime[11] == ' ')
|
||||
format = STAR_FORMAT;
|
||||
else if (extended_header.size)
|
||||
format = POSIX_FORMAT;
|
||||
else
|
||||
format = USTAR_FORMAT;
|
||||
}
|
||||
else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
|
||||
format = OLDGNU_FORMAT;
|
||||
else
|
||||
format = V7_FORMAT;
|
||||
*format_pointer = format;
|
||||
|
||||
stat_info->st_mode = MODE_FROM_HEADER (header->header.mode);
|
||||
stat_info->st_mtime = TIME_FROM_HEADER (header->header.mtime);
|
||||
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);
|
||||
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;
|
||||
|
||||
if (format == OLDGNU_FORMAT && incremental_option)
|
||||
{
|
||||
stat_info->st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
|
||||
stat_info->st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
|
||||
stat_info->stat.st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
|
||||
stat_info->stat.st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
|
||||
}
|
||||
|
||||
if (format == V7_FORMAT)
|
||||
{
|
||||
stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
|
||||
stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
|
||||
stat_info->st_rdev = 0;
|
||||
stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid);
|
||||
stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
|
||||
stat_info->stat.st_rdev = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (format == STAR_FORMAT)
|
||||
{
|
||||
stat_info->stat.st_atime = TIME_FROM_HEADER (header->star_header.atime);
|
||||
stat_info->stat.st_ctime = TIME_FROM_HEADER (header->star_header.ctime);
|
||||
}
|
||||
|
||||
if (do_user_group)
|
||||
{
|
||||
/* FIXME: Decide if this should somewhat depend on -p. */
|
||||
|
||||
if (numeric_owner_option
|
||||
|| !*header->header.uname
|
||||
|| !uname_to_uid (header->header.uname, &stat_info->st_uid))
|
||||
stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
|
||||
|| !uname_to_uid (header->header.uname, &stat_info->stat.st_uid))
|
||||
stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid);
|
||||
|
||||
if (numeric_owner_option
|
||||
|| !*header->header.gname
|
||||
|| !gname_to_gid (header->header.gname, &stat_info->st_gid))
|
||||
stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
|
||||
|| !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:
|
||||
stat_info->st_rdev
|
||||
= makedev (MAJOR_FROM_HEADER (header->header.devmajor),
|
||||
MINOR_FROM_HEADER (header->header.devminor));
|
||||
break;
|
||||
|
||||
case CHRTYPE:
|
||||
stat_info->st_rdev
|
||||
= makedev (MAJOR_FROM_HEADER (header->header.devmajor),
|
||||
MINOR_FROM_HEADER (header->header.devminor));
|
||||
stat_info->stat.st_rdev = makedev (stat_info->devmajor, stat_info->devminor);
|
||||
break;
|
||||
|
||||
default:
|
||||
stat_info->st_rdev = 0;
|
||||
stat_info->stat.st_rdev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
current_stat_info.archive_file_size = current_stat_info.stat.st_size;
|
||||
xheader_decode (stat_info);
|
||||
}
|
||||
|
||||
/* Convert buffer at WHERE0 of size DIGS from external format to
|
||||
@@ -680,7 +771,7 @@ from_header (char const *where0, size_t digs, char const *type,
|
||||
*--value_string = '-';
|
||||
if (minus_minval)
|
||||
*--minval_string = '-';
|
||||
ERROR ((0, 0, _("Archive value %s is out of %s range %s..%s"),
|
||||
ERROR ((0, 0, _("Archive value %s is out of %s range %s.%s"),
|
||||
value_string, type,
|
||||
minval_string, STRINGIFY_BIGINT (maxval, maxval_buf)));
|
||||
}
|
||||
@@ -745,7 +836,7 @@ off_from_header (const char *p, size_t s)
|
||||
size_t
|
||||
size_from_header (const char *p, size_t s)
|
||||
{
|
||||
return from_header (p, s, "size_t", (uintmax_t) 0,
|
||||
return from_header (p, s, "size_t", (uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (size_t));
|
||||
}
|
||||
|
||||
@@ -811,8 +902,8 @@ tartime (time_t t)
|
||||
struct tm *tm = localtime (&t);
|
||||
if (tm)
|
||||
{
|
||||
sprintf (buffer, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
sprintf (buffer, "%04ld-%02d-%02d %02d:%02d:%02d",
|
||||
tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
return buffer;
|
||||
}
|
||||
@@ -842,7 +933,7 @@ tartime (time_t t)
|
||||
|
||||
|
||||
/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
|
||||
HEAD_STANDARD, which must be set up in advance. Not very clean... */
|
||||
HEAD_STANDARD, which must be set up in advance. Not very clean.. */
|
||||
|
||||
/* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the
|
||||
columns never shift during the listing. */
|
||||
@@ -857,10 +948,12 @@ static int ugswidth = UGSWIDTH; /* maximum width encountered so far */
|
||||
#endif
|
||||
|
||||
void
|
||||
print_header (void)
|
||||
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;
|
||||
@@ -872,14 +965,18 @@ print_header (void)
|
||||
if (block_number_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
if (block_ordinal < 0)
|
||||
block_ordinal = current_block_ordinal ();
|
||||
block_ordinal -= recent_long_name_blocks;
|
||||
block_ordinal -= recent_long_link_blocks;
|
||||
fprintf (stdlis, _("block %s: "),
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf));
|
||||
STRINGIFY_BIGINT (block_ordinal, buf));
|
||||
}
|
||||
|
||||
if (verbose_option <= 1)
|
||||
{
|
||||
/* Just the fax, mam. */
|
||||
fprintf (stdlis, "%s\n", quotearg (current_file_name));
|
||||
fprintf (stdlis, "%s\n", quotearg (temp_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -902,17 +999,20 @@ print_header (void)
|
||||
|
||||
case GNUTYPE_LONGNAME:
|
||||
case GNUTYPE_LONGLINK:
|
||||
modes[0] = 'L';
|
||||
ERROR ((0, 0, _("Visible longname error")));
|
||||
break;
|
||||
|
||||
case GNUTYPE_SPARSE:
|
||||
case REGTYPE:
|
||||
case AREGTYPE:
|
||||
case LNKTYPE:
|
||||
modes[0] = '-';
|
||||
if (current_file_name[strlen (current_file_name) - 1] == '/')
|
||||
if (temp_name[strlen (temp_name) - 1] == '/')
|
||||
modes[0] = 'd';
|
||||
break;
|
||||
case LNKTYPE:
|
||||
modes[0] = 'h';
|
||||
break;
|
||||
case GNUTYPE_DUMPDIR:
|
||||
modes[0] = 'd';
|
||||
break;
|
||||
@@ -936,17 +1036,17 @@ print_header (void)
|
||||
break;
|
||||
}
|
||||
|
||||
decode_mode (current_stat.st_mode, modes + 1);
|
||||
decode_mode (st->stat.st_mode, modes + 1);
|
||||
|
||||
/* Time stamp. */
|
||||
|
||||
time_stamp = tartime (current_stat.st_mtime);
|
||||
time_stamp = tartime (st->stat.st_mtime);
|
||||
|
||||
/* User and group names. */
|
||||
|
||||
if (*current_header->header.uname && current_format != V7_FORMAT
|
||||
if (st->uname && current_format != V7_FORMAT
|
||||
&& !numeric_owner_option)
|
||||
user = current_header->header.uname;
|
||||
user = st->uname;
|
||||
else
|
||||
{
|
||||
/* Try parsing it as an unsigned integer first, and as a
|
||||
@@ -966,9 +1066,9 @@ print_header (void)
|
||||
}
|
||||
}
|
||||
|
||||
if (*current_header->header.gname && current_format != V7_FORMAT
|
||||
if (st->gname && current_format != V7_FORMAT
|
||||
&& !numeric_owner_option)
|
||||
group = current_header->header.gname;
|
||||
group = st->gname;
|
||||
else
|
||||
{
|
||||
/* Try parsing it as an unsigned integer first, and as a
|
||||
@@ -995,10 +1095,10 @@ print_header (void)
|
||||
case CHRTYPE:
|
||||
case BLKTYPE:
|
||||
strcpy (size,
|
||||
STRINGIFY_BIGINT (major (current_stat.st_rdev), uintbuf));
|
||||
STRINGIFY_BIGINT (major (st->stat.st_rdev), uintbuf));
|
||||
strcat (size, ",");
|
||||
strcat (size,
|
||||
STRINGIFY_BIGINT (minor (current_stat.st_rdev), uintbuf));
|
||||
STRINGIFY_BIGINT (minor (st->stat.st_rdev), uintbuf));
|
||||
break;
|
||||
case GNUTYPE_SPARSE:
|
||||
strcpy (size,
|
||||
@@ -1008,7 +1108,8 @@ print_header (void)
|
||||
uintbuf));
|
||||
break;
|
||||
default:
|
||||
strcpy (size, STRINGIFY_BIGINT (current_stat.st_size, uintbuf));
|
||||
/* st->stat.st_size keeps stored file size */
|
||||
strcpy (size, STRINGIFY_BIGINT (st->archive_file_size, uintbuf));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1021,16 +1122,16 @@ print_header (void)
|
||||
fprintf (stdlis, "%s %s/%s %*s%s %s",
|
||||
modes, user, group, ugswidth - pad, "", size, time_stamp);
|
||||
|
||||
fprintf (stdlis, " %s", quotearg (current_file_name));
|
||||
fprintf (stdlis, " %s", quotearg (temp_name));
|
||||
|
||||
switch (current_header->header.typeflag)
|
||||
{
|
||||
case SYMTYPE:
|
||||
fprintf (stdlis, " -> %s\n", quotearg (current_link_name));
|
||||
fprintf (stdlis, " -> %s\n", quotearg (st->link_name));
|
||||
break;
|
||||
|
||||
case LNKTYPE:
|
||||
fprintf (stdlis, _(" link to %s\n"), quotearg (current_link_name));
|
||||
fprintf (stdlis, _(" link to %s\n"), quotearg (st->link_name));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1055,6 +1156,14 @@ print_header (void)
|
||||
putc ('\n', stdlis);
|
||||
break;
|
||||
|
||||
case GNUTYPE_LONGLINK:
|
||||
fprintf (stdlis, _("--Long Link--\n"));
|
||||
break;
|
||||
|
||||
case GNUTYPE_LONGNAME:
|
||||
fprintf (stdlis, _("--Long Name--\n"));
|
||||
break;
|
||||
|
||||
case GNUTYPE_VOLHDR:
|
||||
fprintf (stdlis, _("--Volume Header--\n"));
|
||||
break;
|
||||
@@ -1132,7 +1241,8 @@ skip_member (void)
|
||||
char save_typeflag = current_header->header.typeflag;
|
||||
set_next_block_after (current_header);
|
||||
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
if (current_format == OLDGNU_FORMAT
|
||||
&& current_header->oldgnu_header.isextended)
|
||||
{
|
||||
union block *exhdr;
|
||||
do
|
||||
@@ -1146,5 +1256,5 @@ skip_member (void)
|
||||
}
|
||||
|
||||
if (save_typeflag != DIRTYPE)
|
||||
skip_file (current_stat.st_size);
|
||||
skip_file (current_stat_info.stat.st_size);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ struct mangled
|
||||
void
|
||||
extract_mangle (void)
|
||||
{
|
||||
off_t size = current_stat.st_size;
|
||||
off_t size = current_stat_info.stat.st_size;
|
||||
char *buffer = xmalloc ((size_t) (size + 1));
|
||||
char *copy = buffer;
|
||||
char *cursor = buffer;
|
||||
|
||||
1011
src/misc.c
1011
src/misc.c
File diff suppressed because it is too large
Load Diff
339
src/names.c
339
src/names.c
@@ -1,7 +1,7 @@
|
||||
/* Various processing of names.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001 Free
|
||||
Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1992, 1994, 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
|
||||
@@ -20,9 +20,7 @@
|
||||
#include "system.h"
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <grp.h>
|
||||
#include <hash.h>
|
||||
#include <pwd.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -43,15 +41,15 @@ struct group *getgrgid ();
|
||||
This code should also be modified for non-UNIX systems to do something
|
||||
reasonable. */
|
||||
|
||||
static char cached_uname[UNAME_FIELD_SIZE];
|
||||
static char cached_gname[GNAME_FIELD_SIZE];
|
||||
static char *cached_uname;
|
||||
static char *cached_gname;
|
||||
|
||||
static uid_t cached_uid; /* valid only if cached_uname is not empty */
|
||||
static gid_t cached_gid; /* valid only if cached_gname is not empty */
|
||||
|
||||
/* These variables are valid only if nonempty. */
|
||||
static char cached_no_such_uname[UNAME_FIELD_SIZE];
|
||||
static char cached_no_such_gname[GNAME_FIELD_SIZE];
|
||||
static char *cached_no_such_uname;
|
||||
static char *cached_no_such_gname;
|
||||
|
||||
/* These variables are valid only if nonzero. It's not worth optimizing
|
||||
the case for weird systems where 0 is not a valid uid or gid. */
|
||||
@@ -60,87 +58,87 @@ static gid_t cached_no_such_gid;
|
||||
|
||||
/* Given UID, find the corresponding UNAME. */
|
||||
void
|
||||
uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
|
||||
uid_to_uname (uid_t uid, char **uname)
|
||||
{
|
||||
struct passwd *passwd;
|
||||
|
||||
if (uid != 0 && uid == cached_no_such_uid)
|
||||
{
|
||||
*uname = '\0';
|
||||
*uname = strdup ("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cached_uname[0] || uid != cached_uid)
|
||||
if (!cached_uname || uid != cached_uid)
|
||||
{
|
||||
passwd = getpwuid (uid);
|
||||
if (passwd)
|
||||
{
|
||||
cached_uid = uid;
|
||||
strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE);
|
||||
assign_string (&cached_uname, passwd->pw_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
cached_no_such_uid = uid;
|
||||
*uname = '\0';
|
||||
*uname = strdup ("");
|
||||
return;
|
||||
}
|
||||
}
|
||||
strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
|
||||
*uname = strdup (cached_uname);
|
||||
}
|
||||
|
||||
/* Given GID, find the corresponding GNAME. */
|
||||
void
|
||||
gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
|
||||
gid_to_gname (gid_t gid, char **gname)
|
||||
{
|
||||
struct group *group;
|
||||
|
||||
if (gid != 0 && gid == cached_no_such_gid)
|
||||
{
|
||||
*gname = '\0';
|
||||
*gname = strdup ("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cached_gname[0] || gid != cached_gid)
|
||||
if (!cached_gname || gid != cached_gid)
|
||||
{
|
||||
group = getgrgid (gid);
|
||||
if (group)
|
||||
{
|
||||
cached_gid = gid;
|
||||
strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE);
|
||||
assign_string (&cached_gname, group->gr_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
cached_no_such_gid = gid;
|
||||
*gname = '\0';
|
||||
*gname = strdup ("");
|
||||
return;
|
||||
}
|
||||
}
|
||||
strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
|
||||
*gname = strdup (cached_gname);
|
||||
}
|
||||
|
||||
/* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
|
||||
int
|
||||
uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
|
||||
uname_to_uid (char *uname, uid_t *uidp)
|
||||
{
|
||||
struct passwd *passwd;
|
||||
|
||||
if (cached_no_such_uname[0]
|
||||
&& strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
|
||||
if (cached_no_such_uname
|
||||
&& strcmp (uname, cached_no_such_uname) == 0)
|
||||
return 0;
|
||||
|
||||
if (!cached_uname[0]
|
||||
if (!cached_uname
|
||||
|| uname[0] != cached_uname[0]
|
||||
|| strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
|
||||
|| strcmp (uname, cached_uname) != 0)
|
||||
{
|
||||
passwd = getpwnam (uname);
|
||||
if (passwd)
|
||||
{
|
||||
cached_uid = passwd->pw_uid;
|
||||
strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
|
||||
assign_string (&cached_uname, passwd->pw_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
|
||||
assign_string (&cached_no_such_uname, uname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -150,33 +148,34 @@ uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
|
||||
|
||||
/* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
|
||||
int
|
||||
gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
|
||||
gname_to_gid (char *gname, gid_t *gidp)
|
||||
{
|
||||
struct group *group;
|
||||
|
||||
if (cached_no_such_gname[0]
|
||||
&& strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
|
||||
if (cached_no_such_gname
|
||||
&& strcmp (gname, cached_no_such_gname) == 0)
|
||||
return 0;
|
||||
|
||||
if (!cached_gname[0]
|
||||
if (!cached_gname
|
||||
|| gname[0] != cached_gname[0]
|
||||
|| strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
|
||||
|| strcmp (gname, cached_gname) != 0)
|
||||
{
|
||||
group = getgrnam (gname);
|
||||
if (group)
|
||||
{
|
||||
cached_gid = group->gr_gid;
|
||||
strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
|
||||
assign_string (&cached_gname, gname);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
|
||||
assign_string (&cached_no_such_gname, gname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*gidp = cached_gid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Names from the command call. */
|
||||
|
||||
@@ -439,7 +438,7 @@ name_gather (void)
|
||||
buffer->change_dir = change_dir;
|
||||
strcpy (buffer->name, name);
|
||||
buffer->next = 0;
|
||||
buffer->found = 0;
|
||||
buffer->found_count = 0;
|
||||
|
||||
namelist = buffer;
|
||||
nametail = &namelist->next;
|
||||
@@ -496,7 +495,7 @@ addname (char const *string, int change_dir)
|
||||
|
||||
name->next = 0;
|
||||
name->length = length;
|
||||
name->found = 0;
|
||||
name->found_count = 0;
|
||||
name->regexp = 0; /* assume not a regular expression */
|
||||
name->firstch = 1; /* assume first char is literal */
|
||||
name->change_dir = change_dir;
|
||||
@@ -531,7 +530,8 @@ namelist_match (char const *path, size_t length)
|
||||
if (p->regexp
|
||||
? fnmatch (p->name, path, recursion_option) == 0
|
||||
: (p->length <= length
|
||||
&& (path[p->length] == '\0' || ISSLASH (path[p->length]))
|
||||
&& (path[p->length] == '\0'
|
||||
|| (ISSLASH (path[p->length]) && recursion_option))
|
||||
&& memcmp (path, p->name, p->length) == 0))
|
||||
return p;
|
||||
}
|
||||
@@ -564,7 +564,9 @@ name_match (const char *path)
|
||||
cursor = namelist_match (path, length);
|
||||
if (cursor)
|
||||
{
|
||||
cursor->found = 1; /* remember it matched */
|
||||
if (!(ISSLASH (path[cursor->length]) && recursion_option)
|
||||
|| cursor->found_count == 0)
|
||||
cursor->found_count++; /* remember it matched */
|
||||
if (starting_file_option)
|
||||
{
|
||||
free (namelist);
|
||||
@@ -572,20 +574,20 @@ name_match (const char *path)
|
||||
nametail = &namelist;
|
||||
}
|
||||
chdir_do (cursor->change_dir);
|
||||
|
||||
|
||||
/* We got a match. */
|
||||
return 1;
|
||||
return ISFOUND (cursor);
|
||||
}
|
||||
|
||||
/* Filename from archive not found in namelist. If we have the whole
|
||||
namelist here, just return 0. Otherwise, read the next name in and
|
||||
compare it. If this was the last name, namelist->found will remain
|
||||
on. If not, we loop to compare the newly read name. */
|
||||
compare it. If this was the last name, namelist->found_count will
|
||||
remain on. If not, we loop to compare the newly read name. */
|
||||
|
||||
if (same_order_option && namelist->found)
|
||||
if (same_order_option && namelist->found_count)
|
||||
{
|
||||
name_gather (); /* read one more */
|
||||
if (namelist->found)
|
||||
if (namelist->found_count)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -593,6 +595,34 @@ name_match (const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if all names from the namelist were processed.
|
||||
P is the stat_info of the most recently processed entry.
|
||||
The decision is postponed until the next entry is read if:
|
||||
|
||||
1) P ended with a slash (i.e. it was a directory)
|
||||
2) P matches any entry from the namelist *and* represents a subdirectory
|
||||
or a file lying under this entry (in the terms of directory structure).
|
||||
|
||||
This is necessary to handle contents of directories. */
|
||||
bool
|
||||
all_names_found (struct tar_stat_info *p)
|
||||
{
|
||||
struct name const *cursor;
|
||||
size_t len;
|
||||
|
||||
if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
|
||||
return false;
|
||||
len = strlen (p->file_name);
|
||||
for (cursor = namelist; cursor; cursor = cursor->next)
|
||||
{
|
||||
if (cursor->regexp
|
||||
|| (!WASFOUND(cursor) && !cursor->fake)
|
||||
|| (len >= cursor->length && ISSLASH (p->file_name[cursor->length])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Print the names of things in the namelist that were not matched. */
|
||||
void
|
||||
names_notfound (void)
|
||||
@@ -600,10 +630,16 @@ names_notfound (void)
|
||||
struct name const *cursor;
|
||||
|
||||
for (cursor = namelist; cursor; cursor = cursor->next)
|
||||
if (!cursor->found && !cursor->fake)
|
||||
ERROR ((0, 0, _("%s: Not found in archive"),
|
||||
quotearg_colon (cursor->name)));
|
||||
|
||||
if (!WASFOUND(cursor) && !cursor->fake)
|
||||
{
|
||||
if (cursor->found_count == 0)
|
||||
ERROR ((0, 0, _("%s: Not found in archive"),
|
||||
quotearg_colon (cursor->name)));
|
||||
else
|
||||
ERROR ((0, 0, _("%s: Required occurrence not found in archive"),
|
||||
quotearg_colon (cursor->name)));
|
||||
}
|
||||
|
||||
/* Don't bother freeing the name list; we're about to exit. */
|
||||
namelist = 0;
|
||||
nametail = &namelist;
|
||||
@@ -612,7 +648,7 @@ names_notfound (void)
|
||||
{
|
||||
char *name;
|
||||
|
||||
while (name = name_next (1), name)
|
||||
while ((name = name_next (1)) != NULL)
|
||||
ERROR ((0, 0, _("%s: Not found in archive"),
|
||||
quotearg_colon (name)));
|
||||
}
|
||||
@@ -701,7 +737,7 @@ merge_sort (struct name *list, int length,
|
||||
static int
|
||||
compare_names (struct name const *n1, struct name const *n2)
|
||||
{
|
||||
int found_diff = n2->found - n1->found;
|
||||
int found_diff = WASFOUND(n2) - WASFOUND(n1);
|
||||
return found_diff ? found_diff : strcmp (n1->name, n2->name);
|
||||
}
|
||||
|
||||
@@ -787,7 +823,7 @@ collect_and_sort_names (void)
|
||||
for (name = namelist; name; name = next_name)
|
||||
{
|
||||
next_name = name->next;
|
||||
if (name->found || name->dir_contents)
|
||||
if (name->found_count || name->dir_contents)
|
||||
continue;
|
||||
if (name->regexp) /* FIXME: just skip regexps for now */
|
||||
continue;
|
||||
@@ -797,15 +833,12 @@ collect_and_sort_names (void)
|
||||
|
||||
if (deref_stat (dereference_option, name->name, &statbuf) != 0)
|
||||
{
|
||||
if (ignore_failed_read_option)
|
||||
stat_warn (name->name);
|
||||
else
|
||||
stat_error (name->name);
|
||||
stat_diag (name->name);
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR (statbuf.st_mode))
|
||||
{
|
||||
name->found = 1;
|
||||
name->found_count++;
|
||||
add_hierarchy_to_namelist (name, statbuf.st_dev);
|
||||
}
|
||||
}
|
||||
@@ -816,7 +849,7 @@ collect_and_sort_names (void)
|
||||
namelist = merge_sort (namelist, num_names, compare_names);
|
||||
|
||||
for (name = namelist; name; name = name->next)
|
||||
name->found = 0;
|
||||
name->found_count = 0;
|
||||
}
|
||||
|
||||
/* This is like name_match, except that it returns a pointer to the
|
||||
@@ -836,13 +869,13 @@ name_scan (const char *path)
|
||||
|
||||
/* Filename from archive not found in namelist. If we have the whole
|
||||
namelist here, just return 0. Otherwise, read the next name in and
|
||||
compare it. If this was the last name, namelist->found will remain
|
||||
on. If not, we loop to compare the newly read name. */
|
||||
compare it. If this was the last name, namelist->found_count will
|
||||
remain on. If not, we loop to compare the newly read name. */
|
||||
|
||||
if (same_order_option && namelist && namelist->found)
|
||||
if (same_order_option && namelist && namelist->found_count)
|
||||
{
|
||||
name_gather (); /* read one more */
|
||||
if (namelist->found)
|
||||
if (namelist->found_count)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -860,11 +893,11 @@ name_from_list (void)
|
||||
{
|
||||
if (!gnu_list_name)
|
||||
gnu_list_name = namelist;
|
||||
while (gnu_list_name && (gnu_list_name->found | gnu_list_name->fake))
|
||||
while (gnu_list_name && (gnu_list_name->found_count || gnu_list_name->fake))
|
||||
gnu_list_name = gnu_list_name->next;
|
||||
if (gnu_list_name)
|
||||
{
|
||||
gnu_list_name->found = 1;
|
||||
gnu_list_name->found_count++;
|
||||
chdir_do (gnu_list_name->change_dir);
|
||||
return gnu_list_name->name;
|
||||
}
|
||||
@@ -878,7 +911,7 @@ blank_name_list (void)
|
||||
|
||||
gnu_list_name = 0;
|
||||
for (name = namelist; name; name = name->next)
|
||||
name->found = 0;
|
||||
name->found_count = 0;
|
||||
}
|
||||
|
||||
/* Yield a newly allocated file name consisting of PATH concatenated to
|
||||
@@ -896,46 +929,192 @@ new_name (const char *path, const char *name)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Return nonzero if file NAME is excluded. Exclude a name if its
|
||||
prefix matches a pattern that contains slashes, or if one of its
|
||||
components matches a pattern that contains no slashes. */
|
||||
/* Return nonzero if file NAME is excluded. */
|
||||
bool
|
||||
excluded_name (char const *name)
|
||||
{
|
||||
return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
|
||||
}
|
||||
|
||||
/* Names to avoid dumping. */
|
||||
static Hash_table *avoided_name_table;
|
||||
/* Hash tables of strings. */
|
||||
|
||||
/* Calculate the hash of an avoided name. */
|
||||
/* Calculate the hash of a string. */
|
||||
static unsigned
|
||||
hash_avoided_name (void const *name, unsigned n_buckets)
|
||||
hash_string_hasher (void const *name, unsigned n_buckets)
|
||||
{
|
||||
return hash_string (name, n_buckets);
|
||||
}
|
||||
|
||||
/* Compare two avoided names for equality. */
|
||||
/* Compare two strings for equality. */
|
||||
static bool
|
||||
compare_avoided_names (void const *name1, void const *name2)
|
||||
hash_string_compare (void const *name1, void const *name2)
|
||||
{
|
||||
return strcmp (name1, name2) == 0;
|
||||
}
|
||||
|
||||
/* Return zero if TABLE contains a copy of STRING; otherwise, insert a
|
||||
copy of STRING to TABLE and return 1. */
|
||||
static bool
|
||||
hash_string_insert (Hash_table **table, char const *string)
|
||||
{
|
||||
Hash_table *t = *table;
|
||||
char *s = xstrdup (string);
|
||||
char *e;
|
||||
|
||||
if (! ((t
|
||||
|| (*table = t = hash_initialize (0, 0, hash_string_hasher,
|
||||
hash_string_compare, 0)))
|
||||
&& (e = hash_insert (t, s))))
|
||||
xalloc_die ();
|
||||
|
||||
if (e == s)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
free (s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 1 if TABLE contains STRING. */
|
||||
static bool
|
||||
hash_string_lookup (Hash_table const *table, char const *string)
|
||||
{
|
||||
return table && hash_lookup (table, string);
|
||||
}
|
||||
|
||||
/* Names to avoid dumping. */
|
||||
static Hash_table *avoided_name_table;
|
||||
|
||||
/* Remember to not archive NAME. */
|
||||
void
|
||||
add_avoided_name (char const *name)
|
||||
{
|
||||
if (! ((avoided_name_table
|
||||
|| (avoided_name_table = hash_initialize (0, 0, hash_avoided_name,
|
||||
compare_avoided_names, 0)))
|
||||
&& hash_insert (avoided_name_table, xstrdup (name))))
|
||||
xalloc_die ();
|
||||
hash_string_insert (&avoided_name_table, name);
|
||||
}
|
||||
|
||||
/* Should NAME be avoided when archiving? */
|
||||
int
|
||||
bool
|
||||
is_avoided_name (char const *name)
|
||||
{
|
||||
return avoided_name_table && hash_lookup (avoided_name_table, name);
|
||||
return hash_string_lookup (avoided_name_table, name);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
FILE_NAME is the target of a hard link, not a member name. */
|
||||
|
||||
char *
|
||||
safer_name_suffix (char const *file_name, bool link_target)
|
||||
{
|
||||
char const *p;
|
||||
|
||||
if (absolute_names_option)
|
||||
p = file_name;
|
||||
else
|
||||
{
|
||||
/* Skip file system prefixes, leading pathnames that contain
|
||||
"..", and leading slashes. */
|
||||
|
||||
size_t prefix_len = FILESYSTEM_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++;
|
||||
if (ISSLASH (c))
|
||||
break;
|
||||
}
|
||||
while (*p);
|
||||
}
|
||||
|
||||
for (p = file_name + prefix_len; ISSLASH (*p); p++)
|
||||
continue;
|
||||
prefix_len = p - file_name;
|
||||
|
||||
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';
|
||||
|
||||
if (hash_string_insert (&prefix_table[link_target], prefix))
|
||||
{
|
||||
static char const *const diagnostic[] =
|
||||
{
|
||||
N_("Removing leading `%s' from member names"),
|
||||
N_("Removing leading `%s' from hard link targets")
|
||||
};
|
||||
WARN ((0, 0, _(diagnostic[link_target]), prefix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! *p)
|
||||
{
|
||||
if (p == file_name)
|
||||
{
|
||||
static char const *const diagnostic[] =
|
||||
{
|
||||
N_("Substituting `.' for empty member name"),
|
||||
N_("Substituting `.' for empty hard link target")
|
||||
};
|
||||
WARN ((0, 0, _(diagnostic[link_target])));
|
||||
}
|
||||
|
||||
p = ".";
|
||||
}
|
||||
|
||||
return (char *) p;
|
||||
}
|
||||
|
||||
/* Return the size of the prefix of FILE_NAME that is removed after
|
||||
stripping NUM leading path 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);
|
||||
while (ISSLASH (*p))
|
||||
p++;
|
||||
while (*p)
|
||||
{
|
||||
bool slash = ISSLASH (*p);
|
||||
p++;
|
||||
if (slash)
|
||||
{
|
||||
if (--num == 0)
|
||||
return p - file_name;
|
||||
while (ISSLASH (*p))
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return nonzero if NAME contains ".." as a path name component. */
|
||||
bool
|
||||
contains_dot_dot (char const *name)
|
||||
{
|
||||
char const *p = name + FILESYSTEM_PREFIX_LEN (name);
|
||||
|
||||
for (;; p++)
|
||||
{
|
||||
if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
|
||||
return 1;
|
||||
|
||||
do
|
||||
{
|
||||
if (! *p++)
|
||||
return 0;
|
||||
}
|
||||
while (! ISSLASH (*p));
|
||||
}
|
||||
}
|
||||
|
||||
49
src/rmt.c
49
src/rmt.c
@@ -1,7 +1,7 @@
|
||||
/* Remote connection server.
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
|
||||
Foundation, Inc.
|
||||
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
|
||||
@@ -32,7 +32,6 @@
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
|
||||
|
||||
#include "system.h"
|
||||
#include <copysym.h>
|
||||
#include <localedir.h>
|
||||
#include <safe-read.h>
|
||||
#include <full-write.h>
|
||||
@@ -130,7 +129,7 @@ get_string (char *string)
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_record_buffer (size_t size)
|
||||
prepare_input_buffer (int fd, size_t size)
|
||||
{
|
||||
if (size <= allocated_size)
|
||||
return;
|
||||
@@ -151,14 +150,14 @@ prepare_record_buffer (size_t size)
|
||||
allocated_size = size;
|
||||
|
||||
#ifdef SO_RCVBUF
|
||||
while (size > 1024 &&
|
||||
(setsockopt (STDIN_FILENO, SOL_SOCKET, SO_RCVBUF,
|
||||
(char *) &size, sizeof size)
|
||||
< 0))
|
||||
size -= 1024;
|
||||
#else
|
||||
/* FIXME: I do not see any purpose to the following line... Sigh! */
|
||||
size = 1 + ((size - 1) % 1024);
|
||||
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
|
||||
}
|
||||
|
||||
@@ -263,7 +262,7 @@ Manipulate a tape drive, accepting commands from a remote process.\n\
|
||||
--version Output version info.\n\
|
||||
--help Output this help.\n"),
|
||||
program_name);
|
||||
fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
|
||||
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
exit (status);
|
||||
@@ -294,10 +293,8 @@ main (int argc, char *const *argv)
|
||||
|
||||
case 'v':
|
||||
{
|
||||
char buf[MB_LEN_MAX + 1];
|
||||
printf ("rmt (GNU %s) %s\n", PACKAGE, VERSION);
|
||||
printf ("Copyright %s 2001 Free Software Foundation, Inc.\n",
|
||||
copyright_symbol (buf, sizeof buf));
|
||||
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\
|
||||
@@ -317,7 +314,7 @@ see the file named COPYING for details."));
|
||||
if (debug_file == 0)
|
||||
{
|
||||
report_numbered_error (errno);
|
||||
exit (EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
setbuf (debug_file, 0);
|
||||
}
|
||||
@@ -398,7 +395,7 @@ top:
|
||||
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
|
||||
{
|
||||
report_error_message (N_("Seek offset out of range"));
|
||||
exit (EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
count = nc;
|
||||
}
|
||||
@@ -411,7 +408,7 @@ top:
|
||||
case 2: whence = SEEK_END; break;
|
||||
default:
|
||||
report_error_message (N_("Seek direction out of range"));
|
||||
exit (EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
count = lseek (tape, count, whence);
|
||||
if (count < 0)
|
||||
@@ -442,7 +439,7 @@ top:
|
||||
size = atol (count_string);
|
||||
DEBUG1 ("rmtd: W %s\n", count_string);
|
||||
|
||||
prepare_record_buffer (size);
|
||||
prepare_input_buffer (STDIN_FILENO, size);
|
||||
for (counter = 0; counter < size; counter += status)
|
||||
{
|
||||
status = safe_read (STDIN_FILENO, &record_buffer[counter],
|
||||
@@ -452,7 +449,7 @@ top:
|
||||
DEBUG (_("rmtd: Premature eof\n"));
|
||||
|
||||
report_error_message (N_("Premature end of file"));
|
||||
exit (EXIT_FAILURE); /* exit status used to be 2 */
|
||||
return EXIT_FAILURE; /* exit status used to be 2 */
|
||||
}
|
||||
}
|
||||
status = full_write (tape, record_buffer, size);
|
||||
@@ -470,7 +467,7 @@ top:
|
||||
DEBUG1 ("rmtd: R %s\n", count_string);
|
||||
|
||||
size = atol (count_string);
|
||||
prepare_record_buffer (size);
|
||||
prepare_input_buffer (-1, size);
|
||||
status = safe_read (tape, record_buffer, size);
|
||||
if (status < 0)
|
||||
goto ioerror;
|
||||
@@ -518,7 +515,7 @@ top:
|
||||
if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
|
||||
{
|
||||
report_error_message (N_("Seek offset out of range"));
|
||||
exit (EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
count = nc;
|
||||
}
|
||||
@@ -528,7 +525,7 @@ top:
|
||||
if (mtop.mt_count != count)
|
||||
{
|
||||
report_error_message (N_("Seek offset out of range"));
|
||||
exit (EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
mtop.mt_op = atoi (operation_string);
|
||||
|
||||
@@ -562,7 +559,7 @@ top:
|
||||
DEBUG1 (_("rmtd: Garbage command %c\n"), command);
|
||||
|
||||
report_error_message (N_("Garbage command"));
|
||||
exit (EXIT_FAILURE); /* exit status used to be 3 */
|
||||
return EXIT_FAILURE; /* exit status used to be 3 */
|
||||
}
|
||||
|
||||
respond:
|
||||
|
||||
16
src/rmt.h
16
src/rmt.h
@@ -1,5 +1,7 @@
|
||||
/* Definitions for communicating with a remote tape drive.
|
||||
Copyright 1988, 1992, 1996, 1997, 2001 Free Software Foundation, Inc.
|
||||
|
||||
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
|
||||
@@ -17,12 +19,12 @@
|
||||
|
||||
extern char *rmt_path__;
|
||||
|
||||
int rmt_open__ PARAMS ((const char *, int, int, const char *));
|
||||
int rmt_close__ PARAMS ((int));
|
||||
ssize_t rmt_read__ PARAMS ((int, char *, size_t));
|
||||
ssize_t rmt_write__ PARAMS ((int, char *, size_t));
|
||||
off_t rmt_lseek__ PARAMS ((int, off_t, int));
|
||||
int rmt_ioctl__ PARAMS ((int, int, char *));
|
||||
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'
|
||||
|
||||
@@ -482,10 +482,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
|
||||
close (from_remote[remote_pipe_number][PREAD]);
|
||||
close (from_remote[remote_pipe_number][PWRITE]);
|
||||
|
||||
#if !MSDOS
|
||||
setuid (getuid ());
|
||||
setgid (getgid ());
|
||||
#endif
|
||||
sys_reset_uid_gid ();
|
||||
|
||||
if (remote_user)
|
||||
execl (remote_shell, remote_shell_basename, remote_host,
|
||||
|
||||
778
src/sparse.c
Normal file
778
src/sparse.c
Normal file
@@ -0,0 +1,778 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright (C) 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. */
|
||||
|
||||
#include "system.h"
|
||||
#include <quotearg.h>
|
||||
#include "common.h"
|
||||
|
||||
struct tar_sparse_file;
|
||||
|
||||
enum sparse_scan_state
|
||||
{
|
||||
scan_begin,
|
||||
scan_block,
|
||||
scan_end
|
||||
};
|
||||
|
||||
struct tar_sparse_optab
|
||||
{
|
||||
bool (*init) (struct tar_sparse_file *);
|
||||
bool (*done) (struct tar_sparse_file *);
|
||||
bool (*dump_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);
|
||||
};
|
||||
|
||||
struct tar_sparse_file
|
||||
{
|
||||
int fd; /* File descriptor */
|
||||
size_t dumped_size; /* Number of bytes actually written
|
||||
to the archive */
|
||||
struct tar_stat_info *stat_info; /* Information about the file */
|
||||
struct tar_sparse_optab *optab;
|
||||
void *closure; /* Any additional data optab calls might
|
||||
reqiure */
|
||||
};
|
||||
|
||||
static bool
|
||||
tar_sparse_init (struct tar_sparse_file *file)
|
||||
{
|
||||
file->dumped_size = 0;
|
||||
if (file->optab->init)
|
||||
return file->optab->init (file);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_done (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->done)
|
||||
return file->optab->done (file);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_scan (struct tar_sparse_file *file, enum sparse_scan_state state,
|
||||
void *block)
|
||||
{
|
||||
if (file->optab->scan_block)
|
||||
return file->optab->scan_block (file, state, block);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_dump_region (struct tar_sparse_file *file, size_t index)
|
||||
{
|
||||
if (file->optab->dump_region)
|
||||
return file->optab->dump_region (file, index);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_extract_region (struct tar_sparse_file *file, size_t index)
|
||||
{
|
||||
if (file->optab->extract_region)
|
||||
return file->optab->extract_region (file, index);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_dump_header (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->dump_header)
|
||||
return file->optab->dump_header (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_decode_header (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->decode_header)
|
||||
return file->optab->decode_header (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
lseek_or_error (struct tar_sparse_file *file, off_t offset, int whence)
|
||||
{
|
||||
if (lseek (file->fd, offset, whence) < 0)
|
||||
{
|
||||
seek_diag_details (file->stat_info->orig_file_name, offset);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Takes a blockful of data and basically cruises through it to see if
|
||||
it's made *entirely* of zeros, returning a 0 the instant it finds
|
||||
something that is a nonzero, i.e., useful data. */
|
||||
static bool
|
||||
zero_block_p (char *buffer, size_t size)
|
||||
{
|
||||
while (size--)
|
||||
if (*buffer++)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define clear_block(p) memset (p, 0, BLOCKSIZE);
|
||||
|
||||
#define SPARSES_INIT_COUNT SPARSES_IN_SPARSE_HEADER
|
||||
|
||||
static void
|
||||
sparse_add_map (struct tar_sparse_file *file, struct sp_array *sp)
|
||||
{
|
||||
if (file->stat_info->sparse_map == NULL)
|
||||
{
|
||||
file->stat_info->sparse_map =
|
||||
xmalloc (SPARSES_INIT_COUNT * sizeof file->stat_info->sparse_map[0]);
|
||||
file->stat_info->sparse_map_size = SPARSES_INIT_COUNT;
|
||||
}
|
||||
else if (file->stat_info->sparse_map_avail == file->stat_info->sparse_map_size)
|
||||
{
|
||||
file->stat_info->sparse_map_size *= 2;
|
||||
file->stat_info->sparse_map =
|
||||
xrealloc (file->stat_info->sparse_map,
|
||||
file->stat_info->sparse_map_size
|
||||
* sizeof file->stat_info->sparse_map[0]);
|
||||
}
|
||||
file->stat_info->sparse_map[file->stat_info->sparse_map_avail++] = *sp;
|
||||
}
|
||||
|
||||
/* Scan the sparse file and create its map */
|
||||
static bool
|
||||
sparse_scan_file (struct tar_sparse_file *file)
|
||||
{
|
||||
static char buffer[BLOCKSIZE];
|
||||
size_t count;
|
||||
size_t offset = 0;
|
||||
struct sp_array sp = {0, 0};
|
||||
|
||||
if (!lseek_or_error (file, 0, SEEK_SET))
|
||||
return false;
|
||||
clear_block (buffer);
|
||||
|
||||
file->stat_info->sparse_map_size = 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)
|
||||
{
|
||||
/* Analize the block */
|
||||
if (zero_block_p (buffer, count))
|
||||
{
|
||||
if (sp.numbytes)
|
||||
{
|
||||
sparse_add_map (file, &sp);
|
||||
sp.numbytes = 0;
|
||||
if (!tar_sparse_scan (file, scan_block, NULL))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
sp.numbytes += count;
|
||||
file->stat_info->archive_file_size += count;
|
||||
if (!tar_sparse_scan (file, scan_block, buffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += count;
|
||||
clear_block (buffer);
|
||||
}
|
||||
|
||||
if (sp.numbytes == 0)
|
||||
sp.offset = offset;
|
||||
|
||||
sparse_add_map (file, &sp);
|
||||
file->stat_info->archive_file_size += count;
|
||||
return tar_sparse_scan (file, scan_end, NULL);
|
||||
}
|
||||
|
||||
static struct tar_sparse_optab oldgnu_optab;
|
||||
static struct tar_sparse_optab star_optab;
|
||||
static struct tar_sparse_optab pax_optab;
|
||||
|
||||
static bool
|
||||
sparse_select_optab (struct tar_sparse_file *file)
|
||||
{
|
||||
switch (current_format == DEFAULT_FORMAT ? archive_format : current_format)
|
||||
{
|
||||
case V7_FORMAT:
|
||||
case USTAR_FORMAT:
|
||||
return false;
|
||||
|
||||
case OLDGNU_FORMAT:
|
||||
case GNU_FORMAT: /*FIXME: This one should disappear? */
|
||||
file->optab = &oldgnu_optab;
|
||||
break;
|
||||
|
||||
case POSIX_FORMAT:
|
||||
file->optab = &pax_optab;
|
||||
break;
|
||||
|
||||
case STAR_FORMAT:
|
||||
file->optab = &star_optab;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sparse_dump_region (struct tar_sparse_file *file, size_t index)
|
||||
{
|
||||
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,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
|
||||
off_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)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
file->stat_info->sparse_map[index].offset
|
||||
+ file->stat_info->sparse_map[index].numbytes
|
||||
- bytes_left,
|
||||
bufsize);
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_left -= bytes_read;
|
||||
file->dumped_size += bytes_read;
|
||||
set_next_block_after (blk);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sparse_extract_region (struct tar_sparse_file *file, size_t index)
|
||||
{
|
||||
size_t write_size;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[index].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
|
||||
write_size = file->stat_info->sparse_map[index].numbytes;
|
||||
|
||||
if (write_size == 0)
|
||||
{
|
||||
/* Last block of the file is a hole */
|
||||
if (sys_truncate (file->fd))
|
||||
truncate_warn (file->stat_info->orig_file_name);
|
||||
}
|
||||
else while (write_size > 0)
|
||||
{
|
||||
size_t count;
|
||||
size_t wrbytes = (write_size > BLOCKSIZE) ? BLOCKSIZE : write_size;
|
||||
union block *blk = find_next_block ();
|
||||
if (!blk)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
count = full_write (file->fd, blk->buffer, wrbytes);
|
||||
write_size -= count;
|
||||
file->dumped_size += count;
|
||||
if (count != wrbytes)
|
||||
{
|
||||
write_error_details (file->stat_info->orig_file_name,
|
||||
count, wrbytes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Interface functions */
|
||||
enum dump_status
|
||||
sparse_dump_file (int fd, struct tar_stat_info *stat)
|
||||
{
|
||||
bool rc;
|
||||
struct tar_sparse_file file;
|
||||
|
||||
file.stat_info = stat;
|
||||
file.fd = fd;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
|| !tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
|
||||
rc = sparse_scan_file (&file);
|
||||
if (rc && file.optab->dump_region)
|
||||
{
|
||||
tar_sparse_dump_header (&file);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
|
||||
rc = tar_sparse_dump_region (&file, i);
|
||||
}
|
||||
}
|
||||
|
||||
pad_archive(file.stat_info->archive_file_size - file.dumped_size);
|
||||
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
|
||||
}
|
||||
|
||||
/* Returns true if the file represented by stat is a sparse one */
|
||||
bool
|
||||
sparse_file_p (struct tar_stat_info *stat)
|
||||
{
|
||||
return (ST_NBLOCKS (stat->stat)
|
||||
< (stat->stat.st_size / ST_NBLOCKSIZE
|
||||
+ (stat->stat.st_size % ST_NBLOCKSIZE != 0)));
|
||||
}
|
||||
|
||||
enum dump_status
|
||||
sparse_extract_file (int fd, struct tar_stat_info *stat, off_t *size)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
size_t i;
|
||||
|
||||
file.stat_info = stat;
|
||||
file.fd = fd;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
|| !tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
|
||||
rc = tar_sparse_decode_header (&file);
|
||||
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
|
||||
rc = tar_sparse_extract_region (&file, i);
|
||||
*size = file.stat_info->archive_file_size - file.dumped_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)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
beg,
|
||||
rdsize);
|
||||
return false;
|
||||
}
|
||||
if (!zero_block_p (diff_buffer, bytes_read))
|
||||
{
|
||||
report_difference (file->stat_info,
|
||||
_("File fragment at %lu is not a hole"), beg);
|
||||
return false;
|
||||
}
|
||||
|
||||
beg += bytes_read;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_data_region (struct tar_sparse_file *file, size_t index)
|
||||
{
|
||||
size_t size_left;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[index].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
size_left = file->stat_info->sparse_map[index].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)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (blk);
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
file->stat_info->sparse_map[index].offset
|
||||
+ file->stat_info->sparse_map[index].numbytes
|
||||
- size_left,
|
||||
rdsize);
|
||||
return false;
|
||||
}
|
||||
file->dumped_size += bytes_read;
|
||||
size_left -= bytes_read;
|
||||
if (memcmp (blk->buffer, diff_buffer, rdsize))
|
||||
{
|
||||
report_difference (file->stat_info, _("Contents differ"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sparse_diff_file (int fd, struct tar_stat_info *stat)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
size_t i;
|
||||
off_t offset = 0;
|
||||
|
||||
file.stat_info = stat;
|
||||
file.fd = fd;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
|| !tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
|
||||
rc = tar_sparse_decode_header (&file);
|
||||
for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
rc = check_sparse_region (&file,
|
||||
offset, file.stat_info->sparse_map[i].offset)
|
||||
&& check_data_region (&file, i);
|
||||
offset = file.stat_info->sparse_map[i].offset
|
||||
+ file.stat_info->sparse_map[i].numbytes;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
skip_file (file.stat_info->archive_file_size - file.dumped_size);
|
||||
|
||||
tar_sparse_done (&file);
|
||||
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
|
||||
at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
|
||||
contains more structs, then the field `isextended' of the main
|
||||
header is set to 1 (binary) and the `struct sparse_header'
|
||||
header follows, containing at most 21 following structs
|
||||
(SPARSES_IN_SPARSE_HEADER). If more structs follow, `isextended'
|
||||
field of the extended header is set and next next extension header
|
||||
follows, etc... */
|
||||
|
||||
enum oldgnu_add_status
|
||||
{
|
||||
add_ok,
|
||||
add_finish,
|
||||
add_fail
|
||||
};
|
||||
|
||||
/* Add a sparse item to the sparse file and its obstack */
|
||||
static enum oldgnu_add_status
|
||||
oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
|
||||
{
|
||||
struct sp_array sp;
|
||||
|
||||
if (s->numbytes[0] == '\0')
|
||||
return add_finish;
|
||||
sp.offset = OFF_FROM_HEADER (s->offset);
|
||||
sp.numbytes = SIZE_FROM_HEADER (s->numbytes);
|
||||
if (sp.offset < 0
|
||||
|| file->stat_info->stat.st_size < sp.offset + sp.numbytes
|
||||
|| file->stat_info->archive_file_size < 0)
|
||||
return add_fail;
|
||||
|
||||
sparse_add_map (file, &sp);
|
||||
return add_ok;
|
||||
}
|
||||
|
||||
/* Convert old GNU format sparse data to internal representation
|
||||
FIXME: Clubbers current_header! */
|
||||
static bool
|
||||
oldgnu_get_sparse_info (struct tar_sparse_file *file)
|
||||
{
|
||||
size_t i;
|
||||
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;
|
||||
for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
|
||||
{
|
||||
rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
|
||||
if (rc != add_ok)
|
||||
break;
|
||||
}
|
||||
|
||||
for (ext_p = h->oldgnu_header.isextended;
|
||||
rc == add_ok && ext_p; ext_p = h->sparse_header.isextended)
|
||||
{
|
||||
h = find_next_block ();
|
||||
if (!h)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (h);
|
||||
for (i = 0; i < SPARSES_IN_SPARSE_HEADER && rc == add_ok; i++)
|
||||
rc = oldgnu_add_sparse (file, &h->sparse_header.sp[i]);
|
||||
}
|
||||
|
||||
if (rc == add_fail)
|
||||
{
|
||||
ERROR ((0, 0, _("%s: invalid sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex,
|
||||
struct sparse *sp, size_t sparse_size)
|
||||
{
|
||||
for (; *pindex < file->stat_info->sparse_map_avail
|
||||
&& sparse_size > 0; sparse_size--, sp++, ++*pindex)
|
||||
{
|
||||
OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset,
|
||||
sp->offset);
|
||||
SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes,
|
||||
sp->numbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
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)
|
||||
blk->oldgnu_header.isextended = 1;
|
||||
|
||||
/* Store the real file size */
|
||||
OFF_TO_CHARS (file->stat_info->stat.st_size, blk->oldgnu_header.realsize);
|
||||
/* Store the effective (shrunken) file size */
|
||||
OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
|
||||
|
||||
i = 0;
|
||||
oldgnu_store_sparse_info (file, &i,
|
||||
blk->oldgnu_header.sp,
|
||||
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 ();
|
||||
memset (blk->buffer, 0, BLOCKSIZE);
|
||||
oldgnu_store_sparse_info (file, &i,
|
||||
blk->sparse_header.sp,
|
||||
SPARSES_IN_SPARSE_HEADER);
|
||||
set_next_block_after (blk);
|
||||
if (i < file->stat_info->sparse_map_avail)
|
||||
blk->sparse_header.isextended = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct tar_sparse_optab oldgnu_optab = {
|
||||
NULL, /* No init function */
|
||||
NULL, /* No done function */
|
||||
oldgnu_dump_header,
|
||||
oldgnu_get_sparse_info,
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
};
|
||||
|
||||
|
||||
/* Star */
|
||||
|
||||
/* Convert STAR format sparse data to internal representation
|
||||
FIXME: Clubbers current_header! */
|
||||
static bool
|
||||
star_get_sparse_info (struct tar_sparse_file *file)
|
||||
{
|
||||
size_t i;
|
||||
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;
|
||||
|
||||
if (h->star_in_header.prefix[0] == '\0'
|
||||
&& h->star_in_header.sp[0].offset[10] != '\0')
|
||||
{
|
||||
/* Old star format */
|
||||
for (i = 0; i < SPARSES_IN_STAR_HEADER; i++)
|
||||
{
|
||||
rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]);
|
||||
if (rc != add_ok)
|
||||
break;
|
||||
}
|
||||
ext_p = h->star_in_header.isextended;
|
||||
}
|
||||
else
|
||||
ext_p = 1;
|
||||
|
||||
for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended)
|
||||
{
|
||||
h = find_next_block ();
|
||||
if (!h)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
return false;
|
||||
}
|
||||
set_next_block_after (h);
|
||||
for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
|
||||
rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
|
||||
}
|
||||
|
||||
if (rc == add_fail)
|
||||
{
|
||||
ERROR ((0, 0, _("%s: invalid sparse archive member"),
|
||||
file->stat_info->orig_file_name));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static struct tar_sparse_optab star_optab = {
|
||||
NULL, /* No init function */
|
||||
NULL, /* No done function */
|
||||
NULL,
|
||||
star_get_sparse_info,
|
||||
NULL, /* No scan_block function */
|
||||
NULL, /* No dump region function */
|
||||
sparse_extract_region,
|
||||
};
|
||||
|
||||
|
||||
/* GNU PAX sparse file format. The sparse file map is stored in
|
||||
x header:
|
||||
|
||||
GNU.sparse.size Real size of the stored file
|
||||
GNU.sparse.numblocks Number of blocks in the sparse map
|
||||
repeat numblocks time
|
||||
GNU.sparse.offset Offset of the next data block
|
||||
GNU.sparse.numbytes Size of the next data block
|
||||
end repeat
|
||||
*/
|
||||
|
||||
static bool
|
||||
pax_dump_header (struct tar_sparse_file *file)
|
||||
{
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
union block *blk;
|
||||
size_t i;
|
||||
|
||||
/* Store the real file size */
|
||||
xheader_store ("GNU.sparse.size", file->stat_info, NULL);
|
||||
xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
|
||||
for (i = 0; i < file->stat_info->sparse_map_avail; i++)
|
||||
{
|
||||
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);
|
||||
finish_header (file->stat_info, blk, block_ordinal);
|
||||
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_dump_header,
|
||||
pax_decode_header,
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
};
|
||||
|
||||
679
src/system.c
Normal file
679
src/system.c
Normal file
@@ -0,0 +1,679 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright (C) 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. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "rmt.h"
|
||||
#include <signal.h>
|
||||
|
||||
void
|
||||
sys_stat_nanoseconds(struct tar_stat_info *stat)
|
||||
{
|
||||
#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;
|
||||
#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;
|
||||
#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;
|
||||
#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;
|
||||
#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);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MSDOS
|
||||
|
||||
bool
|
||||
sys_get_archive_stat ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
sys_file_is_archive (struct tar_stat_info *p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
sys_save_archive_dev_ino ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_detect_dev_null_output ()
|
||||
{
|
||||
static char const dev_null[] = "nul";
|
||||
|
||||
dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
|
||||
|| (! _isrmt (archive)));
|
||||
}
|
||||
|
||||
void
|
||||
sys_drain_input_pipe ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_wait_for_child (pid_t child_pid)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_spawn_shell ()
|
||||
{
|
||||
spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
|
||||
}
|
||||
|
||||
/* stat() in djgpp's C library gives a constant number of 42 as the
|
||||
uid and gid of a file. So, comparing an FTP'ed archive just after
|
||||
unpack would fail on MSDOS. */
|
||||
|
||||
bool
|
||||
sys_compare_uid (struct stat *a, struct stat *b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sys_compare_gid (struct stat *a, struct stat *b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
sys_compare_links (struct stat *link_data, struct stat *stat_data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
sys_truncate (int fd)
|
||||
{
|
||||
return write (fd, "", 0);
|
||||
}
|
||||
|
||||
void
|
||||
sys_reset_uid_gid ()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_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;
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for writing, then compressing an archive. */
|
||||
void
|
||||
sys_child_open_for_compress (void)
|
||||
{
|
||||
FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for uncompressing, then reading an archive. */
|
||||
void
|
||||
sys_child_open_for_uncompress (void)
|
||||
{
|
||||
FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern union block *record_start; /* FIXME */
|
||||
|
||||
static struct stat archive_stat; /* stat block for archive file */
|
||||
|
||||
bool
|
||||
sys_get_archive_stat ()
|
||||
{
|
||||
return fstat (archive, &archive_stat) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
sys_file_is_archive (struct tar_stat_info *p)
|
||||
{
|
||||
return (ar_dev && p->stat.st_dev == ar_dev && p->stat.st_ino == ar_ino);
|
||||
}
|
||||
|
||||
/* Save archive file inode and device numbers */
|
||||
void
|
||||
sys_save_archive_dev_ino ()
|
||||
{
|
||||
if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
|
||||
{
|
||||
ar_dev = archive_stat.st_dev;
|
||||
ar_ino = archive_stat.st_ino;
|
||||
}
|
||||
else
|
||||
ar_dev = 0;
|
||||
}
|
||||
|
||||
/* Detect if outputting to "/dev/null". */
|
||||
void
|
||||
sys_detect_dev_null_output ()
|
||||
{
|
||||
static char const dev_null[] = "/dev/null";
|
||||
struct stat dev_null_stat;
|
||||
|
||||
dev_null_output = (strcmp (archive_name_array[0], dev_null) == 0
|
||||
|| (! _isrmt (archive)
|
||||
&& S_ISCHR (archive_stat.st_mode)
|
||||
&& stat (dev_null, &dev_null_stat) == 0
|
||||
&& archive_stat.st_dev == dev_null_stat.st_dev
|
||||
&& archive_stat.st_ino == dev_null_stat.st_ino));
|
||||
}
|
||||
|
||||
/* Manage to fully drain a pipe we might be reading, so to not break it on
|
||||
the producer after the EOF block. FIXME: one of these days, GNU tar
|
||||
might become clever enough to just stop working, once there is no more
|
||||
work to do, we might have to revise this area in such time. */
|
||||
|
||||
void
|
||||
sys_drain_input_pipe ()
|
||||
{
|
||||
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)
|
||||
continue;
|
||||
}
|
||||
|
||||
void
|
||||
sys_wait_for_child (pid_t child_pid)
|
||||
{
|
||||
if (child_pid)
|
||||
{
|
||||
int wait_status;
|
||||
|
||||
while (waitpid (child_pid, &wait_status, 0) == -1)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (use_compress_program_option);
|
||||
break;
|
||||
}
|
||||
|
||||
if (WIFSIGNALED (wait_status))
|
||||
ERROR ((0, 0, _("Child died with signal %d"),
|
||||
WTERMSIG (wait_status)));
|
||||
else if (WEXITSTATUS (wait_status) != 0)
|
||||
ERROR ((0, 0, _("Child returned status %d"),
|
||||
WEXITSTATUS (wait_status)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sys_spawn_shell ()
|
||||
{
|
||||
pid_t child;
|
||||
const char *shell = getenv ("SHELL");
|
||||
if (! shell)
|
||||
shell = "/bin/sh";
|
||||
child = xfork ();
|
||||
if (child == 0)
|
||||
{
|
||||
execlp (shell, "-sh", "-i", (char *) 0);
|
||||
exec_fatal (shell);
|
||||
}
|
||||
else
|
||||
{
|
||||
int wait_status;
|
||||
while (waitpid (child, &wait_status, 0) == -1)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (shell);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
sys_compare_uid (struct stat *a, struct stat *b)
|
||||
{
|
||||
return a->st_uid == b->st_uid;
|
||||
}
|
||||
|
||||
bool
|
||||
sys_compare_gid (struct stat *a, struct stat *b)
|
||||
{
|
||||
return a->st_gid == b->st_gid;
|
||||
}
|
||||
|
||||
bool
|
||||
sys_compare_links (struct stat *link_data, struct stat *stat_data)
|
||||
{
|
||||
return stat_data->st_dev == link_data->st_dev
|
||||
&& stat_data->st_ino == link_data->st_ino;
|
||||
}
|
||||
|
||||
int
|
||||
sys_truncate (int fd)
|
||||
{
|
||||
off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
|
||||
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
|
||||
is_regular_file (const char *name)
|
||||
{
|
||||
struct stat stbuf;
|
||||
|
||||
if (stat (name, &stbuf) == 0)
|
||||
return S_ISREG (stbuf.st_mode);
|
||||
else
|
||||
return errno == ENOENT;
|
||||
}
|
||||
|
||||
ssize_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;
|
||||
}
|
||||
|
||||
#define PREAD 0 /* read file descriptor from pipe() */
|
||||
#define PWRITE 1 /* write file descriptor from pipe() */
|
||||
|
||||
/* Duplicate file descriptor FROM into becoming INTO.
|
||||
INTO is closed first and has to be the next available slot. */
|
||||
static void
|
||||
xdup2 (int from, int into)
|
||||
{
|
||||
if (from != into)
|
||||
{
|
||||
int status = close (into);
|
||||
|
||||
if (status != 0 && errno != EBADF)
|
||||
{
|
||||
int e = errno;
|
||||
FATAL_ERROR ((0, e, _("Cannot close")));
|
||||
}
|
||||
status = dup (from);
|
||||
if (status != into)
|
||||
{
|
||||
if (status < 0)
|
||||
{
|
||||
int e = errno;
|
||||
FATAL_ERROR ((0, e, _("Cannot dup")));
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
xclose (from);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for writing, then compressing an archive. */
|
||||
pid_t
|
||||
sys_child_open_for_compress (void)
|
||||
{
|
||||
int parent_pipe[2];
|
||||
int child_pipe[2];
|
||||
pid_t grandchild_pid;
|
||||
pid_t child_pid;
|
||||
int wait_status;
|
||||
|
||||
xpipe (parent_pipe);
|
||||
child_pid = xfork ();
|
||||
|
||||
if (child_pid > 0)
|
||||
{
|
||||
/* The parent tar is still here! Just clean up. */
|
||||
|
||||
archive = parent_pipe[PWRITE];
|
||||
xclose (parent_pipe[PREAD]);
|
||||
return child_pid;
|
||||
}
|
||||
|
||||
/* The new born child tar is here! */
|
||||
|
||||
program_name = _("tar (child)");
|
||||
|
||||
xdup2 (parent_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (parent_pipe[PWRITE]);
|
||||
|
||||
/* Check if we need a grandchild tar. This happens only if either:
|
||||
a) we are writing stdout: to force reblocking;
|
||||
b) the file is to be accessed by rmt: compressor doesn't know how;
|
||||
c) the file is not a plain file. */
|
||||
|
||||
if (strcmp (archive_name_array[0], "-") != 0
|
||||
&& !_remdev (archive_name_array[0])
|
||||
&& is_regular_file (archive_name_array[0]))
|
||||
{
|
||||
if (backup_option)
|
||||
maybe_backup_file (archive_name_array[0], 1);
|
||||
|
||||
/* We don't need a grandchild tar. Open the archive and launch the
|
||||
compressor. */
|
||||
|
||||
archive = creat (archive_name_array[0], MODE_RW);
|
||||
if (archive < 0)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
errno = saved_errno;
|
||||
open_fatal (archive_name_array[0]);
|
||||
}
|
||||
xdup2 (archive, STDOUT_FILENO);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
(char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
|
||||
xpipe (child_pipe);
|
||||
grandchild_pid = xfork ();
|
||||
|
||||
if (grandchild_pid == 0)
|
||||
{
|
||||
/* The newborn grandchild tar is here! Launch the compressor. */
|
||||
|
||||
program_name = _("tar (grandchild)");
|
||||
|
||||
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (child_pipe[PREAD]);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
(char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
|
||||
/* Prepare for reblocking the data from the compressor into the archive. */
|
||||
|
||||
xdup2 (child_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (child_pipe[PWRITE]);
|
||||
|
||||
if (strcmp (archive_name_array[0], "-") == 0)
|
||||
archive = STDOUT_FILENO;
|
||||
else
|
||||
{
|
||||
archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
|
||||
if (archive < 0)
|
||||
open_fatal (archive_name_array[0]);
|
||||
}
|
||||
|
||||
/* Let's read out of the stdin pipe and write an archive. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
ssize_t status = 0;
|
||||
char *cursor;
|
||||
size_t length;
|
||||
|
||||
/* Assemble a record. */
|
||||
|
||||
for (length = 0, cursor = record_start->buffer;
|
||||
length < record_size;
|
||||
length += status, cursor += status)
|
||||
{
|
||||
size_t size = record_size - length;
|
||||
|
||||
status = safe_read (STDIN_FILENO, cursor, size);
|
||||
if (status <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
read_fatal (use_compress_program_option);
|
||||
|
||||
/* Copy the record. */
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
/* We hit the end of the file. Write last record at
|
||||
full length, as the only role of the grandchild is
|
||||
doing proper reblocking. */
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
memset (record_start->buffer + length, 0, record_size - length);
|
||||
status = sys_write_archive_buffer ();
|
||||
if (status != record_size)
|
||||
archive_write_error (status);
|
||||
}
|
||||
|
||||
/* There is nothing else to read, break out. */
|
||||
break;
|
||||
}
|
||||
|
||||
status = sys_write_archive_buffer ();
|
||||
if (status != record_size)
|
||||
archive_write_error (status);
|
||||
}
|
||||
|
||||
/* Propagate any failure of the grandchild back to the parent. */
|
||||
|
||||
while (waitpid (grandchild_pid, &wait_status, 0) == -1)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (use_compress_program_option);
|
||||
break;
|
||||
}
|
||||
|
||||
if (WIFSIGNALED (wait_status))
|
||||
{
|
||||
kill (child_pid, WTERMSIG (wait_status));
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
}
|
||||
else if (WEXITSTATUS (wait_status) != 0)
|
||||
exit_status = WEXITSTATUS (wait_status);
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for uncompressing, then reading an archive. */
|
||||
pid_t
|
||||
sys_child_open_for_uncompress (void)
|
||||
{
|
||||
int parent_pipe[2];
|
||||
int child_pipe[2];
|
||||
pid_t grandchild_pid;
|
||||
pid_t child_pid;
|
||||
int wait_status;
|
||||
|
||||
xpipe (parent_pipe);
|
||||
child_pid = xfork ();
|
||||
|
||||
if (child_pid > 0)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* The newborn child tar is here! */
|
||||
|
||||
program_name = _("tar (child)");
|
||||
|
||||
xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (parent_pipe[PREAD]);
|
||||
|
||||
/* Check if we need a grandchild tar. This happens only if either:
|
||||
a) we're reading stdin: to force unblocking;
|
||||
b) the file is to be accessed by rmt: compressor doesn't know how;
|
||||
c) the file is not a plain file. */
|
||||
|
||||
if (strcmp (archive_name_array[0], "-") != 0
|
||||
&& !_remdev (archive_name_array[0])
|
||||
&& is_regular_file (archive_name_array[0]))
|
||||
{
|
||||
/* We don't need a grandchild tar. Open the archive and lauch the
|
||||
uncompressor. */
|
||||
|
||||
archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
|
||||
if (archive < 0)
|
||||
open_fatal (archive_name_array[0]);
|
||||
xdup2 (archive, STDIN_FILENO);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
|
||||
xpipe (child_pipe);
|
||||
grandchild_pid = xfork ();
|
||||
|
||||
if (grandchild_pid == 0)
|
||||
{
|
||||
/* The newborn grandchild tar is here! Launch the uncompressor. */
|
||||
|
||||
program_name = _("tar (grandchild)");
|
||||
|
||||
xdup2 (child_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (child_pipe[PWRITE]);
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
|
||||
/* Prepare for unblocking the data from the archive into the
|
||||
uncompressor. */
|
||||
|
||||
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (child_pipe[PREAD]);
|
||||
|
||||
if (strcmp (archive_name_array[0], "-") == 0)
|
||||
archive = STDIN_FILENO;
|
||||
else
|
||||
archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
|
||||
MODE_RW, rsh_command_option);
|
||||
if (archive < 0)
|
||||
open_fatal (archive_name_array[0]);
|
||||
|
||||
/* Let's read the archive and pipe it into stdout. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *cursor;
|
||||
size_t maximum;
|
||||
size_t count;
|
||||
ssize_t status;
|
||||
|
||||
clear_read_error_count ();
|
||||
|
||||
error_loop:
|
||||
status = rmtread (archive, record_start->buffer, record_size);
|
||||
if (status < 0)
|
||||
{
|
||||
archive_read_error ();
|
||||
goto error_loop;
|
||||
}
|
||||
if (status == 0)
|
||||
break;
|
||||
cursor = record_start->buffer;
|
||||
maximum = status;
|
||||
while (maximum)
|
||||
{
|
||||
count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
|
||||
if (full_write (STDOUT_FILENO, cursor, count) != count)
|
||||
write_error (use_compress_program_option);
|
||||
cursor += count;
|
||||
maximum -= count;
|
||||
}
|
||||
}
|
||||
|
||||
xclose (STDOUT_FILENO);
|
||||
|
||||
/* Propagate any failure of the grandchild back to the parent. */
|
||||
|
||||
while (waitpid (grandchild_pid, &wait_status, 0) == -1)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (use_compress_program_option);
|
||||
break;
|
||||
}
|
||||
|
||||
if (WIFSIGNALED (wait_status))
|
||||
{
|
||||
kill (child_pid, WTERMSIG (wait_status));
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
}
|
||||
else if (WEXITSTATUS (wait_status) != 0)
|
||||
exit_status = WEXITSTATUS (wait_status);
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
#endif /* not MSDOS */
|
||||
|
||||
421
src/system.h
421
src/system.h
@@ -1,5 +1,7 @@
|
||||
/* System dependent definitions for GNU tar.
|
||||
Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
|
||||
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
|
||||
@@ -20,51 +22,31 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Declare alloca. AIX requires this to be the first thing in the file. */
|
||||
#include <alloca.h>
|
||||
|
||||
#if __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
#else
|
||||
# if HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifndef alloca
|
||||
char *alloca ();
|
||||
# endif
|
||||
# endif
|
||||
#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>
|
||||
|
||||
/* Declare a generic pointer type. */
|
||||
#if __STDC__ || defined(__TURBOC__)
|
||||
# define voidstar void *
|
||||
#else
|
||||
# define voidstar char *
|
||||
#endif
|
||||
|
||||
/* Declare ISASCII. */
|
||||
|
||||
#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 ISASCII(Char) 1
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# ifdef isascii
|
||||
# define ISASCII(Char) isascii (Char)
|
||||
# else
|
||||
# if HAVE_ISASCII
|
||||
# define ISASCII(Char) isascii (Char)
|
||||
# else
|
||||
# define ISASCII(Char) 1
|
||||
# endif
|
||||
# endif
|
||||
# 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. */
|
||||
@@ -83,10 +65,10 @@ char *alloca ();
|
||||
# define strrchr rindex
|
||||
# endif
|
||||
# ifndef memcpy
|
||||
# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
|
||||
# define memcpy(d, s, n) bcopy ((char const *) (s), (char *) (d), n)
|
||||
# endif
|
||||
# ifndef memcmp
|
||||
# define memcmp(Src1, Src2, Num) bcmp (Src1, Src2, Num)
|
||||
# define memcmp(a, b, n) bcmp ((char const *) (a), (char const *) (b), n)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -114,10 +96,10 @@ extern int errno;
|
||||
#ifndef O_RDWR
|
||||
# define O_RDWR 2 /* both are allowed */
|
||||
#endif
|
||||
/* The rest can be OR-ed in to the above: */
|
||||
#ifndef O_NDELAY
|
||||
# define O_NDELAY 4 /* don't block on opening devices */
|
||||
#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
|
||||
@@ -126,36 +108,38 @@ extern int errno;
|
||||
#endif
|
||||
#ifndef O_TRUNC
|
||||
# define O_TRUNC 32 /* truncate file on open */
|
||||
#endif
|
||||
#ifndef O_APPEND
|
||||
# define O_APPEND 64 /* always write at end of file */
|
||||
#endif
|
||||
/* MS-DOG forever, with my love! */
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
/* Emulate System V 3-argument open call */
|
||||
#if EMUL_OPEN3
|
||||
# define open open3
|
||||
#endif
|
||||
|
||||
/* Declare file status routines and bits. */
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef S_ISLNK
|
||||
#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_ISMPB
|
||||
# undef S_ISMPC
|
||||
# undef S_ISNWK
|
||||
# undef S_ISREG
|
||||
# undef S_ISSOCK
|
||||
#endif
|
||||
@@ -167,58 +151,131 @@ extern int errno;
|
||||
# define S_ISVTX 0
|
||||
#endif
|
||||
|
||||
#ifndef S_ISREG /* POSIX.1 stat stuff missing */
|
||||
# define mode_t unsigned short
|
||||
#endif
|
||||
#if !defined(S_ISBLK) && defined(S_IFBLK)
|
||||
# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
|
||||
#endif
|
||||
#if !defined(S_ISCHR) && defined(S_IFCHR)
|
||||
# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
|
||||
#endif
|
||||
#if !defined(S_ISDIR) && defined(S_IFDIR)
|
||||
#ifndef S_ISDIR
|
||||
# define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
#if !defined(S_ISREG) && defined(S_IFREG)
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
#if !defined(S_ISFIFO) && defined(S_IFIFO)
|
||||
# define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
|
||||
|
||||
#ifndef S_ISBLK
|
||||
# ifdef S_IFBLK
|
||||
# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
|
||||
# else
|
||||
# define S_ISBLK(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(S_ISLNK) && defined(S_IFLNK)
|
||||
# define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
|
||||
#ifndef S_ISCHR
|
||||
# ifdef S_IFCHR
|
||||
# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
|
||||
# else
|
||||
# define S_ISCHR(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
|
||||
# define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
|
||||
#ifndef S_ISCTG
|
||||
# ifdef S_IFCTG
|
||||
# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
|
||||
# else
|
||||
# define S_ISCTG(Mode) 0
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
|
||||
# define S_ISMPB(Mode) (((Mode) & S_IFMT) == S_IFMPB)
|
||||
# define S_ISMPC(Mode) (((Mode) & S_IFMT) == S_IFMPC)
|
||||
#ifndef S_ISDOOR
|
||||
# define S_ISDOOR(Mode) 0
|
||||
#endif
|
||||
#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
|
||||
# define S_ISNWK(Mode) (((Mode) & S_IFMT) == S_IFNWK)
|
||||
#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
|
||||
#if !HAVE_MKFIFO && !defined mkfifo && defined S_IFIFO
|
||||
# define mkfifo(Path, Mode) (mknod (Path, (Mode) | S_IFIFO, 0))
|
||||
#endif
|
||||
|
||||
#if !defined(S_ISCTG) && defined(S_IFCTG) /* contiguous file */
|
||||
# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
|
||||
#ifndef S_ISUID
|
||||
# define S_ISUID 0004000
|
||||
#endif
|
||||
#if !defined(S_ISVTX)
|
||||
#ifndef S_ISGID
|
||||
# define S_ISGID 0002000
|
||||
#endif
|
||||
#ifndef S_ISVTX
|
||||
# define S_ISVTX 0001000
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_SOURCE
|
||||
# include <sys/param.h>
|
||||
#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. */
|
||||
@@ -263,122 +320,66 @@ extern int errno;
|
||||
|
||||
#undef GOT_MAJOR
|
||||
|
||||
/* Declare directory reading routines and structures. */
|
||||
|
||||
#if __TURBOC__
|
||||
# include "msd_dir.h"
|
||||
# define NAMLEN(dirent) ((dirent)->d_namlen)
|
||||
#else
|
||||
# if HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) (strlen((dirent)->d_name))
|
||||
# else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) ((dirent)->d_namlen)
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Declare wait status. */
|
||||
|
||||
#if HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_UNION_WAIT
|
||||
# define WAIT_T union wait
|
||||
# ifndef WTERMSIG
|
||||
# define WTERMSIG(Status) ((Status).w_termsig)
|
||||
# endif
|
||||
# ifndef WCOREDUMP
|
||||
# define WCOREDUMP(Status) ((Status).w_coredump)
|
||||
# endif
|
||||
# ifndef WEXITSTATUS
|
||||
# define WEXITSTATUS(Status) ((Status).w_retcode)
|
||||
# endif
|
||||
#else
|
||||
# define WAIT_T int
|
||||
# ifndef WTERMSIG
|
||||
# define WTERMSIG(Status) ((Status) & 0x7f)
|
||||
# endif
|
||||
# ifndef WCOREDUMP
|
||||
# define WCOREDUMP(Status) ((Status) & 0x80)
|
||||
# endif
|
||||
# ifndef WEXITSTATUS
|
||||
# define WEXITSTATUS(Status) (((Status) >> 8) & 0xff)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef WIFSTOPPED
|
||||
# define WIFSTOPPED(Status) (WTERMSIG(Status) == 0x7f)
|
||||
#ifndef WEXITSTATUS
|
||||
# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
|
||||
#endif
|
||||
#ifndef WIFSIGNALED
|
||||
# define WIFSIGNALED(Status) (WTERMSIG(Status) != 0)
|
||||
# define WIFSIGNALED(s) (((s) & 0xffff) - 1 < (unsigned) 0xff)
|
||||
#endif
|
||||
#ifndef WIFEXITED
|
||||
# define WIFEXITED(Status) (WTERMSIG(Status) == 0)
|
||||
#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. */
|
||||
|
||||
/* Get or fake the disk device blocksize. Usually defined by sys/param.h
|
||||
(if at all). */
|
||||
|
||||
#if !defined(DEV_BSIZE) && defined(BSIZE)
|
||||
# define DEV_BSIZE BSIZE
|
||||
#endif
|
||||
#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */
|
||||
# define DEV_BSIZE BBSIZE
|
||||
#endif
|
||||
#ifndef DEV_BSIZE
|
||||
# define DEV_BSIZE 4096
|
||||
#endif
|
||||
|
||||
/* 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) DEV_BSIZE
|
||||
# define ST_BLKSIZE(Statbuf) DEFAULT_ST_BLKSIZE
|
||||
#else
|
||||
# define ST_BLKSIZE(Statbuf) \
|
||||
((Statbuf).st_blksize > 0 ? (Statbuf).st_blksize : DEV_BSIZE)
|
||||
((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 512-byte blocks in the file (including indirect blocks).
|
||||
fileblocks.c uses BSIZE. HP-UX counts st_blocks in 1024-byte units,
|
||||
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 + 512 - 1) / 512)
|
||||
# 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_NBLOCKS(Statbuf) ((Statbuf).st_blocks * 2)
|
||||
# define ST_NBLOCKSIZE 1024
|
||||
# else
|
||||
# if defined(_AIX) && defined(_I386)
|
||||
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks * 8)
|
||||
# else
|
||||
# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks)
|
||||
# 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
|
||||
@@ -418,75 +419,95 @@ extern int errno;
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
voidstar malloc ();
|
||||
voidstar realloc ();
|
||||
# if HAVE_GETCWD
|
||||
char *getcwd ();
|
||||
# endif
|
||||
void *malloc ();
|
||||
char *getenv ();
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef _POSIX_VERSION
|
||||
# if MSDOS
|
||||
# include <io.h>
|
||||
# else
|
||||
off_t lseek ();
|
||||
# endif
|
||||
#include <stdio.h>
|
||||
#if !defined _POSIX_VERSION && MSDOS
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include <pathmax.h>
|
||||
|
||||
#if WITH_DMALLOC
|
||||
# undef HAVE_VALLOC
|
||||
# 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. */
|
||||
|
||||
#ifndef PARAMS
|
||||
# if PROTOTYPES
|
||||
# define PARAMS(Args) Args
|
||||
# else
|
||||
# define PARAMS(Args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#if !HAVE_SETLOCALE
|
||||
# define setlocale(Category, Locale)
|
||||
# define setlocale(Category, Locale) /* empty */
|
||||
#endif
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(Text) gettext (Text)
|
||||
#else
|
||||
# define bindtextdomain(Domain, Directory)
|
||||
# define textdomain(Domain)
|
||||
# define _(Text) Text
|
||||
#include <time.h>
|
||||
#ifndef time
|
||||
time_t time ();
|
||||
#endif
|
||||
#define N_(Text) Text
|
||||
|
||||
/* Library modules. */
|
||||
|
||||
#include "error.h"
|
||||
#include <dirname.h>
|
||||
#include <error.h>
|
||||
#include <savedir.h>
|
||||
#include <unlocked-io.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#if !HAVE_STRSTR
|
||||
char *strstr PARAMS ((const char *, const char *));
|
||||
#endif
|
||||
#include <gettext.h>
|
||||
#define _(msgid) gettext (msgid)
|
||||
#define N_(msgid) msgid
|
||||
|
||||
#if HAVE_VALLOC
|
||||
# ifndef valloc
|
||||
voidstar valloc PARAMS ((size_t));
|
||||
# endif
|
||||
#else
|
||||
#if ! defined valloc && ! HAVE_DECL_VALLOC
|
||||
# define valloc(Size) malloc (Size)
|
||||
#endif
|
||||
|
||||
voidstar xmalloc PARAMS ((size_t));
|
||||
voidstar xrealloc PARAMS ((voidstar, size_t));
|
||||
char *xstrdup PARAMS ((const char *));
|
||||
#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
|
||||
|
||||
514
src/tar.c
514
src/tar.c
@@ -1,7 +1,7 @@
|
||||
/* A tar (tape archiver) program.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001
|
||||
Free Software Foundation, Inc.
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000,
|
||||
2001, 2003 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, starting 1985-08-25.
|
||||
|
||||
@@ -36,16 +36,18 @@
|
||||
#define GLOBAL
|
||||
#include "common.h"
|
||||
|
||||
#include <copysym.h>
|
||||
#include <getdate.h>
|
||||
#include <localedir.h>
|
||||
#include <prepargs.h>
|
||||
#include <quotearg.h>
|
||||
#include <xstrtol.h>
|
||||
|
||||
time_t get_date ();
|
||||
|
||||
/* Local declarations. */
|
||||
|
||||
#ifndef DEFAULT_ARCHIVE_FORMAT
|
||||
# define DEFAULT_ARCHIVE_FORMAT GNU_FORMAT
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_ARCHIVE
|
||||
# define DEFAULT_ARCHIVE "tar.out"
|
||||
#endif
|
||||
@@ -54,7 +56,7 @@ time_t get_date ();
|
||||
# define DEFAULT_BLOCKING 20
|
||||
#endif
|
||||
|
||||
static void usage PARAMS ((int)) __attribute__ ((noreturn));
|
||||
void usage (int) __attribute__ ((noreturn));
|
||||
|
||||
/* Miscellaneous. */
|
||||
|
||||
@@ -114,6 +116,57 @@ confirm (const char *message_action, const char *message_name)
|
||||
return reply == 'y' || reply == 'Y';
|
||||
}
|
||||
}
|
||||
|
||||
static struct fmttab {
|
||||
char const *name;
|
||||
enum archive_format fmt;
|
||||
} const fmttab[] = {
|
||||
{ "v7", V7_FORMAT },
|
||||
{ "oldgnu", OLDGNU_FORMAT },
|
||||
{ "ustar", USTAR_FORMAT },
|
||||
{ "posix", POSIX_FORMAT },
|
||||
#if 0 /* not fully supported yet */
|
||||
{ "star", STAR_FORMAT },
|
||||
#endif
|
||||
{ "gnu", GNU_FORMAT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
set_archive_format (char const *name)
|
||||
{
|
||||
struct fmttab const *p;
|
||||
|
||||
for (p = fmttab; strcmp (p->name, name) != 0; )
|
||||
if (! (++p)->name)
|
||||
USAGE_ERROR ((0, 0, _("%s: Invalid archive format"),
|
||||
quotearg_colon (name)));
|
||||
|
||||
archive_format = p->fmt;
|
||||
}
|
||||
|
||||
static const char *
|
||||
archive_format_string (enum archive_format fmt)
|
||||
{
|
||||
struct fmttab const *p;
|
||||
|
||||
for (p = fmttab; p->name; p++)
|
||||
if (p->fmt == fmt)
|
||||
return p->name;
|
||||
return "unknown?";
|
||||
}
|
||||
|
||||
#define FORMAT_MASK(n) (1<<(n))
|
||||
|
||||
static void
|
||||
assert_format(unsigned fmt_mask)
|
||||
{
|
||||
if ((FORMAT_MASK(archive_format) & fmt_mask) == 0)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("GNU features wanted on incompatible archive format")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Options. */
|
||||
|
||||
@@ -127,41 +180,45 @@ confirm (const char *message_action, const char *message_name)
|
||||
enum
|
||||
{
|
||||
ANCHORED_OPTION = CHAR_MAX + 1,
|
||||
ATIME_PRESERVE_OPTION,
|
||||
BACKUP_OPTION,
|
||||
CHECKPOINT_OPTION,
|
||||
DELETE_OPTION,
|
||||
EXCLUDE_OPTION,
|
||||
FORCE_LOCAL_OPTION,
|
||||
FORMAT_OPTION,
|
||||
GROUP_OPTION,
|
||||
IGNORE_CASE_OPTION,
|
||||
IGNORE_FAILED_READ_OPTION,
|
||||
INDEX_FILE_OPTION,
|
||||
MODE_OPTION,
|
||||
NEWER_MTIME_OPTION,
|
||||
NO_ANCHORED_OPTION,
|
||||
NO_IGNORE_CASE_OPTION,
|
||||
NO_OVERWRITE_DIR_OPTION,
|
||||
NO_WILDCARDS_OPTION,
|
||||
NO_WILDCARDS_MATCH_SLASH_OPTION,
|
||||
NULL_OPTION,
|
||||
NUMERIC_OWNER_OPTION,
|
||||
OCCURRENCE_OPTION,
|
||||
OVERWRITE_OPTION,
|
||||
OWNER_OPTION,
|
||||
PAX_OPTION,
|
||||
POSIX_OPTION,
|
||||
PRESERVE_OPTION,
|
||||
RECORD_SIZE_OPTION,
|
||||
RECURSIVE_UNLINK_OPTION,
|
||||
REMOVE_FILES_OPTION,
|
||||
RSH_COMMAND_OPTION,
|
||||
SHOW_DEFAULTS_OPTION,
|
||||
SHOW_OMITTED_DIRS_OPTION,
|
||||
STRIP_PATH_OPTION,
|
||||
SUFFIX_OPTION,
|
||||
TOTALS_OPTION,
|
||||
USE_COMPRESS_PROGRAM_OPTION,
|
||||
VOLNO_FILE_OPTION,
|
||||
WILDCARDS_OPTION,
|
||||
WILDCARDS_MATCH_SLASH_OPTION,
|
||||
|
||||
/* Some cleanup is being made in GNU tar long options. Using old names is
|
||||
allowed for a while, but will also send a warning to stderr. Take old
|
||||
names out in 1.14, or in summer 1997, whichever happens last. */
|
||||
|
||||
OBSOLETE_ABSOLUTE_NAMES,
|
||||
OBSOLETE_BLOCK_COMPRESS,
|
||||
OBSOLETE_BLOCKING_FACTOR,
|
||||
OBSOLETE_BLOCK_NUMBER,
|
||||
OBSOLETE_READ_FULL_RECORDS,
|
||||
OBSOLETE_TOUCH,
|
||||
OBSOLETE_VERSION_CONTROL
|
||||
WILDCARDS_MATCH_SLASH_OPTION
|
||||
};
|
||||
|
||||
/* If nonzero, display usage information and exit. */
|
||||
@@ -173,19 +230,17 @@ static int show_version;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"absolute-names", no_argument, 0, 'P'},
|
||||
{"absolute-paths", no_argument, 0, OBSOLETE_ABSOLUTE_NAMES},
|
||||
{"after-date", required_argument, 0, 'N'},
|
||||
{"anchored", no_argument, 0, ANCHORED_OPTION},
|
||||
{"append", no_argument, 0, 'r'},
|
||||
{"atime-preserve", no_argument, &atime_preserve_option, 1},
|
||||
{"atime-preserve", no_argument, 0, ATIME_PRESERVE_OPTION},
|
||||
{"backup", optional_argument, 0, BACKUP_OPTION},
|
||||
{"block-compress", no_argument, 0, OBSOLETE_BLOCK_COMPRESS},
|
||||
{"block-number", no_argument, 0, 'R'},
|
||||
{"block-size", required_argument, 0, OBSOLETE_BLOCKING_FACTOR},
|
||||
{"blocking-factor", required_argument, 0, 'b'},
|
||||
{"bzip2", no_argument, 0, 'j'},
|
||||
{"catenate", no_argument, 0, 'A'},
|
||||
{"checkpoint", no_argument, &checkpoint_option, 1},
|
||||
{"checkpoint", no_argument, 0, CHECKPOINT_OPTION},
|
||||
{"check-links", no_argument, &check_links_option, 1},
|
||||
{"compare", no_argument, 0, 'd'},
|
||||
{"compress", no_argument, 0, 'Z'},
|
||||
{"concatenate", no_argument, 0, 'A'},
|
||||
@@ -201,17 +256,19 @@ static struct option long_options[] =
|
||||
{"extract", no_argument, 0, 'x'},
|
||||
{"file", required_argument, 0, 'f'},
|
||||
{"files-from", required_argument, 0, 'T'},
|
||||
{"force-local", no_argument, &force_local_option, 1},
|
||||
{"force-local", no_argument, 0, FORCE_LOCAL_OPTION},
|
||||
{"format", required_argument, 0, FORMAT_OPTION},
|
||||
{"get", no_argument, 0, 'x'},
|
||||
{"group", required_argument, 0, GROUP_OPTION},
|
||||
{"gunzip", no_argument, 0, 'z'},
|
||||
{"gzip", no_argument, 0, 'z'},
|
||||
{"help", no_argument, &show_help, 1},
|
||||
{"ignore-case", no_argument, 0, IGNORE_CASE_OPTION},
|
||||
{"ignore-failed-read", no_argument, &ignore_failed_read_option, 1},
|
||||
{"ignore-failed-read", no_argument, 0, IGNORE_FAILED_READ_OPTION},
|
||||
{"ignore-zeros", no_argument, 0, 'i'},
|
||||
/* FIXME: --ignore-end as a new name for --ignore-zeros? */
|
||||
{"incremental", no_argument, 0, 'G'},
|
||||
{"index-file", required_argument, 0, INDEX_FILE_OPTION},
|
||||
{"info-script", required_argument, 0, 'F'},
|
||||
{"interactive", no_argument, 0, 'w'},
|
||||
{"keep-old-files", no_argument, 0, 'k'},
|
||||
@@ -219,7 +276,6 @@ static struct option long_options[] =
|
||||
{"list", no_argument, 0, 't'},
|
||||
{"listed-incremental", required_argument, 0, 'g'},
|
||||
{"mode", required_argument, 0, MODE_OPTION},
|
||||
{"modification-time", no_argument, 0, OBSOLETE_TOUCH},
|
||||
{"multi-volume", no_argument, 0, 'M'},
|
||||
{"new-volume-script", required_argument, 0, 'F'},
|
||||
{"newer", required_argument, 0, 'N'},
|
||||
@@ -227,40 +283,43 @@ static struct option long_options[] =
|
||||
{"null", no_argument, 0, NULL_OPTION},
|
||||
{"no-anchored", no_argument, 0, NO_ANCHORED_OPTION},
|
||||
{"no-ignore-case", no_argument, 0, NO_IGNORE_CASE_OPTION},
|
||||
{"no-overwrite-dir", no_argument, 0, NO_OVERWRITE_DIR_OPTION},
|
||||
{"no-wildcards", no_argument, 0, NO_WILDCARDS_OPTION},
|
||||
{"no-wildcards-match-slash", no_argument, 0, NO_WILDCARDS_MATCH_SLASH_OPTION},
|
||||
{"no-recursion", no_argument, &recursion_option, 0},
|
||||
{"no-same-owner", no_argument, &same_owner_option, -1},
|
||||
{"no-same-permissions", no_argument, &same_permissions_option, -1},
|
||||
{"numeric-owner", no_argument, &numeric_owner_option, 1},
|
||||
{"numeric-owner", no_argument, 0, NUMERIC_OWNER_OPTION},
|
||||
{"occurrence", optional_argument, 0, OCCURRENCE_OPTION},
|
||||
{"old-archive", no_argument, 0, 'o'},
|
||||
{"one-file-system", no_argument, 0, 'l'},
|
||||
{"overwrite", no_argument, 0, OVERWRITE_OPTION},
|
||||
{"owner", required_argument, 0, OWNER_OPTION},
|
||||
{"pax-option", required_argument, 0, PAX_OPTION},
|
||||
{"portability", no_argument, 0, 'o'},
|
||||
{"posix", no_argument, 0, POSIX_OPTION},
|
||||
{"preserve", no_argument, 0, PRESERVE_OPTION},
|
||||
{"preserve-order", no_argument, 0, 's'},
|
||||
{"preserve-permissions", no_argument, 0, 'p'},
|
||||
{"recursion", no_argument, &recursion_option, FNM_LEADING_DIR},
|
||||
{"recursive-unlink", no_argument, &recursive_unlink_option, 1},
|
||||
{"read-full-blocks", no_argument, 0, OBSOLETE_READ_FULL_RECORDS},
|
||||
{"recursive-unlink", no_argument, 0, RECURSIVE_UNLINK_OPTION},
|
||||
{"read-full-records", no_argument, 0, 'B'},
|
||||
/* FIXME: --partial-blocks might be a synonym for --read-full-records? */
|
||||
{"record-number", no_argument, 0, OBSOLETE_BLOCK_NUMBER},
|
||||
{"record-size", required_argument, 0, RECORD_SIZE_OPTION},
|
||||
{"remove-files", no_argument, &remove_files_option, 1},
|
||||
{"remove-files", no_argument, 0, REMOVE_FILES_OPTION},
|
||||
{"rsh-command", required_argument, 0, RSH_COMMAND_OPTION},
|
||||
{"same-order", no_argument, 0, 's'},
|
||||
{"same-owner", no_argument, &same_owner_option, 1},
|
||||
{"same-permissions", no_argument, 0, 'p'},
|
||||
{"show-omitted-dirs", no_argument, &show_omitted_dirs_option, 1},
|
||||
{"show-defaults", no_argument, 0, SHOW_DEFAULTS_OPTION},
|
||||
{"show-omitted-dirs", no_argument, 0, SHOW_OMITTED_DIRS_OPTION},
|
||||
{"sparse", no_argument, 0, 'S'},
|
||||
{"starting-file", required_argument, 0, 'K'},
|
||||
{"strip-path", required_argument, 0, STRIP_PATH_OPTION },
|
||||
{"suffix", required_argument, 0, SUFFIX_OPTION},
|
||||
{"tape-length", required_argument, 0, 'L'},
|
||||
{"to-stdout", no_argument, 0, 'O'},
|
||||
{"totals", no_argument, &totals_option, 1},
|
||||
{"totals", no_argument, 0, TOTALS_OPTION},
|
||||
{"touch", no_argument, 0, 'm'},
|
||||
{"uncompress", no_argument, 0, 'Z'},
|
||||
{"ungzip", no_argument, 0, 'z'},
|
||||
@@ -270,16 +329,15 @@ static struct option long_options[] =
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"verify", no_argument, 0, 'W'},
|
||||
{"version", no_argument, &show_version, 1},
|
||||
{"version-control", required_argument, 0, OBSOLETE_VERSION_CONTROL},
|
||||
{"volno-file", required_argument, 0, VOLNO_FILE_OPTION},
|
||||
{"wildcards", no_argument, 0, WILDCARDS_OPTION},
|
||||
{"wildcards-match-slash", no_argument, 0, WILDCARDS_MATCH_SLASH_OPTION},
|
||||
|
||||
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* Print a usage message and exit with STATUS. */
|
||||
static void
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != TAREXIT_SUCCESS)
|
||||
@@ -323,6 +381,7 @@ Operation modifiers:\n\
|
||||
--remove-files remove files after adding them to the archive\n\
|
||||
-k, --keep-old-files don't replace existing files when extracting\n\
|
||||
--overwrite overwrite existing files when extracting\n\
|
||||
--no-overwrite-dir preserve metadata of existing directories\n\
|
||||
-U, --unlink-first remove each file prior to extracting over it\n\
|
||||
--recursive-unlink empty hierarchies prior to extracting directory\n\
|
||||
-S, --sparse handle sparse files efficiently\n\
|
||||
@@ -330,7 +389,14 @@ Operation modifiers:\n\
|
||||
-G, --incremental handle old GNU-format incremental backup\n\
|
||||
-g, --listed-incremental=FILE\n\
|
||||
handle new GNU-format incremental backup\n\
|
||||
--ignore-failed-read do not exit with nonzero on unreadable files\n"),
|
||||
--ignore-failed-read do not exit with nonzero on unreadable files\n\
|
||||
--occurrence[=NUM] process only the NUMth occurrence of each file in\n\
|
||||
the archive. This option is valid only in\n\
|
||||
conjunction with one of the subcommands --delete,\n\
|
||||
--diff, --extract or --list and when a list of\n\
|
||||
files is given either on the command line or\n\
|
||||
via -T option.\n\
|
||||
NUM defaults to 1.\n"),
|
||||
stdout);
|
||||
fputs (_("\
|
||||
\n\
|
||||
@@ -374,10 +440,19 @@ Device blocking:\n\
|
||||
fputs (_("\
|
||||
\n\
|
||||
Archive format selection:\n\
|
||||
--format=FMTNAME create archive of the given format.\n\
|
||||
FMTNAME is one of the following:\n\
|
||||
v7 old V7 tar format\n\
|
||||
oldgnu GNU format as per tar <= 1.12\n\
|
||||
gnu GNU tar 1.13 format\n\
|
||||
ustar POSIX 1003.1-1988 (ustar) format\n\
|
||||
posix POSIX 1003.1-2001 (pax) format\n\
|
||||
--old-archive, --portability same as --format=v7\n\
|
||||
--posix same as --format=posix\n\
|
||||
--pax-option keyword[[:]=value][,keyword[[:]=value], ...]\n\
|
||||
control pax keywords\n\
|
||||
-V, --label=NAME create archive with volume name NAME\n\
|
||||
PATTERN at list/extract time, a globbing PATTERN\n\
|
||||
-o, --old-archive, --portability write a V7 format archive\n\
|
||||
--posix write a POSIX format archive\n\
|
||||
-j, --bzip2 filter the archive through bzip2\n\
|
||||
-z, --gzip, --ungzip filter the archive through gzip\n\
|
||||
-Z, --compress, --uncompress filter the archive through compress\n\
|
||||
@@ -403,11 +478,13 @@ Local file selection:\n\
|
||||
-h, --dereference dump instead the files symlinks point to\n\
|
||||
--no-recursion avoid descending automatically in directories\n\
|
||||
-l, --one-file-system stay in local file system when creating archive\n\
|
||||
-K, --starting-file=NAME begin at file NAME in the archive\n"),
|
||||
-K, --starting-file=NAME begin at file NAME in the archive\n\
|
||||
--strip-path=NUM strip NUM leading components from file names\n\
|
||||
before extraction\n"),
|
||||
stdout);
|
||||
#if !MSDOS
|
||||
fputs (_("\
|
||||
-N, --newer=DATE only store files newer than DATE\n\
|
||||
-N, --newer=DATE-OR-FILE only store files newer than DATE-OR-FILE\n\
|
||||
--newer-mtime=DATE compare date and time when data changed only\n\
|
||||
--after-date=DATE same as -N\n"),
|
||||
stdout);
|
||||
@@ -423,13 +500,22 @@ Informative output:\n\
|
||||
--version print tar program version number, then exit\n\
|
||||
-v, --verbose verbosely list files processed\n\
|
||||
--checkpoint print directory names while reading the archive\n\
|
||||
--check-links print a message if not all links are dumped\n\
|
||||
--totals print total bytes written while creating archive\n\
|
||||
--index-file=FILE send verbose output to FILE\n\
|
||||
-R, --block-number show block number within archive with each message\n\
|
||||
-w, --interactive ask for confirmation for every action\n\
|
||||
--confirmation same as -w\n"),
|
||||
stdout);
|
||||
fputs (_("\
|
||||
\n\
|
||||
Compatibility options:\n\
|
||||
-o when creating, same as --old-archive\n\
|
||||
when extracting, same as --no-same-owner\n"),
|
||||
stdout);
|
||||
|
||||
fputs (_("\
|
||||
\n\
|
||||
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
|
||||
The version control may be set with --backup or VERSION_CONTROL, values are:\n\
|
||||
\n\
|
||||
@@ -439,14 +525,12 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\
|
||||
stdout);
|
||||
printf (_("\
|
||||
\n\
|
||||
GNU tar cannot read nor produce `--posix' archives. If POSIXLY_CORRECT\n\
|
||||
is set in the environment, GNU extensions are disallowed with `--posix'.\n\
|
||||
Support for POSIX is only partially implemented, don't count on it yet.\n\
|
||||
ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; DATE may be a textual date\n\
|
||||
or a file name starting with `/' or `.', in which case the file's date is used.\n\
|
||||
*This* `tar' defaults to `-f%s -b%d'.\n"),
|
||||
*This* `tar' defaults to `--format=%s -f%s -b%d'.\n"),
|
||||
archive_format_string (DEFAULT_ARCHIVE_FORMAT),
|
||||
DEFAULT_ARCHIVE, DEFAULT_BLOCKING);
|
||||
fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
|
||||
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
@@ -491,9 +575,12 @@ decode_options (int argc, char **argv)
|
||||
{
|
||||
int optchar; /* option letter */
|
||||
int input_files; /* number of input files */
|
||||
const char *backup_suffix_string;
|
||||
const char *version_control_string = 0;
|
||||
char const *textual_date_option = 0;
|
||||
char const *backup_suffix_string;
|
||||
char const *version_control_string = 0;
|
||||
int exclude_options = EXCLUDE_WILDCARDS;
|
||||
bool o_option = 0;
|
||||
int pax_option = 0;
|
||||
|
||||
/* Set some default option values. */
|
||||
|
||||
@@ -531,7 +618,7 @@ decode_options (int argc, char **argv)
|
||||
/* Allocate a new argument array, and copy program name in it. */
|
||||
|
||||
new_argc = argc - 1 + strlen (argv[1]);
|
||||
new_argv = xmalloc (new_argc * sizeof (char *));
|
||||
new_argv = xmalloc ((new_argc + 1) * sizeof (char *));
|
||||
in = argv;
|
||||
out = new_argv;
|
||||
*out++ = *in++;
|
||||
@@ -558,6 +645,7 @@ decode_options (int argc, char **argv)
|
||||
|
||||
while (in < argv + argc)
|
||||
*out++ = *in++;
|
||||
*out = 0;
|
||||
|
||||
/* Replace the old option list by the new one. */
|
||||
|
||||
@@ -593,14 +681,6 @@ decode_options (int argc, char **argv)
|
||||
set_subcommand_option (CAT_SUBCOMMAND);
|
||||
break;
|
||||
|
||||
case OBSOLETE_BLOCK_COMPRESS:
|
||||
WARN ((0, 0, _("Obsolete option, now implied by --blocking-factor")));
|
||||
break;
|
||||
|
||||
case OBSOLETE_BLOCKING_FACTOR:
|
||||
WARN ((0, 0, _("Obsolete option name replaced by --blocking-factor")));
|
||||
/* Fall through. */
|
||||
|
||||
case 'b':
|
||||
{
|
||||
uintmax_t u;
|
||||
@@ -613,11 +693,6 @@ decode_options (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case OBSOLETE_READ_FULL_RECORDS:
|
||||
WARN ((0, 0,
|
||||
_("Obsolete option name replaced by --read-full-records")));
|
||||
/* Fall through. */
|
||||
|
||||
case 'B':
|
||||
/* Try to reblock input records. For reading 4.2BSD pipes. */
|
||||
|
||||
@@ -626,7 +701,7 @@ decode_options (int argc, char **argv)
|
||||
BSD-derived systems. This is a consequence of the block/record
|
||||
terminology confusion. */
|
||||
|
||||
read_full_records_option = 1;
|
||||
read_full_records_option = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
@@ -658,12 +733,12 @@ decode_options (int argc, char **argv)
|
||||
script at the end of each tape. */
|
||||
|
||||
info_script_option = optarg;
|
||||
multi_volume_option = 1;
|
||||
multi_volume_option = true;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
listed_incremental_option = optarg;
|
||||
after_date_option = 1;
|
||||
after_date_option = true;
|
||||
/* Fall through. */
|
||||
|
||||
case 'G':
|
||||
@@ -671,13 +746,12 @@ decode_options (int argc, char **argv)
|
||||
directories at the beginning of the archive, and include in each
|
||||
directory its contents. */
|
||||
|
||||
incremental_option = 1;
|
||||
incremental_option = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
/* Follow symbolic links. */
|
||||
|
||||
dereference_option = 1;
|
||||
dereference_option = true;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
@@ -685,7 +759,7 @@ decode_options (int argc, char **argv)
|
||||
because Unix tar writes two blocks of zeros, then pads out
|
||||
the record with garbage. */
|
||||
|
||||
ignore_zeros_option = 1;
|
||||
ignore_zeros_option = true;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
@@ -704,7 +778,7 @@ decode_options (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
starting_file_option = 1;
|
||||
starting_file_option = true;
|
||||
addname (optarg, 0);
|
||||
break;
|
||||
|
||||
@@ -712,7 +786,7 @@ decode_options (int argc, char **argv)
|
||||
/* When dumping directories, don't dump files/subdirectories
|
||||
that are on other filesystems. */
|
||||
|
||||
one_file_system_option = 1;
|
||||
one_file_system_option = true;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
@@ -722,28 +796,24 @@ decode_options (int argc, char **argv)
|
||||
USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
|
||||
_("Invalid tape length")));
|
||||
tape_length_option = 1024 * (tarlong) u;
|
||||
multi_volume_option = 1;
|
||||
multi_volume_option = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case OBSOLETE_TOUCH:
|
||||
WARN ((0, 0, _("Obsolete option name replaced by --touch")));
|
||||
/* Fall through. */
|
||||
|
||||
case 'm':
|
||||
touch_option = 1;
|
||||
touch_option = true;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
/* Make multivolume archive: when we can't write any more into
|
||||
the archive, re-open it, and continue writing. */
|
||||
|
||||
multi_volume_option = 1;
|
||||
multi_volume_option = true;
|
||||
break;
|
||||
|
||||
#if !MSDOS
|
||||
case 'N':
|
||||
after_date_option = 1;
|
||||
after_date_option = true;
|
||||
/* Fall through. */
|
||||
|
||||
case NEWER_MTIME_OPTION:
|
||||
@@ -768,42 +838,33 @@ decode_options (int argc, char **argv)
|
||||
if (newer_mtime_option == (time_t) -1)
|
||||
WARN ((0, 0, _("Substituting %s for unknown date format %s"),
|
||||
tartime (newer_mtime_option), quote (optarg)));
|
||||
else
|
||||
textual_date_option = optarg;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif /* not MSDOS */
|
||||
|
||||
case 'o':
|
||||
if (archive_format == DEFAULT_FORMAT)
|
||||
archive_format = V7_FORMAT;
|
||||
else if (archive_format != V7_FORMAT)
|
||||
USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
|
||||
o_option = true;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
to_stdout_option = 1;
|
||||
to_stdout_option = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
same_permissions_option = 1;
|
||||
same_permissions_option = true;
|
||||
break;
|
||||
|
||||
case OBSOLETE_ABSOLUTE_NAMES:
|
||||
WARN ((0, 0, _("Obsolete option name replaced by --absolute-names")));
|
||||
/* Fall through. */
|
||||
|
||||
case 'P':
|
||||
absolute_names_option = 1;
|
||||
absolute_names_option = true;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
set_subcommand_option (APPEND_SUBCOMMAND);
|
||||
break;
|
||||
|
||||
case OBSOLETE_BLOCK_NUMBER:
|
||||
WARN ((0, 0, _("Obsolete option name replaced by --block-number")));
|
||||
/* Fall through. */
|
||||
|
||||
case 'R':
|
||||
/* Print block numbers for debugging bad tar archives. */
|
||||
|
||||
@@ -812,17 +873,17 @@ decode_options (int argc, char **argv)
|
||||
BSD-derived systems. This is a consequence of the block/record
|
||||
terminology confusion. */
|
||||
|
||||
block_number_option = 1;
|
||||
block_number_option = true;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
/* Names to extr are sorted. */
|
||||
|
||||
same_order_option = 1;
|
||||
same_order_option = true;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
sparse_option = 1;
|
||||
sparse_option = true;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
@@ -851,11 +912,11 @@ decode_options (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
interactive_option = 1;
|
||||
interactive_option = true;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
verify_option = 1;
|
||||
verify_option = true;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
@@ -886,16 +947,20 @@ decode_options (int argc, char **argv)
|
||||
set_use_compress_program_option ("compress");
|
||||
break;
|
||||
|
||||
case OBSOLETE_VERSION_CONTROL:
|
||||
WARN ((0, 0, _("Obsolete option name replaced by --backup")));
|
||||
/* Fall through. */
|
||||
|
||||
case ANCHORED_OPTION:
|
||||
exclude_options |= EXCLUDE_ANCHORED;
|
||||
break;
|
||||
|
||||
case ATIME_PRESERVE_OPTION:
|
||||
atime_preserve_option = true;
|
||||
break;
|
||||
|
||||
case CHECKPOINT_OPTION:
|
||||
checkpoint_option = true;
|
||||
break;
|
||||
|
||||
case BACKUP_OPTION:
|
||||
backup_option = 1;
|
||||
backup_option = true;
|
||||
if (optarg)
|
||||
version_control_string = optarg;
|
||||
break;
|
||||
@@ -908,10 +973,26 @@ decode_options (int argc, char **argv)
|
||||
add_exclude (excluded, optarg, exclude_options | recursion_option);
|
||||
break;
|
||||
|
||||
case FORCE_LOCAL_OPTION:
|
||||
force_local_option = true;
|
||||
break;
|
||||
|
||||
case FORMAT_OPTION:
|
||||
set_archive_format (optarg);
|
||||
break;
|
||||
|
||||
case INDEX_FILE_OPTION:
|
||||
index_file_name = optarg;
|
||||
break;
|
||||
|
||||
case IGNORE_CASE_OPTION:
|
||||
exclude_options |= FNM_CASEFOLD;
|
||||
break;
|
||||
|
||||
case IGNORE_FAILED_READ_OPTION:
|
||||
ignore_failed_read_option = true;
|
||||
break;
|
||||
|
||||
case GROUP_OPTION:
|
||||
if (! (strlen (optarg) < GNAME_FIELD_SIZE
|
||||
&& gname_to_gid (optarg, &group_option)))
|
||||
@@ -944,6 +1025,10 @@ decode_options (int argc, char **argv)
|
||||
exclude_options &= ~ FNM_CASEFOLD;
|
||||
break;
|
||||
|
||||
case NO_OVERWRITE_DIR_OPTION:
|
||||
old_files_option = NO_OVERWRITE_DIR_OLD_FILES;
|
||||
break;
|
||||
|
||||
case NO_WILDCARDS_OPTION:
|
||||
exclude_options &= ~ EXCLUDE_WILDCARDS;
|
||||
break;
|
||||
@@ -956,6 +1041,24 @@ decode_options (int argc, char **argv)
|
||||
filename_terminator = '\0';
|
||||
break;
|
||||
|
||||
case NUMERIC_OWNER_OPTION:
|
||||
numeric_owner_option = true;
|
||||
break;
|
||||
|
||||
case OCCURRENCE_OPTION:
|
||||
if (!optarg)
|
||||
occurrence_option = 1;
|
||||
else
|
||||
{
|
||||
uintmax_t u;
|
||||
if (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK)
|
||||
occurrence_option = u;
|
||||
else
|
||||
FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
|
||||
_("Invalid number")));
|
||||
}
|
||||
break;
|
||||
|
||||
case OVERWRITE_OPTION:
|
||||
old_files_option = OVERWRITE_OLD_FILES;
|
||||
break;
|
||||
@@ -974,23 +1077,18 @@ decode_options (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case PAX_OPTION:
|
||||
pax_option++;
|
||||
xheader_set_option (optarg);
|
||||
break;
|
||||
|
||||
case POSIX_OPTION:
|
||||
#if OLDGNU_COMPATIBILITY
|
||||
if (archive_format == DEFAULT_FORMAT)
|
||||
archive_format = GNU_FORMAT;
|
||||
else if (archive_format != GNU_FORMAT)
|
||||
USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
|
||||
#else
|
||||
if (archive_format == DEFAULT_FORMAT)
|
||||
archive_format = POSIX_FORMAT;
|
||||
else if (archive_format != POSIX_FORMAT)
|
||||
USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
|
||||
#endif
|
||||
set_archive_format ("posix");
|
||||
break;
|
||||
|
||||
case PRESERVE_OPTION:
|
||||
same_permissions_option = 1;
|
||||
same_order_option = 1;
|
||||
same_permissions_option = true;
|
||||
same_order_option = true;
|
||||
break;
|
||||
|
||||
case RECORD_SIZE_OPTION:
|
||||
@@ -1008,15 +1106,44 @@ decode_options (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case RECURSIVE_UNLINK_OPTION:
|
||||
recursive_unlink_option = true;
|
||||
break;
|
||||
|
||||
case REMOVE_FILES_OPTION:
|
||||
remove_files_option = true;
|
||||
break;
|
||||
|
||||
case RSH_COMMAND_OPTION:
|
||||
rsh_command_option = optarg;
|
||||
break;
|
||||
|
||||
case SHOW_DEFAULTS_OPTION:
|
||||
printf ("--format=%s -f%s -b%d\n",
|
||||
archive_format_string (DEFAULT_ARCHIVE_FORMAT),
|
||||
DEFAULT_ARCHIVE, DEFAULT_BLOCKING);
|
||||
exit(0);
|
||||
|
||||
case STRIP_PATH_OPTION:
|
||||
{
|
||||
uintmax_t u;
|
||||
if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
|
||||
&& u == (size_t) u))
|
||||
USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
|
||||
_("Invalid number of elements")));
|
||||
strip_path_elements = u;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUFFIX_OPTION:
|
||||
backup_option = 1;
|
||||
backup_option = true;
|
||||
backup_suffix_string = optarg;
|
||||
break;
|
||||
|
||||
case TOTALS_OPTION:
|
||||
totals_option = true;
|
||||
break;
|
||||
|
||||
case USE_COMPRESS_PROGRAM_OPTION:
|
||||
set_use_compress_program_option (optarg);
|
||||
break;
|
||||
@@ -1097,10 +1224,7 @@ decode_options (int argc, char **argv)
|
||||
xrealloc (archive_name_array,
|
||||
sizeof (const char *) * allocated_archive_names);
|
||||
}
|
||||
archive_name_array[archive_names++] = buf;
|
||||
|
||||
/* FIXME: How comes this works for many archives when buf is
|
||||
not xstrdup'ed? */
|
||||
archive_name_array[archive_names++] = strdup (buf);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1112,6 +1236,29 @@ decode_options (int argc, char **argv)
|
||||
#endif /* not DEVICE_PREFIX */
|
||||
}
|
||||
|
||||
/* Special handling for 'o' option:
|
||||
|
||||
GNU tar used to say "output old format".
|
||||
UNIX98 tar says don't chown files after extracting (we use
|
||||
"--no-same-owner" for this).
|
||||
|
||||
The old GNU tar semantics is retained when used with --create
|
||||
option, otherwise UNIX98 semantics is assumed */
|
||||
|
||||
if (o_option)
|
||||
{
|
||||
if (subcommand_option == CREATE_SUBCOMMAND)
|
||||
{
|
||||
/* GNU Tar <= 1.13 compatibility */
|
||||
set_archive_format ("v7");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* UNIX98 compatibility */
|
||||
same_owner_option = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle operands after any "--" argument. */
|
||||
for (; optind < argc; optind++)
|
||||
{
|
||||
@@ -1123,10 +1270,8 @@ decode_options (int argc, char **argv)
|
||||
|
||||
if (show_version)
|
||||
{
|
||||
char buf[MB_LEN_MAX + 1];
|
||||
printf ("tar (GNU %s) %s\n", PACKAGE, VERSION);
|
||||
printf ("Copyright %s 2001 Free Software Foundation, Inc.\n",
|
||||
copyright_symbol (buf, sizeof buf));
|
||||
printf ("tar (%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\
|
||||
@@ -1144,21 +1289,36 @@ see the file named COPYING for details."));
|
||||
|
||||
if (archive_format == DEFAULT_FORMAT)
|
||||
{
|
||||
#if OLDGNU_COMPATIBILITY
|
||||
archive_format = OLDGNU_FORMAT;
|
||||
#else
|
||||
archive_format = GNU_FORMAT;
|
||||
#endif
|
||||
if (pax_option)
|
||||
archive_format = POSIX_FORMAT;
|
||||
else
|
||||
archive_format = DEFAULT_ARCHIVE_FORMAT;
|
||||
}
|
||||
|
||||
if (volume_label_option && subcommand_option == CREATE_SUBCOMMAND)
|
||||
assert_format (FORMAT_MASK (OLDGNU_FORMAT)
|
||||
| FORMAT_MASK (GNU_FORMAT));
|
||||
|
||||
if (archive_format == GNU_FORMAT && getenv ("POSIXLY_CORRECT"))
|
||||
archive_format = POSIX_FORMAT;
|
||||
|
||||
if ((volume_label_option
|
||||
|| incremental_option || multi_volume_option || sparse_option)
|
||||
&& archive_format != OLDGNU_FORMAT && archive_format != GNU_FORMAT)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("GNU features wanted on incompatible archive format")));
|
||||
if (incremental_option || multi_volume_option)
|
||||
assert_format (FORMAT_MASK (OLDGNU_FORMAT) | FORMAT_MASK (GNU_FORMAT));
|
||||
|
||||
if (sparse_option)
|
||||
assert_format (FORMAT_MASK (OLDGNU_FORMAT)
|
||||
| FORMAT_MASK (GNU_FORMAT)
|
||||
| FORMAT_MASK (POSIX_FORMAT));
|
||||
|
||||
if (occurrence_option)
|
||||
{
|
||||
if (!input_files && !files_from_option)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("--occurrence is meaningless without a file list")));
|
||||
if (subcommand_option != DELETE_SUBCOMMAND
|
||||
&& subcommand_option != DIFF_SUBCOMMAND
|
||||
&& subcommand_option != EXTRACT_SUBCOMMAND
|
||||
&& subcommand_option != LIST_SUBCOMMAND)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("--occurrence cannot be used in the requested operation mode")));
|
||||
}
|
||||
|
||||
if (archive_names == 0)
|
||||
{
|
||||
@@ -1175,7 +1335,7 @@ see the file named COPYING for details."));
|
||||
|
||||
if (archive_names > 1 && !multi_volume_option)
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("Multiple archive files requires `-M' option")));
|
||||
_("Multiple archive files require `-M' option")));
|
||||
|
||||
if (listed_incremental_option
|
||||
&& newer_mtime_option != TYPE_MINIMUM (time_t))
|
||||
@@ -1195,11 +1355,40 @@ see the file named COPYING for details."));
|
||||
: 0));
|
||||
if (volume_label_max_len < strlen (volume_label_option))
|
||||
USAGE_ERROR ((0, 0,
|
||||
_("%s: Volume label is too long (limit is %lu bytes)"),
|
||||
ngettext ("%s: Volume label is too long (limit is %lu byte)",
|
||||
"%s: Volume label is too long (limit is %lu bytes)",
|
||||
volume_label_max_len),
|
||||
quotearg_colon (volume_label_option),
|
||||
(unsigned long) volume_label_max_len));
|
||||
}
|
||||
|
||||
if (verify_option)
|
||||
{
|
||||
if (multi_volume_option)
|
||||
USAGE_ERROR ((0, 0, _("Cannot verify multi-volume archives")));
|
||||
if (use_compress_program_option)
|
||||
USAGE_ERROR ((0, 0, _("Cannot verify compressed archives")));
|
||||
}
|
||||
|
||||
if (use_compress_program_option)
|
||||
{
|
||||
if (multi_volume_option)
|
||||
USAGE_ERROR ((0, 0, _("Cannot use multi-volume compressed archives")));
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND)
|
||||
USAGE_ERROR ((0, 0, _("Cannot update compressed archives")));
|
||||
}
|
||||
|
||||
/* It is no harm to use --pax-option on non-pax archives in archive
|
||||
reading mode. It may even be useful, since it allows to override
|
||||
file attributes from tar headers. Therefore I allow such usage.
|
||||
--gray */
|
||||
if (pax_option
|
||||
&& archive_format != POSIX_FORMAT
|
||||
&& (subcommand_option != EXTRACT_SUBCOMMAND
|
||||
|| subcommand_option != DIFF_SUBCOMMAND
|
||||
|| subcommand_option != LIST_SUBCOMMAND))
|
||||
USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives")));
|
||||
|
||||
/* If ready to unlink hierarchies, so we are for simpler files. */
|
||||
if (recursive_unlink_option)
|
||||
old_files_option = UNLINK_FIRST_OLD_FILES;
|
||||
@@ -1248,7 +1437,16 @@ see the file named COPYING for details."));
|
||||
|
||||
if (backup_option)
|
||||
backup_type = xget_version ("--backup", version_control_string);
|
||||
|
||||
if (verbose_option && textual_date_option)
|
||||
{
|
||||
char const *treated_as = tartime (newer_mtime_option);
|
||||
if (strcmp (textual_date_option, treated_as) != 0)
|
||||
WARN ((0, 0, _("Treating date `%s' as %s"),
|
||||
textual_date_option, treated_as));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Tar proper. */
|
||||
|
||||
@@ -1320,7 +1518,11 @@ main (int argc, char **argv)
|
||||
case EXTRACT_SUBCOMMAND:
|
||||
extr_init ();
|
||||
read_and (extract_archive);
|
||||
|
||||
/* FIXME: should extract_finish () even if an ordinary signal is
|
||||
received. */
|
||||
extract_finish ();
|
||||
|
||||
break;
|
||||
|
||||
case LIST_SUBCOMMAND:
|
||||
@@ -1333,6 +1535,9 @@ main (int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (check_links_option)
|
||||
check_links ();
|
||||
|
||||
if (volno_file_option)
|
||||
closeout_volume_number ();
|
||||
|
||||
@@ -1341,9 +1546,30 @@ main (int argc, char **argv)
|
||||
free (archive_name_array);
|
||||
name_term ();
|
||||
|
||||
if (stdlis == stdout && (ferror (stdout) || fclose (stdout) != 0))
|
||||
if (stdlis != stderr && (ferror (stdlis) || fclose (stdlis) != 0))
|
||||
FATAL_ERROR ((0, 0, _("Error in writing to standard output")));
|
||||
if (exit_status == TAREXIT_FAILURE)
|
||||
error (0, 0, _("Error exit delayed from previous errors"));
|
||||
exit (exit_status);
|
||||
if (ferror (stderr) || fclose (stderr) != 0)
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
void
|
||||
tar_stat_init (struct tar_stat_info *st)
|
||||
{
|
||||
memset (st, 0, sizeof (*st));
|
||||
}
|
||||
|
||||
void
|
||||
tar_stat_destroy (struct tar_stat_info *st)
|
||||
{
|
||||
free (st->orig_file_name);
|
||||
free (st->file_name);
|
||||
free (st->link_name);
|
||||
free (st->uname);
|
||||
free (st->gname);
|
||||
free (st->sparse_map);
|
||||
memset (st, 0, sizeof (*st));
|
||||
}
|
||||
|
||||
|
||||
164
src/tar.h
164
src/tar.h
@@ -1,5 +1,7 @@
|
||||
/* Format of tar archives.
|
||||
Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
|
||||
/* GNU tar Archive Format description.
|
||||
|
||||
Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
||||
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
|
||||
@@ -15,19 +17,6 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* GNU tar Archive Format description. */
|
||||
|
||||
/* If OLDGNU_COMPATIBILITY is not zero, tar produces archives which, by
|
||||
default, are readable by older versions of GNU tar. This can be
|
||||
overriden by using --posix; in this case, POSIXLY_CORRECT in environment
|
||||
may be set for enforcing stricter conformance. If OLDGNU_COMPATIBILITY
|
||||
is zero or undefined, tar will eventually produces archives which, by
|
||||
default, POSIX compatible; then either using --posix or defining
|
||||
POSIXLY_CORRECT enforces stricter conformance.
|
||||
|
||||
This #define will disappear in a few years. FP, June 1995. */
|
||||
#define OLDGNU_COMPATIBILITY 1
|
||||
|
||||
/* tar Header Block, from POSIX 1003.1-1990. */
|
||||
|
||||
/* POSIX header. */
|
||||
@@ -69,6 +58,10 @@ struct posix_header
|
||||
#define FIFOTYPE '6' /* FIFO special */
|
||||
#define CONTTYPE '7' /* reserved */
|
||||
|
||||
#define XHDTYPE 'x' /* Extended header referring to the
|
||||
next file in the archive */
|
||||
#define XGLTYPE 'g' /* Global extended header */
|
||||
|
||||
/* Bits used in the mode field, values in octal. */
|
||||
#define TSUID 04000 /* set UID on execution */
|
||||
#define TSGID 02000 /* set GID on execution */
|
||||
@@ -122,26 +115,6 @@ struct sparse
|
||||
#define SPARSES_IN_OLDGNU_HEADER 4
|
||||
#define SPARSES_IN_SPARSE_HEADER 21
|
||||
|
||||
/* The GNU extra header contains some information GNU tar needs, but not
|
||||
foreseen in POSIX header format. It is only used after a POSIX header
|
||||
(and never with old GNU headers), and immediately follows this POSIX
|
||||
header, when typeflag is a letter rather than a digit, so signaling a GNU
|
||||
extension. */
|
||||
|
||||
struct extra_header
|
||||
{ /* byte offset */
|
||||
char atime[12]; /* 0 */
|
||||
char ctime[12]; /* 12 */
|
||||
char offset[12]; /* 24 */
|
||||
char realsize[12]; /* 36 */
|
||||
char longnames[4]; /* 48 */
|
||||
char unused_pad1[68]; /* 52 */
|
||||
struct sparse sp[SPARSES_IN_EXTRA_HEADER];
|
||||
/* 120 */
|
||||
char isextended; /* 504 */
|
||||
/* 505 */
|
||||
};
|
||||
|
||||
/* Extension header for sparse files, used immediately after the GNU extra
|
||||
header, and used only if all sparse information cannot fit into that
|
||||
extra header. There might even be many such extension headers, one after
|
||||
@@ -166,15 +139,17 @@ struct sparse_header
|
||||
struct oldgnu_header
|
||||
{ /* byte offset */
|
||||
char unused_pad1[345]; /* 0 */
|
||||
char atime[12]; /* 345 */
|
||||
char ctime[12]; /* 357 */
|
||||
char offset[12]; /* 369 */
|
||||
char longnames[4]; /* 381 */
|
||||
char atime[12]; /* 345 Incr. archive: atime of the file */
|
||||
char ctime[12]; /* 357 Incr. archive: ctime of the file */
|
||||
char offset[12]; /* 369 Multivolume archive: the offset of
|
||||
the start of this volume */
|
||||
char longnames[4]; /* 381 Not used */
|
||||
char unused_pad2; /* 385 */
|
||||
struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
|
||||
/* 386 */
|
||||
char isextended; /* 482 */
|
||||
char realsize[12]; /* 483 */
|
||||
char isextended; /* 482 Sparse file: Extension sparse header
|
||||
follows */
|
||||
char realsize[12]; /* 483 Sparse file: Real size*/
|
||||
/* 495 */
|
||||
};
|
||||
|
||||
@@ -185,7 +160,12 @@ struct oldgnu_header
|
||||
#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
|
||||
|
||||
/* The standards committee allows only capital A through capital Z for
|
||||
user-defined expansion. */
|
||||
user-defined expansion. Other letters in use include:
|
||||
|
||||
'A' Solaris Access Control List
|
||||
'E' Solaris Extended Attribute File
|
||||
'I' Inode only, as in 'star'
|
||||
'X' POSIX 1003.1-2001 eXtended (VU version) */
|
||||
|
||||
/* This is a dir entry that contains the names of files that were in the
|
||||
dir at the time the dump was made. */
|
||||
@@ -209,6 +189,57 @@ struct oldgnu_header
|
||||
/* This file is a tape/volume header. Ignore it on extraction. */
|
||||
#define GNUTYPE_VOLHDR 'V'
|
||||
|
||||
|
||||
/* J<>rg Schilling star header */
|
||||
|
||||
struct star_header
|
||||
{ /* byte offset */
|
||||
char name[100]; /* 0 */
|
||||
char mode[8]; /* 100 */
|
||||
char uid[8]; /* 108 */
|
||||
char gid[8]; /* 116 */
|
||||
char size[12]; /* 124 */
|
||||
char mtime[12]; /* 136 */
|
||||
char chksum[8]; /* 148 */
|
||||
char typeflag; /* 156 */
|
||||
char linkname[100]; /* 157 */
|
||||
char magic[6]; /* 257 */
|
||||
char version[2]; /* 263 */
|
||||
char uname[32]; /* 265 */
|
||||
char gname[32]; /* 297 */
|
||||
char devmajor[8]; /* 329 */
|
||||
char devminor[8]; /* 337 */
|
||||
char prefix[131]; /* 345 */
|
||||
char atime[12]; /* 476 */
|
||||
char ctime[12]; /* 488 */
|
||||
/* 500 */
|
||||
};
|
||||
|
||||
#define SPARSES_IN_STAR_HEADER 4
|
||||
#define SPARSES_IN_STAR_EXT_HEADER 21
|
||||
|
||||
struct star_in_header {
|
||||
char fill[345]; /* 0 Everything that is before t_prefix */
|
||||
char prefix[1]; /* 345 t_name prefix */
|
||||
char fill2; /* 346 */
|
||||
char fill3[8]; /* 347 */
|
||||
char isextended; /* 355 */
|
||||
struct sparse sp[SPARSES_IN_STAR_HEADER]; /* 356 */
|
||||
char realsize[12]; /* 452 Actual size of the file */
|
||||
char offset[12]; /* 464 Offset of multivolume contents */
|
||||
char atime[12]; /* 476 */
|
||||
char ctime[12]; /* 488 */
|
||||
char mfill[8]; /* 500 */
|
||||
char xmagic[4]; /* 508 "tar" */
|
||||
};
|
||||
|
||||
struct star_ext_header {
|
||||
struct sparse sp[SPARSES_IN_STAR_EXT_HEADER];
|
||||
char isextended;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* tar Header Block, overall structure. */
|
||||
|
||||
/* tar files are made in basic blocks of this size. */
|
||||
@@ -219,17 +250,60 @@ enum archive_format
|
||||
DEFAULT_FORMAT, /* format to be decided later */
|
||||
V7_FORMAT, /* old V7 tar format */
|
||||
OLDGNU_FORMAT, /* GNU format as per before tar 1.12 */
|
||||
POSIX_FORMAT, /* restricted, pure POSIX format */
|
||||
GNU_FORMAT /* POSIX format with GNU extensions */
|
||||
USTAR_FORMAT, /* POSIX.1-1988 (ustar) format */
|
||||
POSIX_FORMAT, /* POSIX.1-2001 format */
|
||||
STAR_FORMAT, /* Star format defined in 1994 */
|
||||
GNU_FORMAT /* Same as OLDGNU_FORMAT with one exception:
|
||||
see FIXME note for to_chars() function
|
||||
(create.c:189) */
|
||||
};
|
||||
|
||||
/* Information about a sparse file. */
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
};
|
||||
|
||||
struct tar_stat_info
|
||||
{
|
||||
char *orig_file_name; /* name of file read from the archive header */
|
||||
char *file_name; /* name of file for the current archive entry
|
||||
after being normalized. */
|
||||
int had_trailing_slash; /* nonzero if the current archive entry had a
|
||||
trailing slash before it was normalized. */
|
||||
char *link_name; /* name of link for the current archive entry. */
|
||||
|
||||
unsigned int devminor; /* device minor number */
|
||||
unsigned int devmajor; /* device major number */
|
||||
char *uname; /* user name of owner */
|
||||
char *gname; /* group name of owner */
|
||||
struct stat stat; /* regular filesystem stat */
|
||||
|
||||
/* Nanosecond parts of file timestamps (if available) */
|
||||
unsigned long atime_nsec;
|
||||
unsigned long mtime_nsec;
|
||||
unsigned long ctime_nsec;
|
||||
|
||||
off_t archive_file_size; /* Size of file as stored in the archive.
|
||||
Equals stat.st_size for non-sparse files */
|
||||
|
||||
size_t sparse_map_avail; /* Index to the first unused element in
|
||||
sparse_map array. Zero if the file is
|
||||
not sparse */
|
||||
size_t sparse_map_size; /* Size of the sparse map */
|
||||
struct sp_array *sparse_map;
|
||||
};
|
||||
|
||||
union block
|
||||
{
|
||||
char buffer[BLOCKSIZE];
|
||||
struct posix_header header;
|
||||
struct extra_header extra_header;
|
||||
struct star_header star_header;
|
||||
struct oldgnu_header oldgnu_header;
|
||||
struct sparse_header sparse_header;
|
||||
struct star_in_header star_in_header;
|
||||
struct star_ext_header star_ext_header;
|
||||
};
|
||||
|
||||
/* End of Format description. */
|
||||
|
||||
37
src/update.c
37
src/update.c
@@ -1,5 +1,7 @@
|
||||
/* Update a tar archive.
|
||||
Copyright 1988, 92, 94, 96, 97, 99, 2000 Free Software Foundation, Inc.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 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
|
||||
@@ -30,8 +32,10 @@ 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). */
|
||||
int time_to_start_writing;
|
||||
re-writing the current record (which has been changed).
|
||||
FIXME: Either eliminate it or move it to common.h.
|
||||
*/
|
||||
bool time_to_start_writing;
|
||||
|
||||
/* Pointer to where we started to write in the first record we write out.
|
||||
This is used if we can't backspace the output and have to null out the
|
||||
@@ -78,7 +82,10 @@ append_file (char *path)
|
||||
read_fatal_details (path, stat_data.st_size - bytes_left,
|
||||
buffer_size);
|
||||
if (status == 0)
|
||||
FATAL_ERROR ((0, 0, _("%s: File shrank by %s bytes"),
|
||||
FATAL_ERROR ((0, 0,
|
||||
ngettext ("%s: File shrank by %s byte",
|
||||
"%s: File shrank by %s bytes",
|
||||
bytes_left),
|
||||
quotearg_colon (path),
|
||||
STRINGIFY_BIGINT (bytes_left, buf)));
|
||||
|
||||
@@ -103,14 +110,16 @@ update_archive (void)
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
|
||||
xheader_write_global ();
|
||||
|
||||
while (!found_end)
|
||||
{
|
||||
enum read_header status = read_header ();
|
||||
enum read_header status = read_header (false);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
@@ -118,16 +127,17 @@ update_archive (void)
|
||||
struct name *name;
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
&& (name = name_scan (current_file_name), name))
|
||||
&& (name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
struct stat s;
|
||||
enum archive_format unused;
|
||||
|
||||
decode_header (current_header, ¤t_stat, &unused, 0);
|
||||
decode_header (current_header, ¤t_stat_info, &unused, 0);
|
||||
chdir_do (name->change_dir);
|
||||
if (deref_stat (dereference_option, current_file_name, &s) == 0
|
||||
&& s.st_mtime <= current_stat.st_mtime)
|
||||
add_avoided_name (current_file_name);
|
||||
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;
|
||||
@@ -159,6 +169,7 @@ update_archive (void)
|
||||
break;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
}
|
||||
break;
|
||||
@@ -168,13 +179,13 @@ update_archive (void)
|
||||
}
|
||||
|
||||
reset_eof ();
|
||||
time_to_start_writing = 1;
|
||||
time_to_start_writing = true;
|
||||
output_start = current_block->buffer;
|
||||
|
||||
{
|
||||
char *path;
|
||||
|
||||
while (path = name_from_list (), path)
|
||||
while ((path = name_from_list ()) != NULL)
|
||||
{
|
||||
if (excluded_name (path))
|
||||
continue;
|
||||
|
||||
351
src/utf8.c
Normal file
351
src/utf8.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/* Charset handling 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. */
|
||||
|
||||
#include "system.h"
|
||||
#include <quotearg.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 */
|
||||
};
|
||||
|
||||
/* The list of language codes defined in ISO 639 with the corresponding
|
||||
default character sets.
|
||||
|
||||
NOTES:
|
||||
|
||||
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 */
|
||||
|
||||
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 }
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
|
||||
|
||||
static iconv_t conv_desc[2] = { (iconv_t) -1, (iconv_t) -1 };
|
||||
|
||||
static iconv_t
|
||||
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 ());
|
||||
else
|
||||
conv_desc[(int) to_utf] = iconv_open (get_input_charset (), "UTF-8");
|
||||
}
|
||||
return conv_desc[(int) to_utf];
|
||||
}
|
||||
|
||||
bool
|
||||
utf8_convert(bool to_utf, char *input, char **output)
|
||||
{
|
||||
const char *ib;
|
||||
char *ob;
|
||||
size_t inlen;
|
||||
size_t outlen;
|
||||
size_t rc;
|
||||
iconv_t cd = utf8_init(to_utf);
|
||||
|
||||
if (cd == 0)
|
||||
{
|
||||
*output = xstrdup (input);
|
||||
return true;
|
||||
}
|
||||
else if (cd == (iconv_t)-1)
|
||||
return false;
|
||||
|
||||
inlen = strlen (input) + 1;
|
||||
outlen = inlen * MB_LEN_MAX + 1;
|
||||
ob = *output = xmalloc (outlen);
|
||||
ib = input;
|
||||
rc = iconv (cd, &ib, &inlen, &ob, &outlen);
|
||||
*ob = 0;
|
||||
return rc != -1;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
string_ascii_p (const char *str)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)str;
|
||||
for (; *p; p++)
|
||||
if (*p > 127)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
1036
src/xheader.c
Normal file
1036
src/xheader.c
Normal file
File diff suppressed because it is too large
Load Diff
8
tests/.cvsignore
Normal file
8
tests/.cvsignore
Normal file
@@ -0,0 +1,8 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
preset
|
||||
.deps
|
||||
genfile
|
||||
tmp-*
|
||||
directory
|
||||
archive
|
||||
@@ -1,41 +1,45 @@
|
||||
# Makefile for GNU tar regression tests.
|
||||
# Copyright <20> 1996, 1997 Free Software Foundation, Inc.
|
||||
# Fran<61>ois Pinard <pinard@iro.umontreal.ca>, 1988.
|
||||
|
||||
# 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.
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
# François Pinard <pinard@iro.umontreal.ca>, 1988.
|
||||
|
||||
# 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.
|
||||
## 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.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits ../src/ansi2knr
|
||||
check_PROGRAMS = genfile
|
||||
## 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_PROGRAMS = genfile mksparse
|
||||
BUILT_SOURCES = preset
|
||||
|
||||
TESTS = version.sh ignfail.sh extrac01.sh extrac02.sh extrac03.sh \
|
||||
old.sh volume.sh gzip.sh append.sh delete01.sh incremen.sh
|
||||
|
||||
# Postponed until after the 1.12 release.
|
||||
POSTPONED_TESTS = delete02.sh
|
||||
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
|
||||
|
||||
genfile_SOURCES = genfile.c
|
||||
EXTRA_DIST = after before preset.in $(TESTS) $(POSTPONED_TESTS)
|
||||
mksparse_SOURCES = mksparse.c
|
||||
EXTRA_DIST = after before preset.in $(TESTS)
|
||||
|
||||
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
|
||||
INCLUDES = -I.. -I../intl -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
LDADD = ../lib/libtar.a @INTLLIBS@
|
||||
localedir = $(prefix)/@DATADIRNAME@/locale
|
||||
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
|
||||
$(TESTS): genfile mksparse
|
||||
|
||||
19
tests/before
19
tests/before
@@ -17,3 +17,22 @@ 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
|
||||
}
|
||||
46
tests/delete03.sh
Executable file
46
tests/delete03.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#! /bin/sh
|
||||
# Deleting members with long file names.
|
||||
|
||||
# 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
|
||||
|
||||
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
|
||||
|
||||
out="\
|
||||
./${prefix}1
|
||||
./${prefix}2
|
||||
./${prefix}3
|
||||
./${prefix}4
|
||||
./${prefix}6
|
||||
./${prefix}7
|
||||
./${prefix}8
|
||||
./${prefix}9
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
34
tests/delete04.sh
Executable file
34
tests/delete04.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#! /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
|
||||
@@ -1,6 +1,9 @@
|
||||
/* Generate a file containing some preset patterns.
|
||||
Copyright <20> 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
Fran<EFBFBD>ois Pinard <pinard@iro.umontreal.ca>, 1995.
|
||||
|
||||
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
|
||||
@@ -19,6 +22,7 @@
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <argmatch.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#ifndef EXIT_SUCCESS
|
||||
@@ -30,8 +34,8 @@
|
||||
|
||||
enum pattern
|
||||
{
|
||||
DEFAULT,
|
||||
ZEROS
|
||||
DEFAULT_PATTERN,
|
||||
ZEROS_PATTERN
|
||||
};
|
||||
|
||||
/* The name this program was run with. */
|
||||
@@ -47,12 +51,9 @@ static int show_version = 0;
|
||||
static int file_length = 0;
|
||||
|
||||
/* Pattern to generate. */
|
||||
static enum pattern pattern = DEFAULT;
|
||||
|
||||
/*-----------------------------------------------.
|
||||
| Explain how to use the program, then get out. |
|
||||
`-----------------------------------------------*/
|
||||
static enum pattern pattern = DEFAULT_PATTERN;
|
||||
|
||||
/* Explain how to use the program, then get out. */
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
@@ -78,10 +79,8 @@ for the equivalent short option also.\n\
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------.
|
||||
| Main program. Decode ARGC arguments passed through the ARGV array of |
|
||||
| strings, then launch execution. |
|
||||
`----------------------------------------------------------------------*/
|
||||
/* Main program. Decode ARGC arguments passed through the ARGV array
|
||||
of strings, then launch execution. */
|
||||
|
||||
/* Long options equivalences. */
|
||||
static const struct option long_options[] =
|
||||
@@ -93,13 +92,8 @@ static const struct option long_options[] =
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
const char *pattern_strings[] =
|
||||
{
|
||||
"default", /* 0 */
|
||||
"zeros", /* 1 */
|
||||
NULL
|
||||
};
|
||||
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)
|
||||
@@ -127,25 +121,8 @@ main (int argc, char *const *argv)
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
switch (argmatch (optarg, pattern_strings))
|
||||
{
|
||||
|
||||
case -2:
|
||||
error (0, 0, _("Ambiguous pattern `%s'"), optarg);
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
case -1:
|
||||
error (0, 0, _("Unknown pattern `%s'"), optarg);
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
case 0:
|
||||
pattern = DEFAULT;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pattern = ZEROS;
|
||||
break;
|
||||
}
|
||||
pattern = XARGMATCH ("--pattern", optarg,
|
||||
pattern_args, pattern_types);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -154,18 +131,17 @@ main (int argc, char *const *argv)
|
||||
if (show_version)
|
||||
{
|
||||
printf ("genfile (GNU %s) %s\n", PACKAGE, VERSION);
|
||||
fputs (_("\
|
||||
\n\
|
||||
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.\n"),
|
||||
stdout);
|
||||
fputs (_("\
|
||||
This is free software; see the source for copying conditions. There is NO\n\
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"),
|
||||
stdout);
|
||||
fputs (_("\
|
||||
\n\
|
||||
Written by Fran<61>ois Pinard <pinard@iro.umontreal.ca>.\n"),
|
||||
stdout);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -179,12 +155,12 @@ Written by Fran
|
||||
|
||||
switch (pattern)
|
||||
{
|
||||
case DEFAULT:
|
||||
case DEFAULT_PATTERN:
|
||||
for (counter = 0; counter < file_length; counter++)
|
||||
putchar (counter & 255);
|
||||
break;
|
||||
|
||||
case ZEROS:
|
||||
case ZEROS_PATTERN:
|
||||
for (counter = 0; counter < file_length; counter++)
|
||||
putchar (0);
|
||||
break;
|
||||
|
||||
@@ -3,16 +3,31 @@
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
prereq gnu oldgnu
|
||||
|
||||
set -e
|
||||
mkdir structure
|
||||
touch structure/file
|
||||
# FIXME: The sleep is necessary for the second tar to work. Exactly why?
|
||||
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 -----
|
||||
touch structure/file
|
||||
sleep 1
|
||||
echo y >structure/file
|
||||
tar cfv archive --listed=list structure
|
||||
|
||||
out="\
|
||||
|
||||
57
tests/listed01.sh
Executable file
57
tests/listed01.sh
Executable file
@@ -0,0 +1,57 @@
|
||||
#! /bin/sh
|
||||
|
||||
# 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.
|
||||
# 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
|
||||
|
||||
mkdir directory
|
||||
dd if=/dev/zero of=directory/file1 bs=1024 count=10 2>/dev/null
|
||||
# Let the things settle
|
||||
sleep 1
|
||||
|
||||
tar --create \
|
||||
--file=archive.1 \
|
||||
--listed-incremental=listing \
|
||||
directory/file*
|
||||
|
||||
tar tf archive.1
|
||||
|
||||
dd if=/dev/zero of=directory/file2 bs=1024 count=20 2>/dev/null
|
||||
|
||||
echo "separator"
|
||||
|
||||
tar --create \
|
||||
--file=archive.2 \
|
||||
--listed-incremental=listing \
|
||||
directory/file*
|
||||
|
||||
tar tf archive.2
|
||||
|
||||
out="\
|
||||
directory/file1
|
||||
separator
|
||||
directory/file2
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
159
tests/mksparse.c
Normal file
159
tests/mksparse.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/* 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;
|
||||
}
|
||||
39
tests/multiv01.sh
Executable file
39
tests/multiv01.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#! /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
|
||||
16
tests/options.sh
Executable file
16
tests/options.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#! /bin/sh
|
||||
# Ensure that TAR_OPTIONS works in conjunction with old-style options.
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
echo > file1
|
||||
TAR_OPTIONS=--numeric-owner tar chof archive file1
|
||||
tar tf archive
|
||||
|
||||
out="\
|
||||
file1
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
15
tests/recurse.sh
Executable file
15
tests/recurse.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#! /bin/sh
|
||||
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
set -e
|
||||
mkdir directory
|
||||
touch directory/file
|
||||
tar --create --file archive --no-recursion directory || exit 1
|
||||
tar tf archive
|
||||
|
||||
out="directory/
|
||||
"
|
||||
|
||||
. $srcdir/after
|
||||
@@ -4,7 +4,7 @@
|
||||
. ./preset
|
||||
. $srcdir/before
|
||||
|
||||
tar cfVT archive label /dev/null || exit 1
|
||||
tar -cf archive -V label -T /dev/null --format=gnu || exit 1
|
||||
|
||||
tar xfV archive label || exit 1
|
||||
tar xfV archive 'la?el' || exit 1
|
||||
|
||||
Reference in New Issue
Block a user