Compare commits
506 Commits
old
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95256b3c07 | ||
|
|
a7109edd94 | ||
|
|
0500b1ba3e | ||
|
|
e8fa866d3a | ||
|
|
3e0962674f | ||
|
|
3295d54e21 | ||
|
|
be8899e6aa | ||
|
|
b5aff8401f | ||
|
|
933d42174f | ||
|
|
33715a50a3 | ||
|
|
3be53a3c2f | ||
|
|
4c004cff39 | ||
|
|
1c623b11f6 | ||
|
|
898dc536c6 | ||
|
|
2b708cb119 | ||
|
|
c6096f64c5 | ||
|
|
b9c6ebab26 | ||
|
|
bc07e8cce4 | ||
|
|
289687bd1c | ||
|
|
ee3b833d37 | ||
|
|
ad63cd4904 | ||
|
|
d58eaa815d | ||
|
|
f71b35b3f6 | ||
|
|
10eef2def8 | ||
|
|
07727fe74a | ||
|
|
ef87ce7d10 | ||
|
|
22fae29fb7 | ||
|
|
981980ac31 | ||
|
|
6246fffacd | ||
|
|
e128aa980c | ||
|
|
21002fe811 | ||
|
|
13ac1dcc0f | ||
|
|
1695e161be | ||
|
|
66cc5df1c6 | ||
|
|
fc22e70a00 | ||
|
|
43d020e35c | ||
|
|
6c1654791d | ||
|
|
4cca5e5887 | ||
|
|
24af03768f | ||
|
|
d2d8f9ab55 | ||
|
|
31e36b1e93 | ||
|
|
6c4dc180dd | ||
|
|
0273b1ae09 | ||
|
|
640effdebd | ||
|
|
d21a12cf62 | ||
|
|
6d9cdefe83 | ||
|
|
19d51157a5 | ||
|
|
4e2d5f2ee8 | ||
|
|
de5ec134a1 | ||
|
|
45399a7e81 | ||
|
|
e662d0f367 | ||
|
|
b7336abee0 | ||
|
|
dca678e62f | ||
|
|
39e95d7eee | ||
|
|
4b6f666105 | ||
|
|
a963130dd7 | ||
|
|
6f7d0eb14d | ||
|
|
8ad16912cf | ||
|
|
e17093af78 | ||
|
|
c5997e92f0 | ||
|
|
7be4d61e92 | ||
|
|
af244aeef3 | ||
|
|
005449337c | ||
|
|
a6d294236b | ||
|
|
f5461e304c | ||
|
|
3087f4c1c9 | ||
|
|
1b0a1ba7ed | ||
|
|
2bda83b48d | ||
|
|
41d042c05f | ||
|
|
b826791a01 | ||
|
|
2a384c4a84 | ||
|
|
f9dc020f90 | ||
|
|
466e40abe5 | ||
|
|
f131340d6d | ||
|
|
7e2a46c522 | ||
|
|
6dd96965de | ||
|
|
1bcc35dda0 | ||
|
|
2b861845e9 | ||
|
|
6cab217353 | ||
|
|
a5bafe7962 | ||
|
|
096bf74fcf | ||
|
|
a55ec0a319 | ||
|
|
61f44c9361 | ||
|
|
55a96565b5 | ||
|
|
15a607fc11 | ||
|
|
1329cfe9f8 | ||
|
|
3ff03c0c5e | ||
|
|
3030a247b1 | ||
|
|
22c2e2ab8a | ||
|
|
be48ff0699 | ||
|
|
a1d15e7c89 | ||
|
|
ad2c53d626 | ||
|
|
8c0cb259bf | ||
|
|
472f860074 | ||
|
|
d8981440bb | ||
|
|
7f2e3cf63a | ||
|
|
f7dbd14d57 | ||
|
|
106a24176e | ||
|
|
c83fcab116 | ||
|
|
4cb8697f60 | ||
|
|
6bd7b64c78 | ||
|
|
e5882c8220 | ||
|
|
72e3da5dc7 | ||
|
|
7b0b6c4e7a | ||
|
|
683390b02d | ||
|
|
e189bd8eca | ||
|
|
5282ef9709 | ||
|
|
b38e4b4520 | ||
|
|
9f14fd52de | ||
|
|
2345d02c63 | ||
|
|
6f219c485e | ||
|
|
a06ed48867 | ||
|
|
d6929326e7 | ||
|
|
7fb546943e | ||
|
|
37400fa94e | ||
|
|
8c1b242931 | ||
|
|
176557a004 | ||
|
|
427f8d6185 | ||
|
|
d584c1ed0f | ||
|
|
a8d1b579d7 | ||
|
|
5a9174376b | ||
|
|
cedd9d6e81 | ||
|
|
29584d69fd | ||
|
|
236deef28e | ||
|
|
ca84e28ee5 | ||
|
|
81bf1687f8 | ||
|
|
7afd75ed24 | ||
|
|
3dbc6a6645 | ||
|
|
d8b790047f | ||
|
|
fb9a7d180f | ||
|
|
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
|
||||
|
||||
110
NEWS
110
NEWS
@@ -1,4 +1,95 @@
|
||||
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.14 - Sergey Poznyakoff, 2004-05-11
|
||||
|
||||
* Added support for POSIX.1-2001 and ustar archive formats.
|
||||
* New option --format allows to select the output archive format
|
||||
* 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.
|
||||
|
||||
* New scripts: backup (replaces old level-0 and level-1) and restore.
|
||||
The scripts are compiled and installed if --enable-backup-scripts
|
||||
option is given to configure.
|
||||
|
||||
* By default tar searches "rmt" utility in "$prefix/libexec/rmt",
|
||||
which is consistent with the location where the version of "rmt"
|
||||
included in the package is installed. Previous versions of tar
|
||||
used "/etc/rmt". To install "rmt" to its traditional location,
|
||||
run configure with option --libexecdir=/etc. Otherwise, if you
|
||||
already have rmt installed and wish to use it, instead of the
|
||||
shipped in version, set the variable DEFAULT_RMT_COMMAND to
|
||||
the full path name of the utility, e.g. ./configure
|
||||
DEFAULT_RMT_COMMAND=/etc/rmt.
|
||||
|
||||
Notice also that the full path name of the "rmt" utility to
|
||||
use can be set at runtime, by giving option --rmt-command to
|
||||
tar.
|
||||
|
||||
* Removed obsolete command line options:
|
||||
** --absolute-paths superseded by --absolute-names
|
||||
** --block-compress is not needed any longer
|
||||
** --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 (Bokm<6B>l) has been withdrawn; use 'nb' instead.
|
||||
|
||||
* Bug fixes.
|
||||
|
||||
version 1.13.25 - Paul Eggert, 2001-09-26
|
||||
|
||||
* Bug fixes.
|
||||
|
||||
version 1.13.24 - Paul Eggert, 2001-09-22
|
||||
|
||||
* New option --overwrite-dir.
|
||||
* Fixes for buffer overrun, porting, and copyright notice problems.
|
||||
* The message translations for Korean are available again.
|
||||
|
||||
version 1.13.23 - Paul Eggert, 2001-09-13
|
||||
|
||||
@@ -104,7 +195,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 +388,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 +431,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 +567,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 +586,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:
|
||||
|
||||
46
PORTS
46
PORTS
@@ -1,17 +1,45 @@
|
||||
* Ports of GNU tar and other micro-tars -*- outline -*-
|
||||
* Ports of GNU tar and other tars -*- outline -*-
|
||||
|
||||
Please write tar-bugs@gnu.ai.mit.edu if you are aware of various ports
|
||||
of GNU tar to non-Unix systems not listed here, or for corrections.
|
||||
Many entries in this file are out of date, unfortunately.
|
||||
Please write bug-tar@gnu.org if you are aware of various ports of GNU tar
|
||||
to non-GNU and non-Unix systems not listed here, or for corrections.
|
||||
Please provide the goal system, a complete and stable URL, the maintainer
|
||||
name and address, the tar version used as a base, and your comments.
|
||||
|
||||
.* Copyright notice
|
||||
|
||||
Copyright (C) 1999, 2001, 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 GNU tar; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
.* GNU/Linux and Unix
|
||||
|
||||
. + Star is a tape archiver similar to tar.
|
||||
<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/star.html>
|
||||
|
||||
.* Amiga
|
||||
|
||||
. + ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/GNUtar-1.11.8.lha
|
||||
maintained by Enrico Forestieri <enrico@com.unipr.it>
|
||||
Based on tar 1.11.8.
|
||||
|
||||
. + ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
|
||||
. + [This link seems to be dead:]
|
||||
ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
|
||||
maintained by the ADE group <fnf@fishpond.ninemoons.com>
|
||||
Based on tar 1.11.8, needs ixemul.library.
|
||||
|
||||
@@ -20,12 +48,14 @@
|
||||
|
||||
.* DEC alpha (NT)
|
||||
|
||||
. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
. + [This link seems to be dead:]
|
||||
ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
|
||||
maintained by Drew Bliss & Geoff Voelker
|
||||
|
||||
.* DEC VAX (VMS)
|
||||
|
||||
. + http://www.lp.se/free/vmstar/
|
||||
. + [This link seems to be dead:]
|
||||
http://www.lp.se/free/vmstar/
|
||||
maintained by Richard Levitte <levitte@lp.se>
|
||||
This is not GNU tar, but a separate implementation.
|
||||
|
||||
@@ -124,6 +154,10 @@
|
||||
|
||||
.* Macintosh
|
||||
|
||||
. + Paulo Abreu (paulotex at yahoo dot com) did a
|
||||
limited port of GNU tar to Darwin, with support for resource forks
|
||||
and finder info, but this no longer seems to be available.
|
||||
|
||||
. + There is a tar in Stuffit Expander which is available many places and
|
||||
comes with MacOS. It creates some spurious files but works on average.
|
||||
|
||||
|
||||
177
README
177
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,37 @@ 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/.
|
||||
** Selecting full pathname of the "rmt" binary.
|
||||
|
||||
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.
|
||||
Previous versions of tar always looked for "rmt" binary using
|
||||
hardcoded path "/etc/rmt". However, the "rmt" program included
|
||||
in the distribution was installed under "$prefix/libexec/rmt".
|
||||
To fix this discrepancy, tar now looks for "$prefix/libexec/rmt".
|
||||
If you do not want this behavior, specify full path name of
|
||||
"rmt" binary using DEFAULT_RMT_COMMAND variable, e.g.:
|
||||
|
||||
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>.
|
||||
./configure DEFAULT_RMT_COMMAND=/etc/rmt
|
||||
|
||||
** Installing backup scripts.
|
||||
|
||||
Installation hints
|
||||
------------------
|
||||
This version of tar is shipped with the shell scripts for producing
|
||||
incremental backups (dumps) and restoring filesystems from them.
|
||||
The name of the backup script is "backup". The name of the
|
||||
restore script is "restore". They are installed in "$prefix/sbin"
|
||||
directory.
|
||||
|
||||
Use option --enable-backup-scripts to compile and install these
|
||||
scripts.
|
||||
|
||||
** `--disable-largefile' omits support for large files, even if the
|
||||
operating system supports large files. Typically, large files are
|
||||
those larger on 2 GB on a 32-bit host.
|
||||
|
||||
* 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 +97,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 +108,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 +129,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 +167,77 @@ 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.
|
||||
GNU tar will be merged into GNU paxutils: a project containing
|
||||
several utilities related to creating and handling archives in
|
||||
various formats. The project will include tar, cpio and pax
|
||||
utilities.
|
||||
|
||||
* Bug reporting.
|
||||
|
||||
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%
|
||||
|
||||
104
THANKS
104
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<61>§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<EFBFBD>§ois Pinard pinard@iro.umontreal.ca
|
||||
Fritz Elfert fritz@fsun.triltsch.de
|
||||
George Chyu gschyu@ccgate.dp.beckman.com
|
||||
Gerben Wierda gerben@rna.indiv.nluug.nl
|
||||
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<EFBFBD>¶ran Uddeborg gvran@uddeborg.pp.se
|
||||
Hans Guerth 100664.3101@compuserve.com
|
||||
Harald K<>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,16 @@ 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<>ters jlueters@t-online.de
|
||||
J<EFBFBD>rgen Reiss reiss@psychologie.uni-wuerzburg.de
|
||||
J<EFBFBD>¼rgen L<>¼ters jlueters@t-online.de
|
||||
J<EFBFBD>¼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<>gg Jorgen.Hagg@axis.se
|
||||
J<EFBFBD>¶rg Weule weule@cs.uni-duesseldorf.de
|
||||
J<EFBFBD>¶rgen H<>¤gg Jorgen.Hagg@axis.se
|
||||
J<EFBFBD>¶rgen Weigert jw@suse.de
|
||||
Kai Petzke wpp@marie.physik.tu-berlin.de
|
||||
Kai Schlichting kai@computel.com
|
||||
Karl Berry karl@cs.umb.edu
|
||||
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
|
||||
@@ -266,10 +280,13 @@ Larry Creech lcreech@lonestar.rcclub.org
|
||||
Larry Schwimmer rosebud@cyclone.stanford.edu
|
||||
Laurent Caillat-Vallet caillat@noe.lyon.cemagref.fr
|
||||
Laurent Sainte-Marthe smarthe@genethon.fr
|
||||
Leland Lucius llucius@tiny.net
|
||||
Les Mikesell les@mcs.com
|
||||
Loren J. Rittle rittle@comm.mot.com
|
||||
Lo<EFBFBD>c Prylli Loic.Prylli@lip.ens-lyon.fr
|
||||
Lo<EFBFBD>¯c Prylli Loic.Prylli@lip.ens-lyon.fr
|
||||
Luke Mewburn lukem@connect.com.au
|
||||
Mads Martin Joergensen mmj@suse.de
|
||||
Machael Stone mstone@cs.loyola.edu
|
||||
Manfred Weichel Manfred.Weichel@mch.sni.de
|
||||
Manuel Munier Manuel.Munier@loria.fr
|
||||
Marc Boucher marc@cam.org
|
||||
@@ -283,7 +300,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 +310,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 +335,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 +373,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 +382,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 +405,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 +430,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 +441,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<>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 +469,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 (--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:
|
||||
|
||||
239
bootstrap
Executable file
239
bootstrap
Executable file
@@ -0,0 +1,239 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Bootstrap 'tar' from CVS.
|
||||
|
||||
# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the 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
|
||||
gettime
|
||||
hash
|
||||
human
|
||||
lchown
|
||||
memset
|
||||
modechange
|
||||
obstack
|
||||
quote
|
||||
quotearg
|
||||
rmdir
|
||||
safe-read
|
||||
save-cwd
|
||||
savedir
|
||||
stdbool
|
||||
stpcpy
|
||||
strtol
|
||||
strtoul
|
||||
timespec
|
||||
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/intdiv0.m4) continue;;
|
||||
m4/inttypes-pri.m4) continue;;
|
||||
m4/isc-posix.m4) continue;;
|
||||
m4/lcmessage.m4) continue;;
|
||||
m4/onceonly_2_57.m4) dest=m4/onceonly.m4;;
|
||||
# These will be overwritten by autopoint, which still uses
|
||||
# old jm_.* macro names, so we have to keep both copies.
|
||||
m4/ulonglong.m4) dest=m4/ulonglong_gl.m4;;
|
||||
m4/inttypes_h.m4) dest=m4/inttypes_h_gl.m4;;
|
||||
m4/stdint_h.m4) dest=m4/stdint_h_gl.m4;;
|
||||
m4/uintmax_t.m4) dest=m4/uintmax_t_gl.m4;;
|
||||
esac
|
||||
|
||||
rm -f $dest &&
|
||||
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file" &&
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
|
||||
done
|
||||
|
||||
echo "$0: Creating m4/gnulib.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([tar_GNULIB],["
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-autoconf-snippet $gnulib_module
|
||||
done | sed '/AM_GNU_GETTEXT/d'
|
||||
echo "])") > ./m4/gnulib.m4
|
||||
|
||||
echo "$0: Creating lib/Makefile.am"
|
||||
(cat lib/Makefile.tmpl
|
||||
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$GNULIB_SRCDIR/gnulib-tool --extract-automake-snippet $gnulib_module
|
||||
done | sed 's/lib_SOURCES/libtar_a_SOURCES/g' ) > lib/Makefile.am
|
||||
|
||||
# Get 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'."
|
||||
326
configure.ac
326
configure.ac
@@ -1,47 +1,53 @@
|
||||
# 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.14], [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/param.h sys/device.h sys/gentape.h \
|
||||
sys/inet.h sys/io/trioctl.h \
|
||||
sys/mtio.h sys/time.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_CHECK_HEADERS([sys/buf.h], [], [],
|
||||
[#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif])
|
||||
|
||||
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 +57,98 @@ 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
|
||||
gl_AC_TYPE_INTMAX_T
|
||||
jm_AC_TYPE_UINTMAX_T
|
||||
|
||||
AC_CACHE_CHECK(for mknod, tar_cv_func_mknod,
|
||||
[AC_TRY_LINK([
|
||||
# gnulib modules
|
||||
tar_GNULIB
|
||||
|
||||
|
||||
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>])
|
||||
|
||||
# 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.
|
||||
# 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.
|
||||
|
||||
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
|
||||
# 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_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"
|
||||
AC_CHECK_FUNCS(fsync lstat mkfifo readlink strerror symlink setlocale utimes)
|
||||
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
|
||||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||||
AC_CHECK_DECLS([valloc])
|
||||
AC_CHECK_DECLS([time],,, [#include <time.h>])
|
||||
|
||||
# The 3-argument open happens to go along with the O_* defines, which
|
||||
# are easier to check for.
|
||||
# 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])
|
||||
|
||||
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
|
||||
case "$ac_cv_search_setsockopt" in
|
||||
-l*) LIB_SETSOCKOPT=$ac_cv_search_setsockopt
|
||||
esac
|
||||
AC_SUBST(LIB_SETSOCKOPT)
|
||||
LIBS=$tar_save_LIBS
|
||||
|
||||
# `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,22 +156,48 @@ 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)
|
||||
|
||||
AC_ARG_VAR([DEFAULT_ARCHIVE_FORMAT],
|
||||
[Set the default archive format. Allowed values are: V7, OLDGNU, USTAR, POSIX, GNU. Default is GNU])
|
||||
|
||||
if test -z "$DEFAULT_ARCHIVE_FORMAT"; then
|
||||
DEFAULT_ARCHIVE_FORMAT="GNU"
|
||||
fi
|
||||
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)
|
||||
|
||||
AC_ARG_VAR([DEFAULT_ARCHIVE],
|
||||
[Set the name of the default archive (default: -)])
|
||||
if test -z "$DEFAULT_ARCHIVE"; then
|
||||
DEFAULT_ARCHIVE=-
|
||||
else
|
||||
@@ -181,35 +208,84 @@ 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_ARG_VAR([DEFAULT_BLOCKING],
|
||||
[Define default blocking factor (default: 20)])
|
||||
AC_MSG_CHECKING(for default blocking)
|
||||
DEFAULT_BLOCKING=${DEFAULT_BLOCKING-20}
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_BLOCKING, $DEFAULT_BLOCKING)
|
||||
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
|
||||
AC_ARG_VAR([DEFAULT_RMT_COMMAND],
|
||||
[Define full pathname of rmt program.])
|
||||
if test "x$DEFAULT_RMT_COMMAND" != x; then
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RMT_COMMAND, "$DEFAULT_RMT_COMMAND",
|
||||
[Define full pathname of rmt program.])
|
||||
fi
|
||||
|
||||
AM_GNU_GETTEXT
|
||||
AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-ngettext])
|
||||
AM_GNU_GETTEXT_VERSION(0.12.1)
|
||||
|
||||
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])
|
||||
# Iconv
|
||||
AM_ICONV
|
||||
AC_CHECK_HEADERS(iconv.h)
|
||||
AC_CHECK_TYPE(iconv_t,:,
|
||||
AC_DEFINE(iconv_t, int,
|
||||
[Conversion descriptor type]),
|
||||
[
|
||||
#ifdef HAVE_ICONV_H
|
||||
# include <iconv.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_SUBST(BACKUP_LIBEXEC_SCRIPTS)
|
||||
AC_SUBST(BACKUP_SBIN_SCRIPTS)
|
||||
AC_ARG_ENABLE(backup-scripts,
|
||||
AC_HELP_STRING([--enable-backup-scripts],
|
||||
[Create and install backup and restore scripts]),
|
||||
[case $enableval in
|
||||
yes) BACKUP_LIBEXEC_SCRIPTS='$(BACKUP_LIBEXEC_SCRIPTS_LIST)'
|
||||
BACKUP_SBIN_SCRIPTS='$(BACKUP_SBIN_SCRIPTS_LIST)'
|
||||
;;
|
||||
esac])
|
||||
|
||||
AC_SUBST(BACKUP_SED_COND)
|
||||
if date +%Y-%m-%d 2>/dev/null >&2; then
|
||||
BACKUP_SED_COND='/^\#ELSE_DATE_FORMAT_OK/,/^\#ENDIF_DATE_FORMAT_OK/d;/^\#IF_DATE_FORMAT_OK/d'
|
||||
else
|
||||
BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
|
||||
fi
|
||||
|
||||
|
||||
AC_OUTPUT([Makefile\
|
||||
doc/Makefile\
|
||||
lib/Makefile\
|
||||
po/Makefile.in\
|
||||
scripts/Makefile\
|
||||
src/Makefile\
|
||||
tests/Makefile\
|
||||
tests/preset])
|
||||
|
||||
29
doc/.cvsignore
Normal file
29
doc/.cvsignore
Normal file
@@ -0,0 +1,29 @@
|
||||
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
|
||||
tmp-tar.*
|
||||
@@ -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:
|
||||
|
||||
117
doc/getdate.texi
117
doc/getdate.texi
@@ -1,8 +1,20 @@
|
||||
@c GNU date syntax documentation
|
||||
|
||||
@c Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
@c 2003, 2004 Free Software 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 or
|
||||
@c any later version published by the Free Software Foundation; with no
|
||||
@c Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
@c Texts. A copy of the license is included in the ``GNU Free
|
||||
@c Documentation License'' file as part of this distribution.
|
||||
|
||||
@node Date input formats
|
||||
@chapter Date input formats
|
||||
|
||||
@cindex date input formats
|
||||
@findex getdate
|
||||
@findex get_date
|
||||
|
||||
First, a quote:
|
||||
|
||||
@@ -33,19 +45,7 @@ or a week from Sunday, with feelings of helpless confusion. @dots{}
|
||||
This section describes the textual date representations that @sc{gnu}
|
||||
programs accept. These are the strings you, as a user, can supply as
|
||||
arguments to the various programs. The C interface (via the
|
||||
@code{getdate} function) is not described here.
|
||||
|
||||
@cindex beginning of time, for @sc{posix}
|
||||
@cindex epoch, for @sc{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
|
||||
have 32-bit signed @code{time_t} and can represent times from 1901-12-13
|
||||
20:45:52 through 2038-01-19 03:14:07 @sc{utc}. Systems with 64-bit
|
||||
signed @code{time_t} can represent all the times in the known
|
||||
lifetime of the universe.
|
||||
@code{get_date} function) is not described here.
|
||||
|
||||
@menu
|
||||
* General date syntax:: Common rules.
|
||||
@@ -55,7 +55,8 @@ lifetime of the universe.
|
||||
* Day of week items:: Monday and others.
|
||||
* Relative items in date strings:: next tuesday, 2 years ago.
|
||||
* Pure numbers in date strings:: 19931219, 1440.
|
||||
* Authors of getdate:: Bellovin, Eggert, Salz, Berets, et al.
|
||||
* Seconds since the Epoch:: @@1078100502.
|
||||
* Authors of get_date:: Bellovin, Eggert, Salz, Berets, et al.
|
||||
@end menu
|
||||
|
||||
|
||||
@@ -117,15 +118,17 @@ ways to do this:
|
||||
|
||||
@example
|
||||
$ LC_ALL=C TZ=UTC0 date
|
||||
Fri Dec 15 19:48:05 UTC 2000
|
||||
$ TZ=UTC0 date +"%Y-%m-%d %H:%M:%SZ"
|
||||
2000-12-15 19:48:05Z
|
||||
$ date --iso-8601=seconds # a GNU extension
|
||||
2000-12-15T11:48:05-0800
|
||||
$ date --rfc-822 # a GNU extension
|
||||
Fri, 15 Dec 2000 11:48:05 -0800
|
||||
$ date +"%Y-%m-%d %H:%M:%S %z" # %z is a GNU extension.
|
||||
2000-12-15 11:48:05 -0800
|
||||
Mon Mar 1 00:21:42 UTC 2004
|
||||
$ TZ=UTC0 date +'%Y-%m-%d %H:%M:%SZ'
|
||||
2004-03-01 00:21:42Z
|
||||
$ date --iso-8601=ns # a GNU extension
|
||||
2004-02-29T16:21:42,692722128-0800
|
||||
$ date --rfc-2822 # a GNU extension
|
||||
Sun, 29 Feb 2004 16:21:42 -0800
|
||||
$ date +'%Y-%m-%d %H:%M:%S %z' # %z is a GNU extension.
|
||||
2004-02-29 16:21:42 -0800
|
||||
$ date +'@@%s.%N' # %s and %N are GNU extensions.
|
||||
@@1078100502.692722128
|
||||
@end example
|
||||
|
||||
@cindex case, ignored in dates
|
||||
@@ -216,7 +219,7 @@ A @dfn{time of day item} in date strings specifies the time on a given
|
||||
day. Here are some examples, all of which represent the same time:
|
||||
|
||||
@example
|
||||
20:02:0
|
||||
20:02:00.000000
|
||||
20:02
|
||||
8:02pm
|
||||
20:02-0500 # In @sc{est} (U.S. Eastern Standard Time).
|
||||
@@ -225,7 +228,9 @@ day. Here are some examples, all of which represent the same time:
|
||||
More generally, the time of the day may be given as
|
||||
@samp{@var{hour}:@var{minute}:@var{second}}, where @var{hour} is
|
||||
a number between 0 and 23, @var{minute} is a number between 0 and
|
||||
59, and @var{second} is a number between 0 and 59. Alternatively,
|
||||
59, and @var{second} is a number between 0 and 59 possibly followed by
|
||||
@samp{.} or @samp{,} and a fraction containing one or more digits.
|
||||
Alternatively,
|
||||
@samp{:@var{second}} can be omitted, in which case it is taken to
|
||||
be zero.
|
||||
|
||||
@@ -370,6 +375,26 @@ When a relative item causes the resulting date to cross a boundary
|
||||
where the clocks were adjusted, typically for daylight-saving time,
|
||||
the resulting date and time are adjusted accordingly.
|
||||
|
||||
The fuzz in units can cause problems with relative items. For
|
||||
example, @samp{2003-07-31 -1 month} might evaluate to 2003-07-01,
|
||||
because 2003-06-31 is an invalid date. To determine the previous
|
||||
month more reliably, you can ask for the month before the 15th of the
|
||||
current month. For example:
|
||||
|
||||
@example
|
||||
$ date -R
|
||||
Thu, 31 Jul 2003 13:02:39 -0700
|
||||
$ date --date='-1 month' +'Last month was %B?'
|
||||
Last month was July?
|
||||
$ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
|
||||
Last month was June!
|
||||
@end example
|
||||
|
||||
Also, take care when manipulating dates around clock changes such as
|
||||
daylight saving leaps. In a few cases these have added or subtracted
|
||||
as much as 24 hours from the clock, so it is often wise to adopt
|
||||
universal time by setting the @env{TZ} environment variable to
|
||||
@samp{UTC0} before embarking on calendrical calculations.
|
||||
|
||||
@node Pure numbers in date strings
|
||||
@section Pure numbers in date strings
|
||||
@@ -395,10 +420,42 @@ in the date string, but no relative item, then the number overrides the
|
||||
year.
|
||||
|
||||
|
||||
@node Authors of getdate
|
||||
@section Authors of @code{getdate}
|
||||
@node Seconds since the Epoch
|
||||
@section Seconds since the Epoch
|
||||
|
||||
@cindex authors of @code{getdate}
|
||||
If you precede a number with @samp{@@}, it represents an internal time
|
||||
stamp as a count of seconds. The number can contain an internal
|
||||
decimal point (either @samp{.} or @samp{,}); any excess precision not
|
||||
supported by the internal representation is truncated toward minus
|
||||
infinity.
|
||||
|
||||
@cindex beginning of time, for @acronym{POSIX}
|
||||
@cindex epoch, for @acronym{POSIX}
|
||||
Internally, computer times are represented as a count of seconds since
|
||||
an epoch---a well-defined point of time. On @acronym{GNU} and
|
||||
@acronym{POSIX} systems, the epoch is 1970-01-01 00:00:00 @sc{utc}, so
|
||||
@samp{@@0} represents this time, @samp{@@1} represents 1970-01-01
|
||||
00:00:01 @sc{utc}, and so forth. @acronym{GNU} and most other
|
||||
@acronym{POSIX}-compliant systems support such times as an extension
|
||||
to @acronym{POSIX}, using negative counts, so that @samp{@@-1}
|
||||
represents 1969-12-31 23:59:59 @sc{utc}.
|
||||
|
||||
Traditional Unix systems count seconds with 32-bit two's-complement
|
||||
integers and can represent times from 1901-12-13 20:45:52 through
|
||||
2038-01-19 03:14:07 @sc{utc}. More modern systems use 64-bit counts
|
||||
of seconds with nanosecond subcounts, and can represent all the times
|
||||
in the known lifetime of the universe to a resolution of 1 nanosecond.
|
||||
|
||||
On most systems, these counts ignore the presence of leap seconds.
|
||||
For example, on most systems @samp{@@915148799} represents 1998-12-31
|
||||
23:59:59 @sc{utc}, @samp{@@915148800} represents 1999-01-01 00:00:00
|
||||
@sc{utc}, and there is no way to represent the intervening leap second
|
||||
1998-12-31 23:59:60 @sc{utc}.
|
||||
|
||||
@node Authors of get_date
|
||||
@section Authors of @code{get_date}
|
||||
|
||||
@cindex authors of @code{get_date}
|
||||
|
||||
@cindex Bellovin, Steven M.
|
||||
@cindex Salz, Rich
|
||||
@@ -406,7 +463,7 @@ year.
|
||||
@cindex MacKenzie, David
|
||||
@cindex Meyering, Jim
|
||||
@cindex Eggert, Paul
|
||||
@code{getdate} was originally implemented by Steven M. Bellovin
|
||||
@code{get_date} was originally implemented by Steven M. Bellovin
|
||||
(@email{smb@@research.att.com}) while at the University of North Carolina
|
||||
at Chapel Hill. The code was later tweaked by a couple of people on
|
||||
Usenet, then completely overhauled by Rich $alz (@email{rsalz@@bbn.com})
|
||||
|
||||
3224
doc/tar.texi
3224
doc/tar.texi
File diff suppressed because it is too large
Load Diff
100
lib/.cvsignore
Normal file
100
lib/.cvsignore
Normal file
@@ -0,0 +1,100 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.am
|
||||
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
|
||||
getopt_int.h
|
||||
gettext.h
|
||||
gettime.c
|
||||
gettimeofday.c
|
||||
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
|
||||
stpcpy.c
|
||||
stpcpy.h
|
||||
strcase.h
|
||||
strcasecmp.c
|
||||
stripslash.c
|
||||
strncasecmp.c
|
||||
strtoimax.c
|
||||
strtol.c
|
||||
strtoll.c
|
||||
strtoul.c
|
||||
strtoull.c
|
||||
strtoumax.c
|
||||
time_r.c
|
||||
time_r.h
|
||||
timespec.h
|
||||
unlocked-io.h
|
||||
utime.c
|
||||
xalloc.h
|
||||
xgetcwd.c
|
||||
xgetcwd.h
|
||||
xmalloc.c
|
||||
xstrdup.c
|
||||
xstrtol.c
|
||||
xstrtol.h
|
||||
xstrtoul.c
|
||||
xstrtoumax.c
|
||||
@@ -1,45 +0,0 @@
|
||||
# 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.
|
||||
|
||||
# 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
|
||||
|
||||
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
|
||||
|
||||
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_DEPENDENCIES = $(libtar_a_LIBADD)
|
||||
|
||||
# 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; \
|
||||
mv -f y.tab.c getdate.c
|
||||
43
lib/Makefile.tmpl
Normal file
43
lib/Makefile.tmpl
Normal file
@@ -0,0 +1,43 @@
|
||||
# Makefile for GNU tar library.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004
|
||||
# Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2, or (at your option)
|
||||
## any later version.
|
||||
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
noinst_LIBRARIES = libtar.a
|
||||
|
||||
libtar_a_SOURCES = prepargs.c prepargs.h
|
||||
|
||||
libtar_a_LIBADD = $(LIBOBJS) $(ALLOCA)
|
||||
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
|
||||
|
||||
BUILT_SOURCES =
|
||||
EXTRA_DIST = Makefile.tmpl
|
||||
MAINTAINERCLEANFILES =
|
||||
MOSTLYCLEANFILES =
|
||||
lib_OBJECTS = $(libtar_a_OBJECTS)
|
||||
|
||||
# Special rule for getdate
|
||||
#
|
||||
# Say $(srcdir), so GNU make does not report an ambiguity with the .y.c rule.
|
||||
$(srcdir)/getdate.c: getdate.y
|
||||
cd $(srcdir) && \
|
||||
$(YACC) $(YFLAGS) getdate.y && \
|
||||
mv -f y.tab.c getdate.c
|
||||
|
||||
# gnulib modules
|
||||
|
||||
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
|
||||
|
||||
|
||||
100
m4/.cvsignore
Normal file
100
m4/.cvsignore
Normal file
@@ -0,0 +1,100 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
alloca.m4
|
||||
backupfile.m4
|
||||
bison.m4
|
||||
chown.m4
|
||||
clock_time.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
|
||||
gettime.m4
|
||||
gettimeofday.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
|
||||
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
|
||||
restrict.m4
|
||||
rmdir.m4
|
||||
safe-read.m4
|
||||
safe-write.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
signed.m4
|
||||
size_max.m4
|
||||
ssize_t.m4
|
||||
st_mtim.m4
|
||||
stdbool.m4
|
||||
stdint_h.m4
|
||||
stpcpy.m4
|
||||
strcase.m4
|
||||
strerror_r.m4
|
||||
strtoimax.m4
|
||||
strtol.m4
|
||||
strtoll.m4
|
||||
strtoul.m4
|
||||
strtoull.m4
|
||||
strtoumax.m4
|
||||
time_r.m4
|
||||
timespec.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
|
||||
*_gl.m4
|
||||
gnulib.m4
|
||||
malloc.m4
|
||||
realloc.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
|
||||
|
||||
6
scripts/.cvsignore
Normal file
6
scripts/.cvsignore
Normal file
@@ -0,0 +1,6 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
backup.sh
|
||||
backup
|
||||
restore
|
||||
dump-remind
|
||||
@@ -1,5 +1,4 @@
|
||||
# Makefile for GNU tar scripts.
|
||||
# Copyright (C) 1994 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
@@ -12,9 +11,39 @@
|
||||
## GNU General Public License for more details.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software Foundation,
|
||||
## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
AUTOMAKE_OPTIONS = gnits
|
||||
BACKUP_LIBEXEC_SCRIPTS_LIST=backup.sh dump-remind
|
||||
BACKUP_SBIN_SCRIPTS_LIST=backup restore
|
||||
libexec_SCRIPTS=@BACKUP_LIBEXEC_SCRIPTS@
|
||||
AM_INSTALLCHECK_STD_OPTIONS_EXEMPT=backup.sh dump-remind
|
||||
sbin_SCRIPTS=@BACKUP_SBIN_SCRIPTS@
|
||||
EXTRA_SCRIPTS=
|
||||
EXTRA_DIST=\
|
||||
backup.sh.in\
|
||||
backup.in\
|
||||
restore.in\
|
||||
dump-remind.in\
|
||||
backup-specs
|
||||
CLEANFILES=backup.sh backup restore dump-remind
|
||||
|
||||
EXTRA_DIST = WARNING backup-specs dump-remind level-0 level-1 weekly.new
|
||||
SED_CMD="s,\@libexecdir\@,$(libexecdir),;\
|
||||
s,\@sysconfdir\@,$(sysconfdir),;\
|
||||
s,\@PACKAGE\@,$(PACKAGE),;\
|
||||
s,\@VERSION\@,$(VERSION),;\
|
||||
s,\@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),;\
|
||||
s,\@DATE_FORMAT_OK\@,$(DATE_FORMAT_OK),;@BACKUP_SED_COND@"
|
||||
|
||||
backup.sh: $(srcdir)/backup.sh.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
backup: $(srcdir)/backup.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
restore: $(srcdir)/restore.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
|
||||
dump-remind: $(srcdir)/dump-remind.in
|
||||
sed $(SED_CMD) $? > $@
|
||||
@@ -1,3 +0,0 @@
|
||||
GNU tar scripts have not been updated in a long while. make will
|
||||
not not install them. Please consider the contents of this directory
|
||||
are provided as indicative for the time being.
|
||||
@@ -1,34 +1,68 @@
|
||||
# site-specific parameters for file system backup.
|
||||
# This is a sample configuration file for GNU tar backup script.
|
||||
# See end of file for copying conditions
|
||||
|
||||
# User name of administrator of backups.
|
||||
ADMINISTRATOR=backup-reports
|
||||
# User name or email address of the administrator of backups. A report
|
||||
# will be sent to this address when the backup terminates
|
||||
ADMINISTRATOR="root@localhost"
|
||||
|
||||
# Hour at which backups are normally done.
|
||||
# This should be a number from 0 to 23.
|
||||
BACKUP_HOUR=1
|
||||
# (Optional) Path to tar binary.
|
||||
TAR=/bin/tar
|
||||
|
||||
# Location of GNU tar. This must be the same for all hosts.
|
||||
TAR=/usr/local/gnubin/tar
|
||||
# (Optional) Path to rsh binary or its equivalent. You may wish to
|
||||
# set it to ssh as shown in the example below, to improve security.
|
||||
# In this case you will have to use public key authentication.
|
||||
RSH=/usr/local/bin/ssh
|
||||
|
||||
# (Optional) Path to rsh binary on remote mashines. This will be
|
||||
# passed via --rsh-command option to the remote invocation of
|
||||
# tar
|
||||
RSH_COMMAND=/usr/local/bin/ssh
|
||||
|
||||
# Name of temporary file to hold volume numbers. This needs to be accessible
|
||||
# by all the machines which have filesystems to be dumped.
|
||||
VOLNO_FILE=/root/volume
|
||||
|
||||
# Device to use for dumping. It should be on the host
|
||||
# on which the dump scripts are run.
|
||||
TAPE_FILE=/dev/nrsmt0
|
||||
|
||||
# Command to obtain status of tape drive, including error count.
|
||||
# On some tape drives there may not be such a command;
|
||||
# then simply use `TAPE_STATUS=false'.
|
||||
#
|
||||
# Might also consider
|
||||
# TAPE_STATUS="mt -f ${TAPE_FILE} status"
|
||||
# if `mts' is missing, though this alternative is rather verbose.
|
||||
TAPE_STATUS="mts -t ${TAPE_FILE}"
|
||||
TAPE_FILE=/dev/rmt0
|
||||
|
||||
# Blocking factor to use for writing the dump.
|
||||
BLOCKING=124
|
||||
|
||||
# Name of temporary file to hold volume numbers. This needs to be accessible
|
||||
# by all the machines which have filesystems to be dumped.
|
||||
VOLNO_FILE=/home/gd2/dump/volnofile
|
||||
# List of file systems to be dumped. If prefixed with a HOST:
|
||||
# the filesystem is accessed on the given HOST, unless it
|
||||
# coincides with the local machine name.
|
||||
# If a file system starts with a slash, it is handled as a local
|
||||
# one.
|
||||
BACKUP_DIRS='remote1:/etc remote1:/var/spool/crontab'
|
||||
# Alternatively, you may leave this variable unassigned, and
|
||||
# keep the list of filesystems to be dumped in file
|
||||
# $SYSCONFDIR/backup/dirs, one filesystem per line. Empty
|
||||
# lines and shell comments are allowed in this file. The location
|
||||
# of this file may be overridden using DIRLIST variable, e.g.:
|
||||
# DIRLIST=/etc/my-backup/dirlist
|
||||
|
||||
# List of individual files to be dumped.
|
||||
# These should be accesible from the machine on which the dump is run.
|
||||
BACKUP_FILES=''
|
||||
# This list may also be kept in file $SYSCONFDIR/backup/files, the
|
||||
# format of which is the same as described above. The location of
|
||||
# this file may be overridden by setting FILELIST variable:
|
||||
# FILELIST=/etc/my-backup/filelist
|
||||
|
||||
# Name of 'exclude file list'. It is searched under $SYSCONFDIR/tar-backup
|
||||
# on remote machines
|
||||
XLIST=exclude_files
|
||||
|
||||
# Default directory for storing incremental listings on remote
|
||||
# machines is $SYSCONFDIR/tar-backup. It can be overridden using
|
||||
# REMOTEBACKUPDIR variable
|
||||
|
||||
# Default directory for storing backup logs is $SYSCONFDIR/backup/log.
|
||||
# It can also be overridden via LOGPATH variable.
|
||||
|
||||
# Time to sleep between dumps of any two successive filesystems
|
||||
SLEEP_TIME=15
|
||||
|
||||
# Script to be run when it's time to insert a new tape in for the next
|
||||
# volume. Administrators may want to tailor this script for their site.
|
||||
@@ -36,37 +70,6 @@ VOLNO_FILE=/home/gd2/dump/volnofile
|
||||
# probably defined in the manual.
|
||||
#DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind'
|
||||
|
||||
# List of file systems to be dumped.
|
||||
# Actually, any directory may be used, but if it has subdirectories on
|
||||
# other file systems, they are not included.
|
||||
# The host name specifies which host to run tar on.
|
||||
# It should normally be the host that actually has the file system.
|
||||
# If GNU tar is not installed on that machine, then you can specify some
|
||||
# other host which can access the file system through NFS.
|
||||
# Although these are arranged one per line, that is not mandatory.
|
||||
# It does not work to use # for comments within the string.
|
||||
|
||||
BACKUP_DIRS='
|
||||
albert:/fs/fsf
|
||||
sugar-bombs:/fs/gd
|
||||
albert:/fs/gd2
|
||||
churchy:/fs/gd3
|
||||
nutrimat:/fs/gp
|
||||
nutrimat:/fs/gp2
|
||||
albert:/fs/mailer
|
||||
placebo:/archive
|
||||
nutrimat:/fs/dist
|
||||
albert:/
|
||||
albert:/usr
|
||||
nutrimat:/
|
||||
placebo:/
|
||||
ernst:/usr1
|
||||
'
|
||||
|
||||
# List of individual files to be dumped.
|
||||
# These should be accesible from the machine on which the dump is run.
|
||||
BACKUP_FILES=''
|
||||
|
||||
# Message to display on the terminal while waiting for dump time. Usually
|
||||
# this will just be some literal text, preferably something more
|
||||
# entertaining than this. The awk script here saves some redundant
|
||||
@@ -78,5 +81,20 @@ SLEEP_MESSAGE="`awk '
|
||||
\"D O N O T T O U C H T H I S T E R M I N A L !!!!!\"
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
# eof
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2, or (at your option)
|
||||
## any later version.
|
||||
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
## 02111-1307, USA.
|
||||
|
||||
253
scripts/backup.in
Normal file
253
scripts/backup.in
Normal file
@@ -0,0 +1,253 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright 2004, Free Software Foundation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
. ${LIBPATH-@libexecdir@}/backup.sh
|
||||
|
||||
DUMP_LEVEL=0
|
||||
TIME=
|
||||
NOW=`now`
|
||||
|
||||
usage() {
|
||||
cat - <<EOF
|
||||
usage: $PROGNAME [OPTIONS] [WHEN]
|
||||
Options are:
|
||||
|
||||
-l, --level=LEVEL Do backup level LEVEL (default $DUMP_LEVEL).
|
||||
-f, --force Force backup even if today's log file already
|
||||
exists.
|
||||
-v, --verbose[=LEVEL] Set verbosity level. Default 100.
|
||||
-t, --time=TIME Wait till TIME, then do backup.
|
||||
|
||||
Informational options:
|
||||
-h, --help Display this help message.
|
||||
-L, --license Display program license.
|
||||
-V, --version Display program version.
|
||||
|
||||
Optional argument WHEN is for backward compatibility only. It has been
|
||||
superseded by --time option.
|
||||
TIME argument can be one of:
|
||||
|
||||
now -- do backup immediately.
|
||||
HH -- do backup at HH hours.
|
||||
HH:MM -- do backup at HH:MM.
|
||||
|
||||
Send bug reports to @PACKAGE_BUGREPORT@.
|
||||
EOF
|
||||
}
|
||||
|
||||
# For compatibility with previous versions, deduce the backup level
|
||||
# from the command name
|
||||
case "$PROGNAME" in
|
||||
level-[0-9]) DUMP_LEVEL=`expr $PROGNAME : 'level-\([0-9][0-9]*\)'`;;
|
||||
esac
|
||||
|
||||
for opt
|
||||
do
|
||||
if [ -z "$prev" ]; then
|
||||
option=$opt
|
||||
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
|
||||
else
|
||||
option="${prev}=$opt"
|
||||
prev=""
|
||||
optarg=$opt
|
||||
fi
|
||||
case $option in
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
;;
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
--t=*|--ti=*|--tim=*|--time=*)
|
||||
TIME=$optarg
|
||||
;;
|
||||
-t) prev=--t;;
|
||||
-t*) TIME=`expr $option : "-t\(.*\)"`;;
|
||||
--t|--ti|--tim|--time)
|
||||
prev=$option
|
||||
;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "backup (@PACKAGE@ @VERSION@)"
|
||||
exit 0;;
|
||||
-L|--li|--lic|--lice|--licen|--licens|--license)
|
||||
license
|
||||
exit;;
|
||||
-h|--h|--he|--hel|--help)
|
||||
usage
|
||||
exit;;
|
||||
-f|--f|--fo|--for|--forc|--force)
|
||||
FORCE=yes
|
||||
;;
|
||||
*) if [ "x$TIME" != "x" ]; then
|
||||
bailout "Extra argument. Try $PROGNAME --help for more info."
|
||||
else
|
||||
TIME=$option
|
||||
fi;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "x$TIME" = x ]; then
|
||||
bailout "No backup time specified. Try $PROGNAME --help for more info."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
init_backup
|
||||
|
||||
# Maybe sleep until around specified or default hour.
|
||||
wait_time $TIME
|
||||
|
||||
if [ $DUMP_LEVEL -ne 0 ]; then
|
||||
PREV_LEVEL=`expr $DUMP_LEVEL - 1`
|
||||
PREV_DATE=`ls -t ${LOGPATH}/log-*-level-$PREV_LEVEL|
|
||||
head -1|
|
||||
sed "s,${LOGPATH}/log-\(.*\)-level.*,\1,"`
|
||||
if [ "x$PREV_DATE" = x ]; then
|
||||
bailout "Can't determine date of the previous backup"
|
||||
fi
|
||||
message 0 "Backup from $PREV_DATE to $NOW"
|
||||
fi
|
||||
|
||||
# start doing things
|
||||
|
||||
# Make sure the log file did not already exist. Create it.
|
||||
|
||||
if [ "x$FORCE" = "xyes" ]; then
|
||||
rm ${LOGFILE}
|
||||
fi
|
||||
|
||||
if [ -f "${LOGFILE}" ] ; then
|
||||
bailout "Log file ${LOGFILE} already exists."
|
||||
else
|
||||
touch "${LOGFILE}"
|
||||
fi
|
||||
message 1 "Ready for backup."
|
||||
message 10 "TAR invocation: $TAR_PART1"
|
||||
message 20 "Variables:"
|
||||
message 20 "BACKUP_DIRS=$BACKUP_DIRS"
|
||||
message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
|
||||
# The buch of commands below is run in a subshell for which all output is
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
message 1 "preparing tapes"
|
||||
$MT_BEGIN "${TAPE_FILE}"
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
|
||||
set - ${BACKUP_DIRS}
|
||||
while [ $# -ne 0 ] ; do
|
||||
date="`date`"
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
remotehost="`expr \"${1}\" : '\([^/][^/]*\):.*'`"
|
||||
if [ -z "$remotehost" ]; then
|
||||
remotehost=$localhost
|
||||
fi
|
||||
|
||||
echo "Backing up ${1} at ${date}"
|
||||
message 10 "fs=$fs"
|
||||
message 10 "fsname=$fsname"
|
||||
message 10 "remotehost=$remotehost"
|
||||
if [ $DUMP_LEVEL -eq 0 ]; then
|
||||
make_level_log ${remotehost}
|
||||
else
|
||||
echo "Last `prev_level` dump on this filesystem was on $PREV_DATE"
|
||||
remote_run "${remotehost}" cp "`level_log_name ${fsname} $PREV_LEVEL`" "`level_log_name temp`"
|
||||
fi
|
||||
|
||||
${DUMP_BEGIN-:} $DUMP_LEVEL $remotehost $fs $fsname
|
||||
backup_host ${remotehost} \
|
||||
"--listed=`level_log_name temp`" \
|
||||
"--label='`print_level` backup of ${fs} on ${remotehost} at ${NOW}'" \
|
||||
-C ${fs} .
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
flush_level_log ${remotehost} ${fsname}
|
||||
fi
|
||||
${MT_STATUS}
|
||||
${DUMP_END-:} $DUMP_LEVEL $remotehost $fs $fsname
|
||||
echo "sleeping ${SLEEP_TIME} seconds"
|
||||
sleep ${SLEEP_TIME}
|
||||
shift
|
||||
done
|
||||
|
||||
# Dump any individual files requested.
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
message 1 "processing individual files"
|
||||
|
||||
date="`date`"
|
||||
|
||||
if [ $DUMP_LEVEL -eq 0 ]; then
|
||||
make_level_log $localhost
|
||||
else
|
||||
echo "Last `prev_level` dump on this filesystem was on $PREV_DATE"
|
||||
remote_run "${localhost}" cp "`level_log_name MISC $PREV_LEVEL`" "`level_log_name temp`"
|
||||
fi
|
||||
|
||||
echo "Backing up miscellaneous files at ${date}"
|
||||
|
||||
${DUMP_BEGIN-:} $DUMP_LEVEL $localhost MISC MISC
|
||||
backup_host $localhost \
|
||||
"--listed=`level_log_name temp`"\
|
||||
"--label='`print_level` backup of miscellaneous files at ${NOW}'" \
|
||||
${BACKUP_FILES}
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of miscellaneous files failed."
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
flush_level_log $localhost MISC
|
||||
fi
|
||||
${MT_STATUS}
|
||||
${DUMP_END-:} $DUMP_LEVEL $localhost MISC MISC
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
message 1 "final cleanup"
|
||||
|
||||
$MT_REWIND "${TAPE_FILE}"
|
||||
$MT_OFFLINE "${TAPE_FILE}"
|
||||
echo "."
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
|
||||
# EOF
|
||||
342
scripts/backup.sh.in
Normal file
342
scripts/backup.sh.in
Normal file
@@ -0,0 +1,342 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright 2004, Free Software Foundation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
PROGNAME=`basename $0`
|
||||
CONFIGPATH="$SYSCONFDIR/backup"
|
||||
REMOTEBACKUPDIR="$SYSCONFDIR/tar-backup"
|
||||
CONFIGFILE=${CONFIGPATH}/backup-specs
|
||||
DIRLIST=${CONFIGPATH}/dirs
|
||||
FILELIST=${CONFIGPATH}/files
|
||||
LOGPATH=${CONFIGPATH}/log
|
||||
|
||||
# Default functions for running various magnetic tape commands
|
||||
mt_begin() {
|
||||
mt -f "$1" retension
|
||||
}
|
||||
|
||||
mt_rewind() {
|
||||
mt -f "$1" rewind
|
||||
}
|
||||
|
||||
mt_offline() {
|
||||
mt -f "$1" offl
|
||||
}
|
||||
|
||||
mt_status() {
|
||||
mt -f "$1" status
|
||||
}
|
||||
|
||||
# The main configuration file may override any of these variables
|
||||
MT_BEGIN=mt_begin
|
||||
MT_REWIND=mt_rewind
|
||||
MT_OFFLINE=mt_offl
|
||||
MT_STATUS=mt_status
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
# to run longer than 24 hours (as may be the case if someone forgets to put
|
||||
# in the next volume of the tape in adequate time), the backup date won't
|
||||
# appear too misleading.
|
||||
startdate="`date`"
|
||||
here="`pwd`"
|
||||
# Save local hostname
|
||||
localhost="`hostname | sed -e 's/\..*//' | tr A-Z a-z`"
|
||||
|
||||
# Produce a diagnostic output
|
||||
message() {
|
||||
if [ "$VERBOSE" != "" ]; then
|
||||
if [ $VERBOSE -ge $1 ]; then
|
||||
shift
|
||||
echo "$@" >&2
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Bail out and exit.
|
||||
bailout() {
|
||||
echo "$PROGNAME: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Return current date
|
||||
now() {
|
||||
#IF_DATE_FORMAT_OK
|
||||
date +%Y-%m-%d
|
||||
#ELSE_DATE_FORMAT_OK
|
||||
LC_ALL=C date | \
|
||||
sed 's/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
||||
/-[0-9]$/s/\([0-9]\)$/0\1/
|
||||
/Jan/{s/Jan/01/p;q;}
|
||||
/Feb/{s/Feb/02/p;q;}
|
||||
/Mar/{s/Mar/03/p;q;}
|
||||
/Apr/{s/Apr/04/p;q;}
|
||||
/May/{s/May/05/p;q;}
|
||||
/Jun/{s/Jun/06/p;q;}
|
||||
/Jul/{s/Jul/07/p;q;}
|
||||
/Aug/{s/Aug/08/p;q;}
|
||||
/Sep/{s/Sep/09/p;q;}
|
||||
/Oct/{s/Oct/10/p;q;}
|
||||
/Nov/{s/Nov/11/p;q;}
|
||||
/Dec/{s/Dec/12/p;q;}'
|
||||
#ENDIF_DATE_FORMAT_OK
|
||||
}
|
||||
|
||||
# Bail out if we don't have root privileges.
|
||||
test_root() {
|
||||
if [ ! -w ${ROOT_FS-/} ]; then
|
||||
bailout "The backup must be run as root or else some files will fail to be dumped."
|
||||
fi
|
||||
}
|
||||
|
||||
advice() {
|
||||
echo "Directory $1 is not found." >&2
|
||||
cat >&2 <<EOF
|
||||
The following directories and files are needed for the backup to function:
|
||||
|
||||
1. Directory with configuration files and file lists:
|
||||
$CONFIGPATH
|
||||
2. Directory for backup log files
|
||||
$LOGPATH
|
||||
3. Main configuration file
|
||||
$CONFIGFILE
|
||||
|
||||
Please, create these and invoke the script again.
|
||||
EOF
|
||||
}
|
||||
|
||||
init_common() {
|
||||
# Check if the necessary directories exist
|
||||
if [ ! -d $CONFIGPATH ]; then
|
||||
advice $CONFIGPATH
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d $LOGPATH ]; then
|
||||
if mkdir $LOGPATH; then
|
||||
:
|
||||
else
|
||||
advice $LOGPATH
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
||||
if [ ! -r $CONFIGFILE ]; then
|
||||
echo "$PROGNAME: cannot read $CONFIGFILE. Stop." >&2
|
||||
exit 1
|
||||
fi
|
||||
. $CONFIGFILE
|
||||
|
||||
# Environment sanity check
|
||||
|
||||
test_root
|
||||
|
||||
if [ x"${ADMINISTRATOR}" = x ]; then
|
||||
bailout "ADMINISTRATOR not defined"
|
||||
fi
|
||||
|
||||
[ x"$TAR" = x ] && TAR=tar
|
||||
[ x"$SLEEP_TIME" = x ] && SLEEP_TIME=60
|
||||
|
||||
if [ x$VOLNO_FILE = x ]; then
|
||||
bailout "VOLNO_FILE not specified"
|
||||
fi
|
||||
|
||||
if [ -r $DIRLIST ]; then
|
||||
BACKUP_DIRS="$BACKUP_DIRS `cat $DIRLIST`"
|
||||
fi
|
||||
if [ -r $FILELIST ]; then
|
||||
BACKUP_FILES="$BACKUP_FILES `cat $FILELIST`"
|
||||
fi
|
||||
|
||||
if [ \( x"$BACKUP_DIRS" = x \) -a \( x"$BACKUP_FILES" = x \) ]; then
|
||||
bailout "Neither BACKUP_DIRS nor BACKUP_FILES specified"
|
||||
fi
|
||||
if [ "$RSH" = "" ]; then
|
||||
RSH=rsh
|
||||
fi
|
||||
POSIXLY_CORRECT=1
|
||||
export POSIXLY_CORRECT
|
||||
}
|
||||
|
||||
init_backup() {
|
||||
init_common
|
||||
TAR_PART1="${TAR} -c --format=gnu --multi-volume --one-file-system --sparse --volno-file=${VOLNO_FILE}"
|
||||
if [ "x$XLIST" != x ]; then
|
||||
TAR_PART1="${TAR_PART1} \`test -r $REMOTEBACKUPDIR/$XLIST && echo \"--exclude-from $REMOTEBACKUPDIR/$XLIST\"\`"
|
||||
fi
|
||||
if [ "$RSH_COMMAND" != "" ]; then
|
||||
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
|
||||
fi
|
||||
if [ x$BLOCKING != x ]; then
|
||||
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
|
||||
fi
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
# Set logfile name
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-0''
|
||||
# They go in the directory `@sysconfdir@/log'.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="${LOGPATH}/log-`now`-level-${DUMP_LEVEL}"
|
||||
}
|
||||
|
||||
init_restore() {
|
||||
init_common
|
||||
# FIXME: Replace --list with --extract
|
||||
TAR_PART1="${TAR} --extract --multi-volume"
|
||||
if [ "$RSH_COMMAND" != "" ]; then
|
||||
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
|
||||
fi
|
||||
if [ x$BLOCKING != x ]; then
|
||||
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
|
||||
fi
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
LOGFILE="${LOGPATH}/restore-`now`"
|
||||
}
|
||||
|
||||
wait_time() {
|
||||
if [ "${1}" != "now" ]; then
|
||||
if [ "${1}x" != "x" ]; then
|
||||
spec="${1}"
|
||||
else
|
||||
spec="${BACKUP_HOUR}"
|
||||
fi
|
||||
|
||||
pausetime="`date | awk -v spec=\"${spec}\" '
|
||||
BEGIN {
|
||||
split(spec, time, ":")
|
||||
}
|
||||
{
|
||||
split($4, now, ":")
|
||||
diff = 3600 * (time[1] - now[1]) + 60 * (time[2] - now[2]);
|
||||
if (diff < 0)
|
||||
diff += 3600 * 24
|
||||
print diff
|
||||
}'`"
|
||||
clear
|
||||
echo "${SLEEP_MESSAGE}"
|
||||
sleep "${pausetime}"
|
||||
fi
|
||||
}
|
||||
|
||||
level_log_name() {
|
||||
echo "$REMOTEBACKUPDIR/${1}.level-${2-$DUMP_LEVEL}"
|
||||
}
|
||||
|
||||
# Prepare a temporary level logfile
|
||||
# usage: make_level_log HOSTNAME
|
||||
make_level_log() {
|
||||
if [ "z${localhost}" != "z$1" ] ; then
|
||||
$RSH "$1" mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
|
||||
$RSH "$1" rm -f `level_log_name temp`
|
||||
else
|
||||
mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
|
||||
rm -f `level_log_name temp`
|
||||
fi
|
||||
}
|
||||
|
||||
# Rename temporary log
|
||||
# usage: flush_level_log HOSTNAME FSNAME
|
||||
flush_level_log() {
|
||||
message 10 "RENAME: `level_log_name temp` --> `level_log_name $2`"
|
||||
if [ "z${localhost}" != "z$1" ] ; then
|
||||
$RSH "$1" mv -f `level_log_name temp` "`level_log_name $2`"
|
||||
else
|
||||
mv -f `level_log_name temp` "`level_log_name $2`"
|
||||
fi
|
||||
}
|
||||
|
||||
# Return the timestamp of the last backup.
|
||||
# usage: get_dump_time LEVEL
|
||||
get_dump_time() {
|
||||
ls -r ${LOGPATH}/log-*-level-$1 \
|
||||
| head -1 \
|
||||
| sed "s,.*log-\(.*\)-level-$1,\1,"
|
||||
}
|
||||
|
||||
# Do actual backup on a host
|
||||
# usage: backup_host HOSTNAME [TAR_ARGUMENTS]
|
||||
backup_host() {
|
||||
message 10 "ARGS: $@"
|
||||
rhost=$1
|
||||
shift
|
||||
if [ "z${localhost}" != "z$rhost" ] ; then
|
||||
$RSH "$rhost" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" $@
|
||||
else
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
|
||||
message 10 "CMD: $CMD"
|
||||
sh -c "$CMD"
|
||||
message 10 "RC: $?"
|
||||
fi
|
||||
}
|
||||
|
||||
print_level() {
|
||||
if [ ${1-$DUMP_LEVEL} -eq 0 ]; then
|
||||
echo "Full"
|
||||
else
|
||||
echo "Level ${1-$DUMP_LEVEL}"
|
||||
fi
|
||||
}
|
||||
|
||||
prev_level() {
|
||||
print_level `expr $DUMP_LEVEL - 1` | tr A-Z a-z
|
||||
}
|
||||
|
||||
remote_run() {
|
||||
rhost=$1
|
||||
shift
|
||||
message 10 "REMOTE $rhost: $@"
|
||||
if [ "x$rhost" != "x${localhost}" ] ; then
|
||||
$RSH "${rhost}" "$@"
|
||||
else
|
||||
$*
|
||||
fi
|
||||
}
|
||||
|
||||
license() {
|
||||
cat - <<EOF
|
||||
This program is part of GNU tar
|
||||
Copyright 2004, Free Software Foundation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
EOF
|
||||
}
|
||||
9
scripts/dump-remind → scripts/dump-remind.in
Executable file → Normal file
9
scripts/dump-remind → scripts/dump-remind.in
Executable file → Normal file
@@ -13,11 +13,12 @@
|
||||
PATH="/usr/lib:/usr/local/gnubin:${PATH}"
|
||||
export PATH
|
||||
|
||||
# Get definition of TAPE_FILE, VOLNO_FILE, and so on.
|
||||
. /home/gd2/dump/backup-specs
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
. ${LIBPATH-@libexecdir@}/backup.sh
|
||||
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
mt -f "${TAPE_FILE}" offl
|
||||
MT_REWIND
|
||||
MT_OFFLINE
|
||||
|
||||
volno="`cat \"${VOLNO_FILE}\" 2> /dev/null`"
|
||||
if [ $? -ne 0 ]; then
|
||||
200
scripts/level-0
200
scripts/level-0
@@ -1,200 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run this script as root on the machine that has the tape drive, to make a
|
||||
# full (level-0) dump.
|
||||
#
|
||||
# If you give `now' as an argument, the dump is done immediately.
|
||||
# Otherwise, it waits until 1am, or until the hour given as argument.
|
||||
# Specify the hour as a number from 0 to 23.
|
||||
#
|
||||
# You must edit the file `backup-specs' to set the parameters for your site.
|
||||
|
||||
# Useful for backup-specs, in case things have to be done slightly
|
||||
# differently for different dump levels.
|
||||
DUMP_LEVEL=0
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
|
||||
# This is not the most reliable test in the world. The following might be
|
||||
# more predictable:
|
||||
#
|
||||
# whoami="`whoami`"
|
||||
# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
|
||||
# if [ "${euid}" != 0 ]; then ...
|
||||
#
|
||||
if [ ! -w / ]; then
|
||||
echo "The backup must be run as root or else some files will fail to be dumped."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
||||
. ./backup-specs
|
||||
|
||||
# Maybe sleep until around specified or default hour.
|
||||
if [ "${1}" != "now" ]; then
|
||||
if [ "${1}x" != "x" ]; then
|
||||
spec="${1}"
|
||||
else
|
||||
spec="${BACKUP_HOUR}"
|
||||
fi
|
||||
|
||||
pausetime="`date | awk '
|
||||
{
|
||||
hr = substr($4, 1, 2);
|
||||
mn = substr($4, 4, 2);
|
||||
if((hr + 0) < (spec + 0))
|
||||
print 3600 * (spec - hr) - 60 * mn;
|
||||
else
|
||||
print 3600 * (spec + (24 - hr)) - 60 * mn;
|
||||
}' spec=\"${spec}\"`"
|
||||
|
||||
clear
|
||||
echo "${SLEEP_MESSAGE}"
|
||||
sleep "${pausetime}"
|
||||
fi
|
||||
|
||||
# start doing things
|
||||
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
# to run longer than 24 hours (as may be the case if someone forgets to put
|
||||
# in the next volume of the tape in adequate time), the backup date won't
|
||||
# appear too misleading.
|
||||
startdate="`date`"
|
||||
|
||||
here="`pwd`"
|
||||
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-0''
|
||||
# They go in the subdirectory `log' of the current directory.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="log/log-`date | sed -ne '
|
||||
s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
||||
/-[0-9]$/s/\([0-9]\)$/0\1/
|
||||
/Jan/{s/Jan/01/p;q;}
|
||||
/Feb/{s/Feb/02/p;q;}
|
||||
/Mar/{s/Mar/03/p;q;}
|
||||
/Apr/{s/Apr/04/p;q;}
|
||||
/May/{s/May/05/p;q;}
|
||||
/Jun/{s/Jun/06/p;q;}
|
||||
/Jul/{s/Jul/07/p;q;}
|
||||
/Aug/{s/Aug/08/p;q;}
|
||||
/Sep/{s/Sep/09/p;q;}
|
||||
/Oct/{s/Oct/10/p;q;}
|
||||
/Nov/{s/Nov/11/p;q;}
|
||||
/Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
|
||||
|
||||
localhost="`hostname | sed -e 's/\..*//'`"
|
||||
|
||||
TAR_PART1="${TAR} -c --multi-volume --one-file-system --blocking=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
|
||||
# Make sure the log file did not already exist. Create it.
|
||||
|
||||
if [ -f "${LOGFILE}" ] ; then
|
||||
echo "Log file ${LOGFILE} already exists." 1>&2
|
||||
exit 1
|
||||
else
|
||||
touch "${LOGFILE}"
|
||||
fi
|
||||
|
||||
# Most everything below here is run in a subshell for which all output is
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
# Caveat: Some version of `mt' require `-t', not `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
set - ${BACKUP_DIRS}
|
||||
while [ $# -ne 0 ] ; do
|
||||
date="`date`"
|
||||
remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
|
||||
# This filename must be absolute; it is opened on the machine that runs tar.
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
|
||||
TAR_PART3="--label='Full backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
|
||||
|
||||
echo "Backing up ${1} at ${date}"
|
||||
|
||||
# Actually back things up.
|
||||
|
||||
if [ "z${localhost}" != "z${remotehost}" ] ; then
|
||||
rsh "${remotehost}" mkdir /etc/tar-backup > /dev/null 2>&1
|
||||
rsh "${remotehost}" rm -f /etc/tar-backup/temp.level-0
|
||||
rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
|
||||
else
|
||||
mkdir /etc/tar-backup > /dev/null 2>&1
|
||||
rm -f /etc/tar-backup/temp.level-0
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
|
||||
fi
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
if [ "z${localhost}" != "z${remotehost}" ] ; then
|
||||
rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
|
||||
fi
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
sleep 60
|
||||
shift
|
||||
done
|
||||
|
||||
# Dump any individual files requested.
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
date="`date`"
|
||||
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
|
||||
TAR_PART3="--label='Full backup of miscellaneous files at ${date}'"
|
||||
|
||||
mkdir /etc/tar-backup > /dev/null 2>&1
|
||||
rm -f /etc/tar-backup/temp.level-0
|
||||
|
||||
echo "Backing up miscellaneous files at ${date}"
|
||||
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of miscellaneous files failed."
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/misc.level-0
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
# Caveat: some versions of `mt' use `-t' instead of `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
mt -f "${TAPE_FILE}" offl
|
||||
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
|
||||
# eof
|
||||
203
scripts/level-1
203
scripts/level-1
@@ -1,203 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run this script as root on the machine that has the tape drive, to make a
|
||||
# level-1 dump containing all files changed since the last full dump.
|
||||
#
|
||||
# If you give `now' as an argument, the dump is done immediately.
|
||||
# Otherwise, it waits until 1am.
|
||||
#
|
||||
# You must edit the file `backup-specs' to set the parameters for your site.
|
||||
|
||||
# Useful for backup-specs, in case things have to be done slightly
|
||||
# differently for different dump levels.
|
||||
DUMP_LEVEL=1
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
|
||||
# This is not the most reliable test in the world. The following might be
|
||||
# more predictable:
|
||||
#
|
||||
# whoami="`whoami`"
|
||||
# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
|
||||
# if [ "${euid}" != 0 ]; then ...
|
||||
#
|
||||
if [ ! -w / ]; then
|
||||
echo "The backup must be run as root or else some files will fail to be dumped."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
||||
. ./backup-specs
|
||||
|
||||
# Maybe sleep until around specified or default hour.
|
||||
if [ "z${1}" != "znow" ]; then
|
||||
if [ "${1}x" != "x" ]; then
|
||||
spec="${1}"
|
||||
else
|
||||
spec="${BACKUP_HOUR}"
|
||||
fi
|
||||
|
||||
pausetime="`date | awk '
|
||||
{
|
||||
hr = substr($4, 1, 2);
|
||||
mn = substr($4, 4, 2);
|
||||
if((hr + 0) < (spec + 0))
|
||||
print 3600 * (spec - hr) - 60 * mn;
|
||||
else
|
||||
print 3600 * (spec + (24 - hr)) - 60 * mn;
|
||||
}' spec=\"${spec}\"`"
|
||||
|
||||
clear
|
||||
echo "${SLEEP_MESSAGE}"
|
||||
sleep "${pausetime}"
|
||||
fi
|
||||
|
||||
# start doing things
|
||||
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
# to run longer than 24 hours (as may be the case if someone forgets to put
|
||||
# in the next volume of the tape in adequate time), the backup date won't
|
||||
# appear too misleading.
|
||||
startdate="`date`"
|
||||
|
||||
here="`pwd`"
|
||||
|
||||
# Logfile name should be in the form ``log-1993-03-18-level-1''
|
||||
# They go in the subdirectory `log' of the current directory.
|
||||
# i.e. year-month-date. This format is useful for sorting by name, since
|
||||
# logfiles are intentionally kept online for future reference.
|
||||
LOGFILE="log/log-`date | sed -ne '
|
||||
s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
||||
/-[0-9]$/s/\([0-9]\)$/0\1/
|
||||
/Jan/{s/Jan/01/p;q;}
|
||||
/Feb/{s/Feb/02/p;q;}
|
||||
/Mar/{s/Mar/03/p;q;}
|
||||
/Apr/{s/Apr/04/p;q;}
|
||||
/May/{s/May/05/p;q;}
|
||||
/Jun/{s/Jun/06/p;q;}
|
||||
/Jul/{s/Jul/07/p;q;}
|
||||
/Aug/{s/Aug/08/p;q;}
|
||||
/Sep/{s/Sep/09/p;q;}
|
||||
/Oct/{s/Oct/10/p;q;}
|
||||
/Nov/{s/Nov/11/p;q;}
|
||||
/Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
|
||||
|
||||
localhost="`hostname | sed -e 's/\..*//'`"
|
||||
|
||||
TAR_PART1="${TAR} -c --multi-volume --one-file-system --blocking=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
|
||||
|
||||
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
||||
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
||||
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
||||
fi
|
||||
|
||||
# Make sure the log file did not already exist. Create it.
|
||||
|
||||
if [ -f "${LOGFILE}" ] ; then
|
||||
echo "Log file ${LOGFILE} already exists." 1>&2
|
||||
exit 1
|
||||
else
|
||||
touch "${LOGFILE}"
|
||||
fi
|
||||
|
||||
# Most everything below here is run in a subshell for which all output is
|
||||
# piped through `tee' to the logfile. Doing this, instead of having
|
||||
# multiple pipelines all over the place, is cleaner and allows access to
|
||||
# the exit value from various commands more easily.
|
||||
(
|
||||
# Caveat: Some version of `mt' require `-t', not `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
set - ${BACKUP_DIRS}
|
||||
while [ $# -ne 0 ] ; do
|
||||
date="`date`"
|
||||
remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
|
||||
# This filename must be absolute; it is opened on the machine that runs tar.
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
|
||||
TAR_PART3="--label='level 1 backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
|
||||
|
||||
echo "Backing up ${1} at ${date}"
|
||||
echo "Last full dump on this filesystem:"
|
||||
|
||||
if [ "z${remotehost}" != "z${localhost}" ] ; then
|
||||
rsh "${remotehost}" "ls -l /etc/tar-backup/${fsname}.level-0; \
|
||||
cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1"
|
||||
else
|
||||
ls -l "/etc/tar-backup/${fsname}.level-0"
|
||||
cp "/etc/tar-backup/${fsname}.level-0" /etc/tar-backup/temp.level-1
|
||||
fi
|
||||
|
||||
# Actually back things up.
|
||||
|
||||
if [ "z${remotehost}" != "z${localhost}" ] ; then
|
||||
rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
|
||||
else
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
|
||||
fi
|
||||
|
||||
# `rsh' doesn't exit with the exit status of the remote command. What
|
||||
# stupid lossage. TODO: think of a reliable workaround.
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of ${1} failed."
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
if [ "z${localhost}" != "z${remotehost}" ] ; then
|
||||
rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
|
||||
fi
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
sleep 60
|
||||
shift
|
||||
done
|
||||
|
||||
# Dump any individual files requested.
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
date="`date`"
|
||||
TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
|
||||
TAR_PART3="--label='Incremental backup of miscellaneous files at ${date}'"
|
||||
|
||||
echo "Backing up miscellaneous files at ${date}"
|
||||
echo "Last full dump of these files:"
|
||||
ls -l /etc/tar-backup/misc.level-0
|
||||
|
||||
rm -f /etc/tar-backup/temp.level-1
|
||||
cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1
|
||||
|
||||
# Using `sh -c exec' causes nested quoting and shell substitution
|
||||
# to be handled here in the same way rsh handles it.
|
||||
sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
|
||||
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Backup of miscellaneous files failed." 1>&2
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1
|
||||
fi
|
||||
${TAPE_STATUS}
|
||||
else
|
||||
echo "No miscellaneous files specified"
|
||||
fi
|
||||
|
||||
# Caveat: some versions of `mt' use `-t' instead of `-f'.
|
||||
mt -f "${TAPE_FILE}" rewind
|
||||
mt -f "${TAPE_FILE}" offl
|
||||
|
||||
) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
|
||||
# eof
|
||||
224
scripts/restore.in
Normal file
224
scripts/restore.in
Normal file
@@ -0,0 +1,224 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright 2004, Free Software Foundation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
. ${LIBPATH-@libexecdir@}/backup.sh
|
||||
|
||||
usage() {
|
||||
cat - <<EOF
|
||||
usage: $PROGNAME [OPTIONS] [PATTERN [PATTERN...]]
|
||||
Options are:
|
||||
|
||||
-l, --level=LEVEL Start restoring from backup level LEVEL (default $DUMP_LEVEL).
|
||||
-v, --verbose[=LEVEL] Set verbosity level. Default 100.
|
||||
|
||||
Informational options:
|
||||
-h, --help Display this help message.
|
||||
-L, --license Display program license.
|
||||
-V, --version Display program version.
|
||||
|
||||
Send bug reports to @PACKAGE_BUGREPORT@.
|
||||
EOF
|
||||
}
|
||||
|
||||
unset PATTERN
|
||||
DUMP_LEVEL=0
|
||||
CMDLINE="$0 $@"
|
||||
|
||||
for opt
|
||||
do
|
||||
if [ -z "$prev" ]; then
|
||||
option=$opt
|
||||
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
|
||||
else
|
||||
option="${prev}=$opt"
|
||||
prev=""
|
||||
optarg=$opt
|
||||
fi
|
||||
case $option in
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
;;
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "restore (@PACKAGE@ @VERSION@)"
|
||||
exit 0;;
|
||||
-L|--li|--lic|--lice|--licen|--licens|--license)
|
||||
license
|
||||
exit;;
|
||||
-h|--h|--he|--hel|--help)
|
||||
usage
|
||||
exit;;
|
||||
-*) bailout "Unknown option $opt. Try $PROGNAME --help for more info.";;
|
||||
*) if [ -z "$PATTERN" ]; then
|
||||
PATTERN=$opt
|
||||
else
|
||||
PATTERN="$PATTERN|$opt"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
init_restore
|
||||
cat > $LOGFILE <<EOF
|
||||
This file contains any messages produced by $PROGNAME.
|
||||
|
||||
It was created by GNU $PROGNAME, from @PACKAGE@ (@VERSION@).
|
||||
Invocation command line was
|
||||
|
||||
\$ $CMDLINE
|
||||
|
||||
EOF
|
||||
|
||||
restore_fs()
|
||||
{
|
||||
fs="`echo \"${1}\" | sed -e 's/^.*://'`"
|
||||
fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
|
||||
remotehost="`expr \"${1}\" : '\([^/][^/]*\):.*'`"
|
||||
if [ -z "$remotehost" ]; then
|
||||
remotehost=$localhost
|
||||
fi
|
||||
message 10 "fs=$fs"
|
||||
message 10 "fsname=$fsname"
|
||||
message 10 "remotehost=$remotehost"
|
||||
|
||||
LOGPAT="`level_log_name ${fsname} '[0-9]'`"
|
||||
PREFIX="`level_log_name ${fsname} ''`"
|
||||
message 10 LOGPAT=$LOGPAT
|
||||
message 10 PREFIX=$PREFIX
|
||||
LEVELS=`remote_run "${remotehost}" ls $LOGPAT |
|
||||
sed "s,$PREFIX,," | sort -n`
|
||||
message 10 "LEVELS=$LEVELS"
|
||||
|
||||
echo "Starting restore of ${1} at level $DUMP_LEVEL."
|
||||
for level in $LEVELS
|
||||
do
|
||||
if [ $level -lt $DUMP_LEVEL ]; then
|
||||
message 10 "Skipping level $level"
|
||||
continue;
|
||||
fi
|
||||
message 10 "Restoring level $level"
|
||||
|
||||
DATE=`get_dump_time $level`
|
||||
FILE="`level_log_name ${fsname} ${level}`"
|
||||
message 10 "FILE=$FILE"
|
||||
|
||||
LABEL="`print_level $level` backup of ${fs} on ${remotehost} at ${DATE}"
|
||||
${RESTORE_BEGIN-:} $level $remotehost $fs $fsname
|
||||
backup_host ${remotehost} \
|
||||
"--listed=`level_log_name $fs $level`" \
|
||||
"--label=\"$LABEL\"" \
|
||||
-C ${ROOT_FS-/}$fs
|
||||
${RESTORE_END-:} $level $remotehost $fs $fsname
|
||||
done
|
||||
}
|
||||
|
||||
restore_files()
|
||||
{
|
||||
LOGPAT="`level_log_name MISC '[0-9]'`"
|
||||
PREFIX="`level_log_name MISC ''`"
|
||||
message 10 LOGPAT=$LOGPAT
|
||||
message 10 PREFIX=$PREFIX
|
||||
LEVELS=`remote_run "${localhost}" ls $LOGPAT | sed "s,$PREFIX,," | sort -n`
|
||||
message 10 "LEVELS=$LEVELS"
|
||||
|
||||
echo "Starting restore of miscellaneous files at level $DUMP_LEVEL."
|
||||
for level in $LEVELS
|
||||
do
|
||||
if [ $level -lt $DUMP_LEVEL ]; then
|
||||
message 10 "Skipping level $level"
|
||||
continue;
|
||||
fi
|
||||
message 10 "Restoring level $level"
|
||||
|
||||
DATE=`get_dump_time $level`
|
||||
FILE="`level_log_name MISC ${level}`"
|
||||
message 10 "FILE=$FILE"
|
||||
|
||||
LABEL="`print_level $level` backup of miscellaneous files at ${DATE}"
|
||||
${RESTORE_BEGIN-:} $level $localhost MISC MISC
|
||||
backup_host ${localhost} \
|
||||
"--listed=`level_log_name MISC $level`" \
|
||||
"--label=\"$LABEL\"" \
|
||||
-C ${ROOT_FS-/} $@
|
||||
${RESTORE_END-:} $level $localhost MISC MISC
|
||||
done
|
||||
}
|
||||
|
||||
# Operation Overwiew:
|
||||
#
|
||||
# 1. Determine the time of the last backup
|
||||
# 2. Create list of incremental listings to process
|
||||
# 3. For each filesystem:
|
||||
# 3.1. Start at the requested dump level (default 0) and proceed up to
|
||||
# the last available level:
|
||||
# 3.1.1 Deduce the volume label
|
||||
# 3.1.2. Invoke [rsh] tar --listed=FILE --label=LABEL [opts] -xf $TAPE_FILE
|
||||
# 4. End
|
||||
|
||||
(message 1 "Preparing for restore"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
|
||||
for dir in ${BACKUP_DIRS}
|
||||
do
|
||||
message 1 "Processing $dir"
|
||||
case $dir in
|
||||
${PATTERN-*}) restore_fs $dir;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "x${BACKUP_FILES}" != "x" ] ; then
|
||||
message 1 "processing miscellaneous files"
|
||||
if [ -z "$PATTERN" ]; then
|
||||
restore_files
|
||||
else
|
||||
RESTORE_FILES=""
|
||||
for file in ${BACKUP_FILES}
|
||||
do
|
||||
rel_file=`expr $file : '/\(.*\)'`
|
||||
case $file in
|
||||
$PATTERN) if [ -z "$RESTORE_FILES" ]; then
|
||||
RESTORE_FILES="$rel_file"
|
||||
else
|
||||
RESTORE_FILES="$RESTORE_FILES $rel_file"
|
||||
fi;;
|
||||
esac
|
||||
done
|
||||
[ -z "$RESTORE_FILES" ] || restore_files $RESTORE_FILES
|
||||
fi
|
||||
|
||||
fi) 2>&1 | tee -a "${LOGFILE}"
|
||||
|
||||
# EOF
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/sh
|
||||
# start doing things
|
||||
TOBACKUP="albert:/"
|
||||
|
||||
HOST=`hostname | sed 's/\..*//'`
|
||||
TAPEFILE=/dev/rfd0a
|
||||
LOGFILE=tar-out
|
||||
BLOCKING=20
|
||||
TAR_PART1="/usr/local/bin/tar clbfVM $BLOCKING"
|
||||
|
||||
rm -f $LOGFILE
|
||||
|
||||
mt -f $TAPEFILE rewind
|
||||
|
||||
host=`echo $TOBACKUP | sed 's/:.*$//'`;
|
||||
fs=`echo $TOBACKUP | sed 's/^.*://'`;
|
||||
date=`date`;
|
||||
fsname=`echo $TOBACKUP | sed 's/\//:/g'`
|
||||
|
||||
TAR_PART2="'Weekly backup of $fs on $host at $date' -C $fs ."
|
||||
echo Backing up $TOBACKUP at $date | tee -a $LOGFILE
|
||||
|
||||
# Actually back things up.
|
||||
|
||||
if [ $HOST != $host ] ; then
|
||||
rsh $host $TAR_PART1 $HOST:$TAPEFILE $TAR_PART2
|
||||
else
|
||||
sh -c "exec $TAR_PART1 $TAPEFILE $TAR_PART2"
|
||||
fi
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo Backup of $TOBACKUP failed. | tee -a $LOGFILE
|
||||
echo mts at time of failure | tee -a $LOGFILE
|
||||
mts -t $TAPEFILE | tee -a $LOGFILE
|
||||
# I'm assuming that the tar will have written an empty
|
||||
# file to the tape, otherwise I should do a cat here.
|
||||
else
|
||||
echo $date > $fsname.lasttar
|
||||
fi
|
||||
sleep 60;
|
||||
|
||||
mt -f $TAPEFILE rewind
|
||||
mt -f $TAPEFILE offl
|
||||
7
src/.cvsignore
Normal file
7
src/.cvsignore
Normal file
@@ -0,0 +1,7 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
localedir.h
|
||||
rmt
|
||||
tar
|
||||
.deps
|
||||
.gdbinit
|
||||
@@ -1,51 +1,61 @@
|
||||
# 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)"' >$@
|
||||
echo "#ifndef DEFAULT_RMT_COMMAND" >> $@
|
||||
echo "# define DEFAULT_RMT_COMMAND \"$(libexecdir)/`echo \"rmt\" | sed 's,^.*/,,;$(transform)'`$(EXEEXT)\"" >> $@
|
||||
echo "#endif" >> $@
|
||||
|
||||
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
|
||||
rmt.o tar.o : localedir.h
|
||||
|
||||
rmt.o: rmt.c
|
||||
$(COMPILE) -DLOCALEDIR=\"$(localedir)\" -c $(srcdir)/rmt.c
|
||||
LDADD = ../lib/libtar.a $(LIBINTL)
|
||||
|
||||
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)
|
||||
|
||||
855
src/buffer.c
855
src/buffer.c
File diff suppressed because it is too large
Load Diff
609
src/common.h
609
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, 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
|
||||
@@ -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,34 @@ 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>
|
||||
#include <timespec.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 +125,12 @@ 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;
|
||||
|
||||
/* Display file times in UTC */
|
||||
GLOBAL bool utc_option;
|
||||
|
||||
/* This variable tells how to interpret newer_mtime_option, below. If zero,
|
||||
files get archived if their mtime is not less than newer_mtime_option.
|
||||
@@ -132,54 +138,61 @@ 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 */
|
||||
KEEP_NEWER_FILES /* --keep-newer-files */
|
||||
};
|
||||
GLOBAL enum old_files old_files_option;
|
||||
|
||||
/* Specified file name for incremental list. */
|
||||
GLOBAL const char *listed_incremental_option;
|
||||
@@ -187,83 +200,82 @@ 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
|
||||
/* The same variable holds the time, whether mtime or ctime. Just fake a
|
||||
non-existing option, for making the code clearer, elsewhere. */
|
||||
#define newer_ctime_option newer_mtime_option
|
||||
|
||||
/* Specified threshold date and time. Files having 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. */
|
||||
GLOBAL time_t newer_mtime_option;
|
||||
/* Specified threshold date and time. Files having an older time stamp
|
||||
do not get archived (also see after_date_option above). */
|
||||
GLOBAL struct timespec newer_mtime_option;
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int no_recurse_option;
|
||||
/* Return true if newer_mtime_option is initialized. */
|
||||
#define NEWER_OPTION_INITIALIZED(opt) (0 <= (opt).tv_nsec)
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int numeric_owner_option;
|
||||
/* Return true if the struct stat ST's M time is less than
|
||||
newer_mtime_option. */
|
||||
#define OLDER_STAT_TIME(st, m) \
|
||||
((st).st_##m##time < newer_mtime_option.tv_sec \
|
||||
|| ((st).st_##m##time == newer_mtime_option.tv_sec \
|
||||
&& TIMESPEC_NS ((st).st_##m##tim) < newer_mtime_option.tv_nsec))
|
||||
|
||||
/* Boolean value. */
|
||||
GLOBAL int one_file_system_option;
|
||||
/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
|
||||
GLOBAL int recursion_option;
|
||||
|
||||
GLOBAL bool numeric_owner_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 rmt command. */
|
||||
GLOBAL const char *rmt_command_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 +289,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 +308,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 +349,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 *);
|
||||
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 +448,245 @@ 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) __attribute__ ((noreturn));
|
||||
void read_warn_details (char const *, off_t, size_t);
|
||||
void read_diag_details (char const *name, off_t offset, size_t size);
|
||||
void readlink_error (char const *);
|
||||
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 *, size_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 const *, gid_t *);
|
||||
void uid_to_uname (uid_t, char **uname);
|
||||
int uname_to_uid (char const *, 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 (void);
|
||||
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 *));
|
||||
void usage (int);
|
||||
|
||||
int confirm (const char *, const char *);
|
||||
void request_stdin (const char *);
|
||||
|
||||
void tar_stat_init (struct tar_stat_info *st);
|
||||
void tar_stat_destroy (struct tar_stat_info *st);
|
||||
void usage (int) __attribute__ ((noreturn));
|
||||
|
||||
/* Module update.c. */
|
||||
|
||||
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_decode_global (void);
|
||||
void xheader_store (char const *, struct tar_stat_info const *, void *);
|
||||
void xheader_read (union block *, size_t);
|
||||
void xheader_write (char type, char *name, struct xheader *xhdr);
|
||||
void xheader_write_global (void);
|
||||
void xheader_finish (struct xheader *);
|
||||
void xheader_destroy (struct xheader *);
|
||||
char *xheader_xhdr_name (struct tar_stat_info *st);
|
||||
char *xheader_ghdr_name (void);
|
||||
void xheader_write (char, char *, struct xheader *);
|
||||
void xheader_write_global (void);
|
||||
void xheader_set_option (char *string);
|
||||
|
||||
/* Module system.c */
|
||||
|
||||
void sys_stat_nanoseconds (struct tar_stat_info *);
|
||||
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);
|
||||
void sys_reset_uid_gid (void);
|
||||
size_t sys_write_archive_buffer (void);
|
||||
bool sys_get_archive_stat (void);
|
||||
void sys_reset_uid_gid (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 *);
|
||||
bool sparse_member_p (struct tar_stat_info *);
|
||||
bool sparse_fixup_header (struct tar_stat_info *);
|
||||
enum dump_status sparse_dump_file (int, struct tar_stat_info *);
|
||||
enum dump_status sparse_extract_file (int, struct tar_stat_info *, off_t *);
|
||||
enum dump_status sparse_skip_file (struct tar_stat_info *);
|
||||
bool sparse_diff_file (int, struct tar_stat_info *);
|
||||
|
||||
/* Module utf8.c */
|
||||
bool string_ascii_p (const char *str);
|
||||
bool utf8_convert (bool to_utf, char const *input, char **output);
|
||||
|
||||
700
src/compare.c
700
src/compare.c
File diff suppressed because it is too large
Load Diff
1625
src/create.c
1625
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 ();
|
||||
}
|
||||
|
||||
528
src/extract.c
528
src/extract.c
File diff suppressed because it is too large
Load Diff
940
src/incremen.c
940
src/incremen.c
File diff suppressed because it is too large
Load Diff
404
src/list.c
404
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, 2004 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,19 @@ 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)
|
||||
|| (newer_mtime_option != TYPE_MINIMUM (time_t)
|
||||
if (! name_match (current_stat_info.file_name)
|
||||
|| (NEWER_OPTION_INITIALIZED (newer_mtime_option)
|
||||
/* FIXME: We get mtime now, and again later; this causes
|
||||
duplicate diagnostics if header.mtime is bogus. */
|
||||
&& ((current_stat.st_mtime
|
||||
= TIME_FROM_HEADER (current_header->header.mtime))
|
||||
< newer_mtime_option))
|
||||
|| excluded_name (current_file_name))
|
||||
&& ((current_stat_info.stat.st_mtime
|
||||
= TIME_FROM_HEADER (current_header->header.mtime)),
|
||||
#ifdef ST_MTIM_NSEC
|
||||
/* FIXME: Grab fractional time stamps from
|
||||
extended header. */
|
||||
current_stat_info.stat.st_mtim.ST_MTIM_NSEC = 0,
|
||||
#endif
|
||||
OLDER_STAT_TIME (current_stat_info.stat, m)))
|
||||
|| excluded_name (current_stat_info.file_name))
|
||||
{
|
||||
switch (current_header->header.typeflag)
|
||||
{
|
||||
@@ -99,17 +111,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 +135,20 @@ 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)));
|
||||
break;
|
||||
}
|
||||
status = prev_status;
|
||||
if (ignore_zeros_option)
|
||||
continue;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
if (block_number_option)
|
||||
@@ -149,6 +171,15 @@ read_and (void (*do_something) ())
|
||||
|
||||
case HEADER_ZERO_BLOCK:
|
||||
case HEADER_SUCCESS:
|
||||
if (block_number_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
off_t block_ordinal = current_block_ordinal ();
|
||||
block_ordinal -= recent_long_name_blocks;
|
||||
block_ordinal -= recent_long_link_blocks;
|
||||
fprintf (stdlis, _("block %s: "),
|
||||
STRINGIFY_BIGINT (block_ordinal, buf));
|
||||
}
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
break;
|
||||
|
||||
@@ -156,11 +187,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 +207,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 +220,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 +242,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 +256,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 +266,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 +287,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 +296,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,41 +349,73 @@ 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)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
break;
|
||||
}
|
||||
written = available_space_after (data_block);
|
||||
if (written > size)
|
||||
written = size;
|
||||
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 ();
|
||||
|
||||
memcpy (bp, data_block->buffer, written);
|
||||
bp += written;
|
||||
set_next_block_after ((union block *)
|
||||
(data_block->buffer + written - 1));
|
||||
header_copy = xmalloc (size + 1);
|
||||
|
||||
if (header->header.typeflag == GNUTYPE_LONGNAME)
|
||||
{
|
||||
if (next_long_name)
|
||||
free (next_long_name);
|
||||
next_long_name = header_copy;
|
||||
next_long_name_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next_long_link)
|
||||
free (next_long_link);
|
||||
next_long_link = header_copy;
|
||||
next_long_link_blocks = size / BLOCKSIZE;
|
||||
}
|
||||
|
||||
set_next_block_after (header);
|
||||
*header_copy = *header;
|
||||
bp = header_copy->buffer + BLOCKSIZE;
|
||||
|
||||
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 +427,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 +457,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 +504,97 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
stat_info->archive_file_size = stat_info->stat.st_size;
|
||||
xheader_decode (stat_info);
|
||||
|
||||
if (sparse_member_p (stat_info))
|
||||
{
|
||||
sparse_fixup_header (stat_info);
|
||||
stat_info->is_sparse = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert buffer at WHERE0 of size DIGS from external format to
|
||||
@@ -680,7 +793,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 +858,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));
|
||||
}
|
||||
|
||||
@@ -808,11 +921,11 @@ tartime (time_t t)
|
||||
#else
|
||||
/* Use ISO 8610 format. See:
|
||||
http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
|
||||
struct tm *tm = localtime (&t);
|
||||
struct tm *tm = utc_option ? gmtime (&t) : localtime (&t);
|
||||
if (tm)
|
||||
{
|
||||
sprintf (buffer, "%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 +955,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 +970,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 +987,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 +1021,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 +1058,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 +1088,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,20 +1117,15 @@ 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));
|
||||
break;
|
||||
case GNUTYPE_SPARSE:
|
||||
strcpy (size,
|
||||
STRINGIFY_BIGINT
|
||||
(UINTMAX_FROM_HEADER (current_header
|
||||
->oldgnu_header.realsize),
|
||||
uintbuf));
|
||||
STRINGIFY_BIGINT (minor (st->stat.st_rdev), 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->stat.st_size, uintbuf));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1021,16 +1138,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 +1172,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,19 +1257,10 @@ skip_member (void)
|
||||
char save_typeflag = current_header->header.typeflag;
|
||||
set_next_block_after (current_header);
|
||||
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
{
|
||||
union block *exhdr;
|
||||
do
|
||||
{
|
||||
exhdr = find_next_block ();
|
||||
if (!exhdr)
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
set_next_block_after (exhdr);
|
||||
}
|
||||
while (exhdr->sparse_header.isextended);
|
||||
}
|
||||
assign_string (&save_name, current_stat_info.file_name);
|
||||
|
||||
if (save_typeflag != DIRTYPE)
|
||||
skip_file (current_stat.st_size);
|
||||
if (sparse_member_p (¤t_stat_info))
|
||||
sparse_skip_file (¤t_stat_info);
|
||||
else if (save_typeflag != DIRTYPE)
|
||||
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
359
src/names.c
359
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, 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
|
||||
@@ -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 const *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 const *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. */
|
||||
|
||||
@@ -228,7 +227,7 @@ is_pattern (const char *string)
|
||||
/* Set up to gather file names for tar. They can either come from a
|
||||
file or were saved from decoding arguments. */
|
||||
void
|
||||
name_init (int argc, char *const *argv)
|
||||
name_init (void)
|
||||
{
|
||||
name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
|
||||
name_buffer_length = NAME_FIELD_SIZE;
|
||||
@@ -439,11 +438,13 @@ 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;
|
||||
}
|
||||
else if (change_dir)
|
||||
addname (0, change_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -496,7 +497,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 +532,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 +566,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 +576,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 +597,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,9 +632,15 @@ 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;
|
||||
@@ -612,7 +650,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 +739,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);
|
||||
}
|
||||
|
||||
@@ -723,18 +761,18 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
|
||||
size_t allocated_length = (name_length >= NAME_FIELD_SIZE
|
||||
? name_length + NAME_FIELD_SIZE
|
||||
: NAME_FIELD_SIZE);
|
||||
char *name_buffer = xmalloc (allocated_length + 1);
|
||||
char *namebuf = xmalloc (allocated_length + 1);
|
||||
/* FIXME: + 2 above? */
|
||||
char *string;
|
||||
size_t string_length;
|
||||
int change_dir = name->change_dir;
|
||||
|
||||
name->dir_contents = buffer;
|
||||
strcpy (name_buffer, path);
|
||||
if (! ISSLASH (name_buffer[name_length - 1]))
|
||||
strcpy (namebuf, path);
|
||||
if (! ISSLASH (namebuf[name_length - 1]))
|
||||
{
|
||||
name_buffer[name_length++] = '/';
|
||||
name_buffer[name_length] = '\0';
|
||||
namebuf[name_length++] = '/';
|
||||
namebuf[name_length] = '\0';
|
||||
}
|
||||
|
||||
for (string = buffer; *string; string += string_length + 1)
|
||||
@@ -752,15 +790,15 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
|
||||
}
|
||||
while (allocated_length <= name_length + string_length);
|
||||
|
||||
name_buffer = xrealloc (name_buffer, allocated_length + 1);
|
||||
namebuf = xrealloc (namebuf, allocated_length + 1);
|
||||
}
|
||||
strcpy (name_buffer + name_length, string + 1);
|
||||
add_hierarchy_to_namelist (addname (name_buffer, change_dir),
|
||||
strcpy (namebuf + name_length, string + 1);
|
||||
add_hierarchy_to_namelist (addname (namebuf, change_dir),
|
||||
device);
|
||||
}
|
||||
}
|
||||
|
||||
free (name_buffer);
|
||||
free (namebuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,7 +825,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 +835,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 +851,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 +871,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 +895,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 +913,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 +931,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));
|
||||
}
|
||||
}
|
||||
|
||||
81
src/rmt.c
81
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, 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
|
||||
@@ -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>
|
||||
@@ -118,19 +117,19 @@ get_string (char *string)
|
||||
{
|
||||
int counter;
|
||||
|
||||
for (counter = 0; counter < STRING_SIZE; counter++)
|
||||
for (counter = 0; ; counter++)
|
||||
{
|
||||
if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
if (string[counter] == '\n')
|
||||
if (string[counter] == '\n' || counter == STRING_SIZE - 1)
|
||||
break;
|
||||
}
|
||||
string[counter] = '\0';
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -180,11 +179,11 @@ decode_oflag (char const *oflag_string)
|
||||
char *oflag_num_end;
|
||||
int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
|
||||
int symbolic_oflag = 0;
|
||||
|
||||
|
||||
oflag_string = oflag_num_end;
|
||||
while (ISSPACE ((unsigned char) *oflag_string))
|
||||
oflag_string++;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
struct name_value_pair { char const *name; int value; };
|
||||
@@ -248,6 +247,8 @@ static struct option const long_opts[] =
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static void usage (int) __attribute__ ((noreturn));
|
||||
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
@@ -263,7 +264,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);
|
||||
@@ -273,7 +274,7 @@ int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
char command;
|
||||
ssize_t status;
|
||||
size_t status;
|
||||
|
||||
/* FIXME: Localization is meaningless, unless --help and --version are
|
||||
locally used. Localization would be best accomplished by the calling
|
||||
@@ -288,16 +289,14 @@ main (int argc, char *const *argv)
|
||||
{
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
|
||||
|
||||
case 'h':
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
|
||||
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) 2004 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 +316,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 +397,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 +410,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)
|
||||
@@ -424,7 +423,7 @@ top:
|
||||
do
|
||||
*--p = '0' + (int) (count % 10);
|
||||
while ((count /= 10) != 0);
|
||||
|
||||
|
||||
DEBUG1 ("rmtd: A %s\n", p);
|
||||
|
||||
sprintf (reply_buffer, "A%s\n", p);
|
||||
@@ -442,21 +441,21 @@ 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],
|
||||
size - counter);
|
||||
if (status <= 0)
|
||||
if (status == SAFE_READ_ERROR || status == 0)
|
||||
{
|
||||
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);
|
||||
if (status < 0)
|
||||
if (status != size)
|
||||
goto ioerror;
|
||||
goto respond;
|
||||
}
|
||||
@@ -470,11 +469,11 @@ 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)
|
||||
if (status == SAFE_READ_ERROR)
|
||||
goto ioerror;
|
||||
sprintf (reply_buffer, "A%ld\n", (long) status);
|
||||
sprintf (reply_buffer, "A%lu\n", (unsigned long int) status);
|
||||
full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
|
||||
full_write (STDOUT_FILENO, record_buffer, status);
|
||||
goto top;
|
||||
@@ -499,13 +498,13 @@ top:
|
||||
/* Parse count_string, taking care to check for overflow.
|
||||
We can't use standard functions,
|
||||
since off_t might be longer than long. */
|
||||
|
||||
|
||||
for (p = count_string; *p == ' ' || *p == '\t'; p++)
|
||||
continue;
|
||||
|
||||
|
||||
negative = *p == '-';
|
||||
p += negative || *p == '+';
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int digit = *p++ - '0';
|
||||
@@ -518,7 +517,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 +527,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 +561,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:
|
||||
|
||||
18
src/rmt.h
18
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, 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
|
||||
@@ -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);
|
||||
size_t rmt_read__ (int, char *, size_t);
|
||||
size_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'
|
||||
@@ -32,7 +34,7 @@ int rmt_ioctl__ PARAMS ((int, int, char *));
|
||||
|
||||
#define _remdev(Path) \
|
||||
(!force_local_option && (rmt_path__ = strchr (Path, ':')) \
|
||||
&& rmt_path__ > (Path) && ! memchr (Path, rmt_path__ - (Path), '/'))
|
||||
&& rmt_path__ > (Path) && ! memchr (Path, '/', rmt_path__ - (Path)))
|
||||
|
||||
#define _isrmt(Fd) \
|
||||
((Fd) >= __REM_BIAS)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Functions for communicating with a remote tape drive.
|
||||
|
||||
Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 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
|
||||
@@ -33,7 +33,7 @@
|
||||
code, courtesy of Dan Kegel. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "common.h"
|
||||
#include <safe-read.h>
|
||||
#include <full-write.h>
|
||||
|
||||
@@ -88,6 +88,8 @@ static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
|
||||
/* The pipes for sending data to remote tape drives. */
|
||||
static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
|
||||
|
||||
#define RMT_COMMAND (rmt_command_option ? rmt_command_option : "/etc/rmt")
|
||||
|
||||
/* Temporary variable used by macros in rmt.h. */
|
||||
char *rmt_path__;
|
||||
|
||||
@@ -163,8 +165,6 @@ get_status_string (int handle, char *command_buffer)
|
||||
|
||||
if (*cursor == 'E' || *cursor == 'F')
|
||||
{
|
||||
errno = atoi (cursor + 1);
|
||||
|
||||
/* Skip the error message line. */
|
||||
|
||||
/* FIXME: there is better to do than merely ignoring error messages
|
||||
@@ -178,6 +178,8 @@ get_status_string (int handle, char *command_buffer)
|
||||
break;
|
||||
}
|
||||
|
||||
errno = atoi (cursor + 1);
|
||||
|
||||
if (*cursor == 'F')
|
||||
_rmt_shutdown (handle, errno);
|
||||
|
||||
@@ -199,12 +201,19 @@ get_status_string (int handle, char *command_buffer)
|
||||
|
||||
/* Read and return the status from remote tape connection HANDLE. If
|
||||
an error occurred, return -1 and set errno. */
|
||||
static long
|
||||
static long int
|
||||
get_status (int handle)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
const char *status = get_status_string (handle, command_buffer);
|
||||
return status ? atol (status) : -1L;
|
||||
if (status)
|
||||
{
|
||||
long int result = atol (status);
|
||||
if (0 <= result)
|
||||
return result;
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static off_t
|
||||
@@ -226,10 +235,10 @@ get_status_off (int handle)
|
||||
|
||||
for (; *status == ' ' || *status == '\t'; status++)
|
||||
continue;
|
||||
|
||||
|
||||
negative = *status == '-';
|
||||
status += negative || *status == '+';
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int digit = *status++ - '0';
|
||||
@@ -282,7 +291,7 @@ _rmt_rexec (char *host, char *user)
|
||||
if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
|
||||
error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
|
||||
|
||||
result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
|
||||
result = rexec (&host, rexecserv->s_port, user, 0, RMT_COMMAND, 0);
|
||||
if (fclose (stdin) == EOF)
|
||||
error (0, errno, _("stdin"));
|
||||
fdopen (saved_stdin, "r");
|
||||
@@ -482,17 +491,14 @@ 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,
|
||||
"-l", remote_user, "/etc/rmt", (char *) 0);
|
||||
"-l", remote_user, RMT_COMMAND, (char *) 0);
|
||||
else
|
||||
execl (remote_shell, remote_shell_basename, remote_host,
|
||||
"/etc/rmt", (char *) 0);
|
||||
RMT_COMMAND, (char *) 0);
|
||||
|
||||
/* Bad problems if we get here. */
|
||||
|
||||
@@ -536,7 +542,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
|
||||
int
|
||||
rmt_close__ (int handle)
|
||||
{
|
||||
int status;
|
||||
long int status;
|
||||
|
||||
if (do_command (handle, "C\n") == -1)
|
||||
return -1;
|
||||
@@ -547,26 +553,27 @@ rmt_close__ (int handle)
|
||||
}
|
||||
|
||||
/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
|
||||
Return the number of bytes read on success, -1 on error. */
|
||||
ssize_t
|
||||
Return the number of bytes read on success, SAFE_READ_ERROR on error. */
|
||||
size_t
|
||||
rmt_read__ (int handle, char *buffer, size_t length)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
ssize_t status, rlen;
|
||||
size_t status;
|
||||
size_t rlen;
|
||||
size_t counter;
|
||||
|
||||
sprintf (command_buffer, "R%lu\n", (unsigned long) length);
|
||||
if (do_command (handle, command_buffer) == -1
|
||||
|| (status = get_status (handle)) == -1)
|
||||
return -1;
|
||||
|| (status = get_status (handle)) == SAFE_READ_ERROR)
|
||||
return SAFE_READ_ERROR;
|
||||
|
||||
for (counter = 0; counter < status; counter += rlen, buffer += rlen)
|
||||
{
|
||||
rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
|
||||
if (rlen <= 0)
|
||||
if (rlen == SAFE_READ_ERROR || rlen == 0)
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
return SAFE_READ_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,8 +581,8 @@ rmt_read__ (int handle, char *buffer, size_t length)
|
||||
}
|
||||
|
||||
/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
|
||||
Return the number of bytes written on success, -1 on error. */
|
||||
ssize_t
|
||||
Return the number of bytes written. */
|
||||
size_t
|
||||
rmt_write__ (int handle, char *buffer, size_t length)
|
||||
{
|
||||
char command_buffer[COMMAND_BUFFER_SIZE];
|
||||
@@ -584,18 +591,25 @@ rmt_write__ (int handle, char *buffer, size_t length)
|
||||
|
||||
sprintf (command_buffer, "W%lu\n", (unsigned long) length);
|
||||
if (do_command (handle, command_buffer) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
pipe_handler = signal (SIGPIPE, SIG_IGN);
|
||||
written = full_write (WRITE_SIDE (handle), buffer, length);
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
if (written == length)
|
||||
return get_status (handle);
|
||||
{
|
||||
long int r = get_status (handle);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
if (r == length)
|
||||
return length;
|
||||
written = r;
|
||||
}
|
||||
|
||||
/* Write error. */
|
||||
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
return written;
|
||||
}
|
||||
|
||||
/* Perform an imitation lseek operation on remote tape connection
|
||||
@@ -608,6 +622,7 @@ rmt_lseek__ (int handle, off_t offset, int whence)
|
||||
uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
|
||||
char *p = operand_buffer + sizeof operand_buffer;
|
||||
|
||||
*--p = 0;
|
||||
do
|
||||
*--p = '0' + (int) (u % 10);
|
||||
while ((u /= 10) != 0);
|
||||
@@ -650,7 +665,8 @@ rmt_ioctl__ (int handle, int operation, char *argument)
|
||||
? - (uintmax_t) ((struct mtop *) argument)->mt_count
|
||||
: (uintmax_t) ((struct mtop *) argument)->mt_count);
|
||||
char *p = operand_buffer + sizeof operand_buffer;
|
||||
|
||||
|
||||
*--p = 0;
|
||||
do
|
||||
*--p = '0' + (int) (u % 10);
|
||||
while ((u /= 10) != 0);
|
||||
@@ -672,7 +688,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
|
||||
case MTIOCGET:
|
||||
{
|
||||
ssize_t status;
|
||||
ssize_t counter;
|
||||
size_t counter;
|
||||
|
||||
/* Grab the status and read it directly into the structure. This
|
||||
assumes that the status buffer is not padded and that 2 shorts
|
||||
@@ -687,7 +703,7 @@ rmt_ioctl__ (int handle, int operation, char *argument)
|
||||
for (; status > 0; status -= counter, argument += counter)
|
||||
{
|
||||
counter = safe_read (READ_SIDE (handle), argument, status);
|
||||
if (counter <= 0)
|
||||
if (counter == SAFE_READ_ERROR || counter == 0)
|
||||
{
|
||||
_rmt_shutdown (handle, EIO);
|
||||
return -1;
|
||||
|
||||
859
src/sparse.c
Normal file
859
src/sparse.c
Normal file
@@ -0,0 +1,859 @@
|
||||
/* Functions for dealing with sparse files
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
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 (*sparse_member_p) (struct tar_sparse_file *);
|
||||
bool (*dump_header) (struct tar_sparse_file *);
|
||||
bool (*fixup_header) (struct tar_sparse_file *);
|
||||
bool (*decode_header) (struct tar_sparse_file *);
|
||||
bool (*scan_block) (struct tar_sparse_file *, enum sparse_scan_state,
|
||||
void *);
|
||||
bool (*dump_region) (struct tar_sparse_file *, size_t);
|
||||
bool (*extract_region) (struct tar_sparse_file *, size_t);
|
||||
};
|
||||
|
||||
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_member_p (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->sparse_member_p)
|
||||
return file->optab->sparse_member_p (file);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_init (struct tar_sparse_file *file)
|
||||
{
|
||||
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 i)
|
||||
{
|
||||
if (file->optab->dump_region)
|
||||
return file->optab->dump_region (file, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_extract_region (struct tar_sparse_file *file, size_t i)
|
||||
{
|
||||
if (file->optab->extract_region)
|
||||
return file->optab->extract_region (file, i);
|
||||
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 true;
|
||||
}
|
||||
|
||||
static bool
|
||||
tar_sparse_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
if (file->optab->fixup_header)
|
||||
return file->optab->fixup_header (file);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
&& count != SAFE_READ_ERROR)
|
||||
{
|
||||
/* 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 i)
|
||||
{
|
||||
union block *blk;
|
||||
off_t bytes_left = file->stat_info->sparse_map[i].numbytes;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
size_t bufsize = (bytes_left > BLOCKSIZE) ? BLOCKSIZE : bytes_left;
|
||||
size_t bytes_read;
|
||||
|
||||
blk = find_next_block ();
|
||||
memset (blk->buffer, 0, BLOCKSIZE);
|
||||
bytes_read = safe_read (file->fd, blk->buffer, bufsize);
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].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 i)
|
||||
{
|
||||
size_t write_size;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
|
||||
write_size = file->stat_info->sparse_map[i].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 *st)
|
||||
{
|
||||
bool rc;
|
||||
struct tar_sparse_file file;
|
||||
|
||||
file.stat_info = st;
|
||||
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 *st)
|
||||
{
|
||||
return (ST_NBLOCKS (st->stat)
|
||||
< (st->stat.st_size / ST_NBLOCKSIZE
|
||||
+ (st->stat.st_size % ST_NBLOCKSIZE != 0)));
|
||||
}
|
||||
|
||||
bool
|
||||
sparse_member_p (struct tar_stat_info *st)
|
||||
{
|
||||
struct tar_sparse_file file;
|
||||
|
||||
if (!sparse_select_optab (&file))
|
||||
return false;
|
||||
file.stat_info = st;
|
||||
return tar_sparse_member_p (&file);
|
||||
}
|
||||
|
||||
bool
|
||||
sparse_fixup_header (struct tar_stat_info *st)
|
||||
{
|
||||
struct tar_sparse_file file;
|
||||
|
||||
if (!sparse_select_optab (&file))
|
||||
return false;
|
||||
file.stat_info = st;
|
||||
return tar_sparse_fixup_header (&file);
|
||||
}
|
||||
|
||||
enum dump_status
|
||||
sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
size_t i;
|
||||
|
||||
file.stat_info = st;
|
||||
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;
|
||||
}
|
||||
|
||||
enum dump_status
|
||||
sparse_skip_file (struct tar_stat_info *st)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
|
||||
file.stat_info = st;
|
||||
file.fd = -1;
|
||||
|
||||
if (!sparse_select_optab (&file)
|
||||
|| !tar_sparse_init (&file))
|
||||
return dump_status_not_implemented;
|
||||
|
||||
rc = tar_sparse_decode_header (&file);
|
||||
skip_file (file.stat_info->archive_file_size);
|
||||
return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
|
||||
}
|
||||
|
||||
|
||||
static char diff_buffer[BLOCKSIZE];
|
||||
|
||||
static bool
|
||||
check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end)
|
||||
{
|
||||
if (!lseek_or_error (file, beg, SEEK_SET))
|
||||
return false;
|
||||
|
||||
while (beg < end)
|
||||
{
|
||||
size_t bytes_read;
|
||||
size_t rdsize = end - beg;
|
||||
|
||||
if (rdsize > BLOCKSIZE)
|
||||
rdsize = BLOCKSIZE;
|
||||
clear_block (diff_buffer);
|
||||
bytes_read = safe_read (file->fd, diff_buffer, rdsize);
|
||||
if (bytes_read == SAFE_READ_ERROR)
|
||||
{
|
||||
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 i)
|
||||
{
|
||||
size_t size_left;
|
||||
|
||||
if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset,
|
||||
SEEK_SET))
|
||||
return false;
|
||||
size_left = file->stat_info->sparse_map[i].numbytes;
|
||||
while (size_left > 0)
|
||||
{
|
||||
size_t bytes_read;
|
||||
size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left;
|
||||
|
||||
union block *blk = find_next_block ();
|
||||
if (!blk)
|
||||
{
|
||||
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 == SAFE_READ_ERROR)
|
||||
{
|
||||
read_diag_details (file->stat_info->orig_file_name,
|
||||
file->stat_info->sparse_map[i].offset
|
||||
+ file->stat_info->sparse_map[i].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 *st)
|
||||
{
|
||||
bool rc = true;
|
||||
struct tar_sparse_file file;
|
||||
size_t i;
|
||||
off_t offset = 0;
|
||||
|
||||
file.stat_info = st;
|
||||
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
|
||||
};
|
||||
|
||||
static bool
|
||||
oldgnu_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
|
||||
{
|
||||
return current_header->header.typeflag == GNUTYPE_SPARSE;
|
||||
}
|
||||
|
||||
/* Add a sparse item to the sparse file and its obstack */
|
||||
static enum oldgnu_add_status
|
||||
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;
|
||||
}
|
||||
|
||||
static bool
|
||||
oldgnu_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* NOTE! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert old GNU format sparse data to internal representation */
|
||||
static bool
|
||||
oldgnu_get_sparse_info (struct tar_sparse_file *file)
|
||||
{
|
||||
size_t i;
|
||||
union block *h = current_header;
|
||||
int ext_p;
|
||||
static enum oldgnu_add_status rc;
|
||||
|
||||
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_sparse_member_p,
|
||||
oldgnu_dump_header,
|
||||
oldgnu_fixup_header,
|
||||
oldgnu_get_sparse_info,
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
};
|
||||
|
||||
|
||||
/* Star */
|
||||
|
||||
static bool
|
||||
star_sparse_member_p (struct tar_sparse_file *file __attribute__ ((unused)))
|
||||
{
|
||||
return current_header->header.typeflag == GNUTYPE_SPARSE;
|
||||
}
|
||||
|
||||
static bool
|
||||
star_fixup_header (struct tar_sparse_file *file)
|
||||
{
|
||||
/* NOTE! st_size was initialized from the header
|
||||
which actually contains archived size. The following fixes it */
|
||||
file->stat_info->archive_file_size = file->stat_info->stat.st_size;
|
||||
file->stat_info->stat.st_size =
|
||||
OFF_FROM_HEADER (current_header->star_in_header.realsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert STAR format sparse data to internal representation */
|
||||
static bool
|
||||
star_get_sparse_info (struct tar_sparse_file *file)
|
||||
{
|
||||
size_t i;
|
||||
union block *h = current_header;
|
||||
int ext_p;
|
||||
static enum oldgnu_add_status rc;
|
||||
|
||||
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 */
|
||||
star_sparse_member_p,
|
||||
NULL,
|
||||
star_fixup_header,
|
||||
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_sparse_member_p (struct tar_sparse_file *file)
|
||||
{
|
||||
return file->stat_info->archive_file_size != file->stat_info->stat.st_size;
|
||||
}
|
||||
|
||||
static bool
|
||||
pax_dump_header (struct tar_sparse_file *file)
|
||||
{
|
||||
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 struct tar_sparse_optab pax_optab = {
|
||||
NULL, /* No init function */
|
||||
NULL, /* No done function */
|
||||
pax_sparse_member_p,
|
||||
pax_dump_header,
|
||||
NULL, /* No decode_header function */
|
||||
NULL, /* No fixup_header function */
|
||||
NULL, /* No scan_block function */
|
||||
sparse_dump_region,
|
||||
sparse_extract_region,
|
||||
};
|
||||
|
||||
643
src/system.c
Normal file
643
src/system.c
Normal file
@@ -0,0 +1,643 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
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 *st)
|
||||
{
|
||||
#if defined(HAVE_STRUCT_STAT_ST_SPARE1)
|
||||
st->atime_nsec = st->stat.st_spare1 * 1000;
|
||||
st->mtime_nsec = st->stat.st_spare2 * 1000;
|
||||
st->ctime_nsec = st->stat.st_spare3 * 1000;
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
|
||||
st->atime_nsec = st->stat.st_atim.tv_nsec;
|
||||
st->mtime_nsec = st->stat.st_mtim.tv_nsec;
|
||||
st->ctime_nsec = st->stat.st_ctim.tv_nsec;
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
|
||||
st->atime_nsec = st->stat.st_atimespec.tv_nsec;
|
||||
st->mtime_nsec = st->stat.st_mtimespec.tv_nsec;
|
||||
st->ctime_nsec = st->stat.st_ctimespec.tv_nsec;
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
|
||||
st->atime_nsec = st->stat.st_atimensec;
|
||||
st->mtime_nsec = st->stat.st_mtimensec;
|
||||
st->ctime_nsec = st->stat.st_ctimensec;
|
||||
#else
|
||||
st->atime_nsec = st->mtime_nsec = st->ctime_nsec = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MSDOS
|
||||
|
||||
bool
|
||||
sys_get_archive_stat (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
sys_file_is_archive (struct tar_stat_info *p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
sys_save_archive_dev_ino (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_detect_dev_null_output (void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_wait_for_child (pid_t child_pid)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
sys_spawn_shell (void)
|
||||
{
|
||||
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 (void)
|
||||
{
|
||||
}
|
||||
|
||||
size_t
|
||||
sys_write_archive_buffer (void)
|
||||
{
|
||||
return full_write (archive, record_start->buffer, record_size);
|
||||
}
|
||||
|
||||
/* 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 (void)
|
||||
{
|
||||
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 (void)
|
||||
{
|
||||
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 (void)
|
||||
{
|
||||
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 (void)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
if (access_mode == ACCESS_READ
|
||||
&& ! _isrmt (archive)
|
||||
&& (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
|
||||
while ((r = rmtread (archive, record_start->buffer, record_size)) != 0
|
||||
&& r != SAFE_READ_ERROR)
|
||||
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 (void)
|
||||
{
|
||||
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 (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
size_t
|
||||
sys_write_archive_buffer (void)
|
||||
{
|
||||
return rmtwrite (archive, record_start->buffer, record_size);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
size_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 == SAFE_READ_ERROR)
|
||||
read_fatal (use_compress_program_option);
|
||||
if (status == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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 = true;
|
||||
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;
|
||||
size_t status;
|
||||
|
||||
clear_read_error_count ();
|
||||
|
||||
error_loop:
|
||||
status = rmtread (archive, record_start->buffer, record_size);
|
||||
if (status == SAFE_READ_ERROR)
|
||||
{
|
||||
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 */
|
||||
|
||||
431
src/system.h
431
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
|
||||
@@ -392,6 +393,9 @@ extern int errno;
|
||||
# if HAVE_SYS_DEVICE_H
|
||||
# include <sys/device.h>
|
||||
# endif
|
||||
# if HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
# endif
|
||||
# if HAVE_SYS_BUF_H
|
||||
# include <sys/buf.h>
|
||||
# endif
|
||||
@@ -418,75 +422,102 @@ 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>
|
||||
#if defined(HAVE_SYS_TIME_H) && defined(TIME_WITH_SYS_TIME)
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
#if ! HAVE_DECL_TIME
|
||||
time_t time ();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
#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
|
||||
|
||||
166
src/tar.h
166
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,62 @@ 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 */
|
||||
|
||||
bool is_sparse; /* Is the file sparse */
|
||||
|
||||
size_t sparse_map_avail; /* Index to the first unused element in
|
||||
sparse_map array. Zero if the file is
|
||||
not sparse */
|
||||
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. */
|
||||
|
||||
39
src/update.c
39
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,
|
||||
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
|
||||
@@ -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
|
||||
@@ -62,7 +66,7 @@ append_file (char *path)
|
||||
{
|
||||
union block *start = find_next_block ();
|
||||
size_t buffer_size = available_space_after (start);
|
||||
ssize_t status;
|
||||
size_t status;
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
if (bytes_left < buffer_size)
|
||||
@@ -74,11 +78,14 @@ append_file (char *path)
|
||||
}
|
||||
|
||||
status = safe_read (handle, start->buffer, buffer_size);
|
||||
if (status < 0)
|
||||
if (status == SAFE_READ_ERROR)
|
||||
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;
|
||||
|
||||
344
src/utf8.c
Normal file
344
src/utf8.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/* 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
|
||||
|
||||
#ifndef ICONV_CONST
|
||||
# define ICONV_CONST
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBICONV
|
||||
|
||||
struct langtab
|
||||
{
|
||||
char const *lang; /* Language code */
|
||||
char const *terr; /* Territory code */
|
||||
char const *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, NULL, NULL}
|
||||
};
|
||||
|
||||
/* Given the language and (optionally) territory code, return the
|
||||
default character set for that language. See notes above. */
|
||||
|
||||
static char const *
|
||||
charset_lookup (char const *lang, char const *terr)
|
||||
{
|
||||
struct langtab const *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 (void)
|
||||
{
|
||||
const char *charset = NULL;
|
||||
char *tmp;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#else /* !defined HAVE_LIBICONV */
|
||||
|
||||
# undef iconv_open
|
||||
# define iconv_open(tocode, fromcode) ((iconv_t) -1)
|
||||
|
||||
# undef iconv
|
||||
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) ((size_t) 0)
|
||||
|
||||
# undef iconv_close
|
||||
# define iconv_close(cd) 0
|
||||
|
||||
#endif /* !defined 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 const *input, char **output)
|
||||
{
|
||||
char ICONV_CONST *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 = (char ICONV_CONST *) 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;
|
||||
}
|
||||
1060
src/xheader.c
Normal file
1060
src/xheader.c
Normal file
File diff suppressed because it is too large
Load Diff
9
tests/.cvsignore
Normal file
9
tests/.cvsignore
Normal file
@@ -0,0 +1,9 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
preset
|
||||
.deps
|
||||
genfile
|
||||
mksparse
|
||||
tmp-*
|
||||
directory
|
||||
archive
|
||||
@@ -1,41 +1,71 @@
|
||||
# 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\
|
||||
longv7.sh\
|
||||
multiv01.sh\
|
||||
multiv02.sh\
|
||||
old.sh\
|
||||
options.sh\
|
||||
same-order01.sh\
|
||||
same-order02.sh\
|
||||
volume.sh\
|
||||
recurse.sh\
|
||||
sparse01.sh\
|
||||
star/gtarfail.sh\
|
||||
star/gtarfail2.sh\
|
||||
star/multi-fail.sh\
|
||||
star/ustar-big-2g.sh\
|
||||
star/ustar-big-8g.sh\
|
||||
star/pax-big-10g.sh\
|
||||
star/qucktest.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) star/README
|
||||
|
||||
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
|
||||
|
||||
50
tests/after
50
tests/after
@@ -1,9 +1,55 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Do common operations after a particular test.
|
||||
|
||||
# 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.
|
||||
|
||||
cd ..
|
||||
exec 1> /dev/null
|
||||
exec 2> /dev/null
|
||||
echo $echo_n "$out$echo_c" | cmp -s - tmp-$$/stdout || exit 1
|
||||
echo $echo_n "$err$echo_c" | cmp -s - tmp-$$/stderr || exit 1
|
||||
|
||||
compare() {
|
||||
eval tempfile=tmp-$$/std${1}
|
||||
eval echo \""\${$1}"\" | sed '$d' > ${tempfile}0
|
||||
|
||||
sedscript=tmp-$$/${1}.sed
|
||||
if eval test \".\${${1}_ignore}\" = .; then
|
||||
:
|
||||
else
|
||||
eval echo \"\${${1}_ignore}\" | sed 's,^.*$,/&/d,;' > $sedscript
|
||||
sed -f $sedscript ${tempfile} > ${tempfile}.1
|
||||
mv ${tempfile}.1 ${tempfile}
|
||||
fi
|
||||
|
||||
if eval test -z \"\${${1}_regex}\" ; then
|
||||
cmp -s ${tempfile}0 ${tempfile} || exit 1
|
||||
else
|
||||
awk '{print NR " " $0}' ${tempfile}0 > ${tempfile}.1
|
||||
awk '{print NR " " $0}' ${tempfile} | join ${tempfile}.1 - |
|
||||
while read NUM RE LINE
|
||||
do
|
||||
echo "$LINE" | grep -- "$RE" >/dev/null || exit 1
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
compare out
|
||||
compare err
|
||||
|
||||
rm -rf tmp-$$
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Append was just not working.
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
48
tests/before
48
tests/before
@@ -1,19 +1,53 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Do common operations before a particular test.
|
||||
|
||||
# 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.
|
||||
|
||||
case $# in
|
||||
0) TAR_ARCHIVE_FORMATS="${TAR_ARCHIVE_FORMATS:-v7 oldgnu ustar posix gnu}"
|
||||
for format in $TAR_ARCHIVE_FORMATS
|
||||
do
|
||||
$0 $format
|
||||
R=$?
|
||||
test $R -eq 0 || exit $R
|
||||
done
|
||||
exit 0;;
|
||||
1) if test "x$1" = xauto; then
|
||||
TAR_OPTIONS=
|
||||
else
|
||||
TAR_OPTIONS="--format=$1"
|
||||
fi;;
|
||||
*) echo "Too many arguments" >&2
|
||||
exit 2;;
|
||||
esac
|
||||
|
||||
mkdir tmp-$$
|
||||
cd tmp-$$
|
||||
|
||||
case $srcdir in
|
||||
/*|~*) ;;
|
||||
*) srcdir=../$srcdir ;;
|
||||
esac
|
||||
|
||||
out=
|
||||
err=
|
||||
|
||||
echo $0 > checking
|
||||
export TAR_OPTIONS
|
||||
#echo "$0 $1"
|
||||
echo "$0 $1" > checking
|
||||
exec 1> stdout
|
||||
exec 2> stderr
|
||||
|
||||
PATH=..:../../src:$PATH
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Deleting a member after a big one was destroying the archive.
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Deleting a member with the archive from stdin was not working correctly.
|
||||
|
||||
# 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
|
||||
|
||||
@@ -12,7 +31,7 @@ tar cf archive 1 2 3
|
||||
tar tf archive
|
||||
cat archive | tar f - --delete 2 > archive2
|
||||
echo -----
|
||||
tar tf archive
|
||||
tar tf archive2
|
||||
|
||||
out="\
|
||||
1
|
||||
|
||||
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
|
||||
TAR_ARCHIVE_FORMATS="gnu oldgnu posix"
|
||||
. $srcdir/before
|
||||
|
||||
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
|
||||
53
tests/delete04.sh
Executable file
53
tests/delete04.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Deleting a large last member was destroying earlier members.
|
||||
|
||||
# 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
|
||||
|
||||
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,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# There was a diagnostic when directory already exists.
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Could not extract symlinks over an existing file.
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
@@ -1,14 +1,33 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Paths going up and down were inducing extraction loops.
|
||||
|
||||
# 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
|
||||
|
||||
set -e
|
||||
mkdir directory
|
||||
tar cfv archive directory/../directory
|
||||
tar -cPvf archive directory/../directory
|
||||
echo -----
|
||||
tar xfv archive
|
||||
tar -xPvf archive
|
||||
|
||||
out="\
|
||||
directory/../directory/
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Check for fnmatch problems in glibc 2.1.95.
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
@@ -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, 2004 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,13 +51,11 @@ static int show_version = 0;
|
||||
static int file_length = 0;
|
||||
|
||||
/* Pattern to generate. */
|
||||
static enum pattern pattern = DEFAULT;
|
||||
static enum pattern pattern = DEFAULT_PATTERN;
|
||||
|
||||
/*-----------------------------------------------.
|
||||
| Explain how to use the program, then get out. |
|
||||
`-----------------------------------------------*/
|
||||
|
||||
void
|
||||
/* Explain how to use the program, then get out. */
|
||||
static void usage (int) __attribute__ ((noreturn));
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
@@ -78,10 +80,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 +93,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 +122,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 +132,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 +156,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;
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
#! /bin/sh
|
||||
|
||||
# tar should detect that its gzip child failed.
|
||||
|
||||
# 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
|
||||
TAR_ARCHIVE_FORMATS=auto
|
||||
. $srcdir/before
|
||||
|
||||
tar xfvz /dev/null
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Unreadable directories yielded error despite --ignore-failed-read.
|
||||
|
||||
# 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
|
||||
|
||||
> check-uid
|
||||
set - x`ls -l check-uid`
|
||||
if test $3 = root; then
|
||||
uid_name="$3"
|
||||
set - x`ls -ln check-uid`
|
||||
uid_number="$3"
|
||||
if test "$uid_name" = root || test "$uid_number" = 0; then
|
||||
|
||||
# The test is meaningless for super-user.
|
||||
rm check-uid
|
||||
@@ -47,15 +69,15 @@ else
|
||||
|
||||
err="\
|
||||
-----
|
||||
tar: Cannot add file file: Permission denied
|
||||
tar: file: Cannot open: Permission denied
|
||||
tar: Error exit delayed from previous errors
|
||||
-----
|
||||
tar: Cannot add file file: Permission denied
|
||||
tar: file: Warning: Cannot open: Permission denied
|
||||
-----
|
||||
tar: Cannot add directory directory: Permission denied
|
||||
tar: directory: Cannot savedir: Permission denied
|
||||
tar: Error exit delayed from previous errors
|
||||
-----
|
||||
tar: Cannot add directory directory: Permission denied
|
||||
tar: directory: Warning: Cannot savedir: Permission denied
|
||||
"
|
||||
|
||||
fi
|
||||
|
||||
@@ -1,18 +1,52 @@
|
||||
#! /bin/sh
|
||||
|
||||
# A directory older than the listed entry was skipped completely.
|
||||
|
||||
# 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
|
||||
TAR_ARCHIVE_FORMATS="gnu oldgnu"
|
||||
. $srcdir/before
|
||||
|
||||
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
|
||||
TAR_ARCHIVE_FORMATS="gnu oldgnu"
|
||||
. $srcdir/before
|
||||
|
||||
mkdir directory
|
||||
genfile --length 10240 --pattern zeros > directory/file1
|
||||
# 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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user