Compare commits
778 Commits
release_1_
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2737e1aec0 | ||
|
|
ca02de4050 | ||
|
|
ea7cfcba77 | ||
|
|
bdc442bd5c | ||
|
|
5402831d62 | ||
|
|
4e742fc867 | ||
|
|
076818f8d9 | ||
|
|
c11084bcc2 | ||
|
|
75735940f1 | ||
|
|
8921131877 | ||
|
|
aecf7146d3 | ||
|
|
1ad538b359 | ||
|
|
7d96e820a5 | ||
|
|
7c4f8fb579 | ||
|
|
4303066730 | ||
|
|
9324b472b0 | ||
|
|
b009124ffd | ||
|
|
827dde1605 | ||
|
|
65228e9ba9 | ||
|
|
e36d3354c7 | ||
|
|
d175e21b7f | ||
|
|
c0fce47363 | ||
|
|
807e340ab2 | ||
|
|
6131dd2805 | ||
|
|
bfc3346394 | ||
|
|
b5f4948ce4 | ||
|
|
cd1f6624f7 | ||
|
|
55ecb28315 | ||
|
|
31d84e2f67 | ||
|
|
2e41cdce6d | ||
|
|
ff9d7ec77b | ||
|
|
4a9a4c16e1 | ||
|
|
0aa991f386 | ||
|
|
53f7e6aa62 | ||
|
|
c3f93039ca | ||
|
|
d2b6b7b0a7 | ||
|
|
9bbcac1cf7 | ||
|
|
ac06d4d104 | ||
|
|
a855a80d06 | ||
|
|
b5bf1ccd18 | ||
|
|
a6cf78b0fa | ||
|
|
568919d77b | ||
|
|
c500103600 | ||
|
|
5c47fcf187 | ||
|
|
005f2916b6 | ||
|
|
15d35a0f61 | ||
|
|
04b4f491a8 | ||
|
|
e531f8c66c | ||
|
|
f4ac66226a | ||
|
|
6993486ed8 | ||
|
|
04c1b85872 | ||
|
|
ef95115f61 | ||
|
|
41143ee46f | ||
|
|
f96aff3ce9 | ||
|
|
53a3691092 | ||
|
|
91ad4ea343 | ||
|
|
7eb4dbaff1 | ||
|
|
112ead7931 | ||
|
|
fd401e1d29 | ||
|
|
f8a679e942 | ||
|
|
3b0d006830 | ||
|
|
6e873de727 | ||
|
|
bde3e8d663 | ||
|
|
967f5f52f7 | ||
|
|
5a41310e57 | ||
|
|
3357683933 | ||
|
|
a337cd35a0 | ||
|
|
5a7185ae31 | ||
|
|
0aa69501d3 | ||
|
|
2339c9106b | ||
|
|
a3ba452f40 | ||
|
|
d9da938963 | ||
|
|
989842ff0d | ||
|
|
6f5718a35f | ||
|
|
d68c37b640 | ||
|
|
c0ef66da92 | ||
|
|
c2ce0b7e13 | ||
|
|
7b278044a7 | ||
|
|
025f19e6bd | ||
|
|
c61a2bee73 | ||
|
|
08a9174444 | ||
|
|
e0f9b0fdea | ||
|
|
17ad155fb2 | ||
|
|
303ac16ec0 | ||
|
|
6df7a72434 | ||
|
|
23582f3445 | ||
|
|
317e4d6a3c | ||
|
|
5f4a4164b7 | ||
|
|
7c0feaefd0 | ||
|
|
e513950080 | ||
|
|
2ce5791124 | ||
|
|
d127dac10e | ||
|
|
61a978f6d4 | ||
|
|
fae968bd2d | ||
|
|
9afbe6961c | ||
|
|
5704e5795a | ||
|
|
b73127edc4 | ||
|
|
dd71d3796d | ||
|
|
f73c927a71 | ||
|
|
04b92eca49 | ||
|
|
5a00343006 | ||
|
|
739483114d | ||
|
|
849f244a0b | ||
|
|
15dc3210cc | ||
|
|
7abf1420c3 | ||
|
|
0b60228081 | ||
|
|
f9ed22de9b | ||
|
|
78dd7bf0bc | ||
|
|
647cafff96 | ||
|
|
bd06b114d9 | ||
|
|
8767b1c84a | ||
|
|
e59d09db7d | ||
|
|
dd1bae32ce | ||
|
|
8b3073e1d2 | ||
|
|
7c4f884747 | ||
|
|
82ef07c9bd | ||
|
|
350cc4077e | ||
|
|
7f557428a4 | ||
|
|
dd0f95965d | ||
|
|
cdcd1580c8 | ||
|
|
dfb1da7253 | ||
|
|
79cb9aaab6 | ||
|
|
da109fae7a | ||
|
|
cc1352699a | ||
|
|
4323e98683 | ||
|
|
005e345c04 | ||
|
|
95a5f043c5 | ||
|
|
f25dd56e83 | ||
|
|
f1e4947992 | ||
|
|
0dfcfa4aa4 | ||
|
|
e9c16628f0 | ||
|
|
a0a1243c69 | ||
|
|
812a49419a | ||
|
|
541f3bc374 | ||
|
|
6bc4c4bf96 | ||
|
|
ab7a14bd92 | ||
|
|
b596676c78 | ||
|
|
15c6010c32 | ||
|
|
43231ae554 | ||
|
|
b201a37421 | ||
|
|
c9a3abcbe7 | ||
|
|
18dadeffc0 | ||
|
|
1521d3dae0 | ||
|
|
5ab90d6c96 | ||
|
|
e137c14285 | ||
|
|
95ebde4303 | ||
|
|
ef290cb171 | ||
|
|
09aec02e32 | ||
|
|
9b69d17e24 | ||
|
|
b3992e4ef8 | ||
|
|
88c2aa1616 | ||
|
|
d1e72a536f | ||
|
|
3ffe2eb073 | ||
|
|
eb9bb9bf80 | ||
|
|
4642cd04ed | ||
|
|
a80f364662 | ||
|
|
5316938142 | ||
|
|
83926613a4 | ||
|
|
9a2344b183 | ||
|
|
5182462cf1 | ||
|
|
0ab451a420 | ||
|
|
dab2830e38 | ||
|
|
9cef4d5495 | ||
|
|
7cda31b1e0 | ||
|
|
cc691f8272 | ||
|
|
390950282d | ||
|
|
f13f2d6815 | ||
|
|
c26c2ea2e9 | ||
|
|
51c841b927 | ||
|
|
aca308a778 | ||
|
|
414f635d8b | ||
|
|
281e03ec6c | ||
|
|
9cb1293628 | ||
|
|
44196e198f | ||
|
|
ba332e36d0 | ||
|
|
61656ef35b | ||
|
|
fbc60c2334 | ||
|
|
a78af4b95e | ||
|
|
c26111742a | ||
|
|
6c91bd82e1 | ||
|
|
aae99e863d | ||
|
|
39d315e8ea | ||
|
|
bf195d4ae4 | ||
|
|
a9372cf08a | ||
|
|
be1aa32c6d | ||
|
|
8a3fc52972 | ||
|
|
927d67855e | ||
|
|
c6a5af16ba | ||
|
|
dcc90722ac | ||
|
|
7557fdd4df | ||
|
|
91ee466c8a | ||
|
|
7079fc369b | ||
|
|
b26e798a0f | ||
|
|
f22b9fe3ce | ||
|
|
8f094605a8 | ||
|
|
26d1e4ddbc | ||
|
|
ec35690e91 | ||
|
|
3fa1fd0751 | ||
|
|
fd33f25989 | ||
|
|
45a86d45b2 | ||
|
|
afd073399a | ||
|
|
9f1c32c18b | ||
|
|
4e0deb7416 | ||
|
|
3d2c735b7c | ||
|
|
bd066ac0a5 | ||
|
|
b96cabb1ea | ||
|
|
42d1143dd5 | ||
|
|
2b9e2cc947 | ||
|
|
1752231f9e | ||
|
|
5f2cda027d | ||
|
|
1e6ce98e3a | ||
|
|
883f2e6dca | ||
|
|
628c49250a | ||
|
|
21318f3856 | ||
|
|
fac2b4c11a | ||
|
|
6ba24c31c6 | ||
|
|
7b65ae35ab | ||
|
|
f622c07108 | ||
|
|
d763055edd | ||
|
|
b4d1fa77b6 | ||
|
|
66eaa2f821 | ||
|
|
24a2fcfd83 | ||
|
|
835b0c7dee | ||
|
|
c6f0ad5117 | ||
|
|
f0098df0b3 | ||
|
|
3a27df1d69 | ||
|
|
c1e277476c | ||
|
|
783321ff1b | ||
|
|
01f986b921 | ||
|
|
05fcfaafb6 | ||
|
|
e35fe3a77c | ||
|
|
78d4ccd755 | ||
|
|
9599d193b8 | ||
|
|
e1bba5e7dd | ||
|
|
f2613580c7 | ||
|
|
1cdad4cc28 | ||
|
|
ecdef6677b | ||
|
|
5114218025 | ||
|
|
a9a8990fb3 | ||
|
|
12b58a69aa | ||
|
|
a5afb36765 | ||
|
|
bfee1d44a3 | ||
|
|
8131ca7b26 | ||
|
|
d437ecf75d | ||
|
|
8e5483577d | ||
|
|
9a30bb2674 | ||
|
|
eb30aa7801 | ||
|
|
68636f0bcb | ||
|
|
8ed95e92ef | ||
|
|
d1ca333391 | ||
|
|
71530f72d2 | ||
|
|
18f90676e4 | ||
|
|
7687bf4acc | ||
|
|
39849e9d91 | ||
|
|
8632df398b | ||
|
|
e545d446df | ||
|
|
e7a5e12445 | ||
|
|
31f68bbe2a | ||
|
|
10954cf163 | ||
|
|
b3a71dbdb9 | ||
|
|
cf16a23945 | ||
|
|
d6a60bba76 | ||
|
|
2ccd643d01 | ||
|
|
fdff045d4b | ||
|
|
90cceec4bb | ||
|
|
826c5eb64e | ||
|
|
2096772fbe | ||
|
|
c542d3d0c8 | ||
|
|
4c7a3798d8 | ||
|
|
5d6736e394 | ||
|
|
9ee30c9804 | ||
|
|
4695adfd59 | ||
|
|
a484178a18 | ||
|
|
e39b93d822 | ||
|
|
8ccfc4e416 | ||
|
|
e7987b72c6 | ||
|
|
06805b9281 | ||
|
|
5461025569 | ||
|
|
3f2b847ddd | ||
|
|
6af0596726 | ||
|
|
204b414d11 | ||
|
|
6a1581240b | ||
|
|
4f814e0e4c | ||
|
|
4177c98bcc | ||
|
|
5e8a915b16 | ||
|
|
edf38d13a4 | ||
|
|
3da78400ea | ||
|
|
02402920f8 | ||
|
|
021845e54d | ||
|
|
0f289d7238 | ||
|
|
71d1619abd | ||
|
|
719d3b44b7 | ||
|
|
a65f01ac35 | ||
|
|
2cde05fa10 | ||
|
|
e89c7a45eb | ||
|
|
24c8306965 | ||
|
|
ba26ec86e2 | ||
|
|
de64229632 | ||
|
|
17debecd73 | ||
|
|
02f9af1b8d | ||
|
|
87f9e42108 | ||
|
|
0f0722df45 | ||
|
|
7324326b1d | ||
|
|
705bb09317 | ||
|
|
4ba281eca3 | ||
|
|
bc277c7069 | ||
|
|
f8e14746d2 | ||
|
|
35d9845d5d | ||
|
|
0b74885e81 | ||
|
|
258d1c44e5 | ||
|
|
e49537dcdf | ||
|
|
66be5a789e | ||
|
|
badd509078 | ||
|
|
4e9e55fbf9 | ||
|
|
fffc6149fd | ||
|
|
8ed180b03c | ||
|
|
131ceea7a5 | ||
|
|
4986147986 | ||
|
|
e5aac38c80 | ||
|
|
5c4f8cadbd | ||
|
|
496cf61638 | ||
|
|
d935dc7d1c | ||
|
|
9f0e54ab2f | ||
|
|
c7b69f05bc | ||
|
|
4eb9d052b2 | ||
|
|
5209d1dfe0 | ||
|
|
b2ed3caefe | ||
|
|
79d1ac38c1 | ||
|
|
79a442d7b0 | ||
|
|
7a37621e5b | ||
|
|
c1027eb5ae | ||
|
|
bc7e758b27 | ||
|
|
de72aa0cd6 | ||
|
|
eeda008a59 | ||
|
|
5c713540e3 | ||
|
|
88ccec5d6c | ||
|
|
399c08b3bf | ||
|
|
7f8fe36040 | ||
|
|
b846956c60 | ||
|
|
ac119c80e4 | ||
|
|
d43adc97d6 | ||
|
|
1f73735ba0 | ||
|
|
39cd8c6586 | ||
|
|
84a08f530d | ||
|
|
c366383852 | ||
|
|
738de9ecde | ||
|
|
771ca7b686 | ||
|
|
8184adddab | ||
|
|
7868054c03 | ||
|
|
4f3824743f | ||
|
|
c5b86d7672 | ||
|
|
c0bf6a723b | ||
|
|
b44c612f5d | ||
|
|
066f7729e0 | ||
|
|
7958eb97e6 | ||
|
|
66262c10d1 | ||
|
|
a339f05cd2 | ||
|
|
cc8f5f78b2 | ||
|
|
193eb8f81d | ||
|
|
93082d6eb8 | ||
|
|
e5bc23efcc | ||
|
|
12d67f44de | ||
|
|
3730dddb3f | ||
|
|
8e82f367d4 | ||
|
|
66b59fccb1 | ||
|
|
91c031678d | ||
|
|
5227d66b3c | ||
|
|
f51461d8be | ||
|
|
6efa8de409 | ||
|
|
c67d223854 | ||
|
|
55f2a0772e | ||
|
|
daf634c44e | ||
|
|
5f8f129415 | ||
|
|
dc101747e8 | ||
|
|
7fb1b6877f | ||
|
|
f4e2411bf5 | ||
|
|
ace146f6a4 | ||
|
|
df6de51574 | ||
|
|
8378991cba | ||
|
|
fa6d317bc7 | ||
|
|
beeb19f927 | ||
|
|
553210d5ad | ||
|
|
ee2ec5ff19 | ||
|
|
d9d4435692 | ||
|
|
2251317e3f | ||
|
|
972bebf07e | ||
|
|
8e2898ab11 | ||
|
|
0b43ea2906 | ||
|
|
e4d1edadef | ||
|
|
0836a51147 | ||
|
|
afa743ac23 | ||
|
|
01dd89c121 | ||
|
|
1263f9bc1d | ||
|
|
1ff0b63f48 | ||
|
|
34d15af170 | ||
|
|
63712973c7 | ||
|
|
d9ec6f04e2 | ||
|
|
b5418cd393 | ||
|
|
615732a804 | ||
|
|
dd1a6bd37a | ||
|
|
41654f91f0 | ||
|
|
8d90723d30 | ||
|
|
14d8fc718f | ||
|
|
883cc555df | ||
|
|
e1005b385d | ||
|
|
14f00a2c7a | ||
|
|
f122fc94a7 | ||
|
|
b31afe7cf0 | ||
|
|
ea6f84dd40 | ||
|
|
2d3396c3ea | ||
|
|
d70b8b3b39 | ||
|
|
c445d99d4f | ||
|
|
2c9730357f | ||
|
|
ef0f882382 | ||
|
|
66162927eb | ||
|
|
44cfdfb8b6 | ||
|
|
97d8951536 | ||
|
|
bf5d66109c | ||
|
|
bd1b0fc97c | ||
|
|
a7289daf5c | ||
|
|
72506bddee | ||
|
|
a311b908c0 | ||
|
|
cb07844454 | ||
|
|
2f5a57be4b | ||
|
|
3da8c2850d | ||
|
|
c697d62598 | ||
|
|
b0930da045 | ||
|
|
f86722c34c | ||
|
|
aa0684ce90 | ||
|
|
85c005ee13 | ||
|
|
2684c88a49 | ||
|
|
1ed62596cf | ||
|
|
9d1993f651 | ||
|
|
e7cd377f78 | ||
|
|
c15c42ccd1 | ||
|
|
3c2a2cd94d | ||
|
|
ea3aea06f1 | ||
|
|
983a82a376 | ||
|
|
916fe62ae9 | ||
|
|
99d415e190 | ||
|
|
c7c59b57fa | ||
|
|
eae48289c0 | ||
|
|
62c0c3a780 | ||
|
|
ba472050da | ||
|
|
f6e2860e8a | ||
|
|
2777a2bfd9 | ||
|
|
9fc1cb40f9 | ||
|
|
6238296458 | ||
|
|
9042dfc4b1 | ||
|
|
016d6d27d1 | ||
|
|
e54741745c | ||
|
|
110e3bd7a6 | ||
|
|
c1b569d9d6 | ||
|
|
577dc34565 | ||
|
|
c7b3f0217f | ||
|
|
e81c89ddd6 | ||
|
|
07b0026e5d | ||
|
|
b531801d6f | ||
|
|
f563b896cc | ||
|
|
c90c6fee01 | ||
|
|
0a0242582f | ||
|
|
2baa531ce5 | ||
|
|
ccef8581b8 | ||
|
|
2d00d8b321 | ||
|
|
e8c3f4860d | ||
|
|
00f03498a9 | ||
|
|
688924d2a8 | ||
|
|
3d45373d3b | ||
|
|
64b43fdf70 | ||
|
|
7b8efcc7cb | ||
|
|
c13401c0a7 | ||
|
|
847a36f064 | ||
|
|
2b7fc4aee9 | ||
|
|
f8459cf838 | ||
|
|
22b5645879 | ||
|
|
d44d592013 | ||
|
|
0c8e7bad3e | ||
|
|
37d7ce16c5 | ||
|
|
9ed0a6ba35 | ||
|
|
35008b75e4 | ||
|
|
9855bc011e | ||
|
|
22093ad2b6 | ||
|
|
ee0508f01c | ||
|
|
32e51de2af | ||
|
|
560f67c9f0 | ||
|
|
3ae075a51a | ||
|
|
1bf590ab2d | ||
|
|
dee7e3f16e | ||
|
|
13edc746f6 | ||
|
|
1e6d2c0488 | ||
|
|
228d83ed24 | ||
|
|
ede0d1b42d | ||
|
|
1e8b786e65 | ||
|
|
8b9026f3ae | ||
|
|
795877532e | ||
|
|
da8d0659a6 | ||
|
|
d06126f814 | ||
|
|
2be02a7c9a | ||
|
|
30fe67226a | ||
|
|
2bfacfe3d0 | ||
|
|
76dad6d1fb | ||
|
|
a2fd82f622 | ||
|
|
3a283cfe9f | ||
|
|
ca9399d4ee | ||
|
|
597b0ae509 | ||
|
|
21c1c29592 | ||
|
|
00f928642f | ||
|
|
c81a0853bb | ||
|
|
bb6ddd8e04 | ||
|
|
7340f67b98 | ||
|
|
1d2674bacc | ||
|
|
e1b7e40ff0 | ||
|
|
c2886473a8 | ||
|
|
ac065c57fd | ||
|
|
9a33077a7b | ||
|
|
20b55f0679 | ||
|
|
35b292ac4b | ||
|
|
61cd3fd268 | ||
|
|
3010818f36 | ||
|
|
733e2741b1 | ||
|
|
195a25316c | ||
|
|
74e3b497c4 | ||
|
|
29f652871e | ||
|
|
13d04fe6ae | ||
|
|
8d31493c99 | ||
|
|
752b447f3e | ||
|
|
a3aa7003ea | ||
|
|
143dc63ffa | ||
|
|
c0fb0740fa | ||
|
|
6ac0dd1d73 | ||
|
|
160fb9abd2 | ||
|
|
f6ad0e4af2 | ||
|
|
e4b246c14a | ||
|
|
2a7c84b4a9 | ||
|
|
da7845c656 | ||
|
|
8980ecd62d | ||
|
|
63f2e969dd | ||
|
|
445293654d | ||
|
|
b5f581e637 | ||
|
|
0f26331b17 | ||
|
|
196fef9b40 | ||
|
|
68dd249987 | ||
|
|
4cf2af4500 | ||
|
|
cadc43ace5 | ||
|
|
239441b5df | ||
|
|
0a93c16c62 | ||
|
|
5dd490e7f1 | ||
|
|
68e9ab4966 | ||
|
|
b684326e69 | ||
|
|
589ba77faf | ||
|
|
6ea9e62bb3 | ||
|
|
d02c81df15 | ||
|
|
e426787454 | ||
|
|
e6fcc73efa | ||
|
|
6167c23e22 | ||
|
|
5e2a1d5b38 | ||
|
|
4aebc943bb | ||
|
|
1a615a41f5 | ||
|
|
cdf41c383f | ||
|
|
a65086c71c | ||
|
|
ae23a57d70 | ||
|
|
c440a92627 | ||
|
|
aa9676dcad | ||
|
|
6cb94e37a9 | ||
|
|
232a7258c3 | ||
|
|
429bd311b7 | ||
|
|
eb621c67cf | ||
|
|
21f86195b7 | ||
|
|
fe3b106cb3 | ||
|
|
3828942550 | ||
|
|
d95457e007 | ||
|
|
da06935f6e | ||
|
|
15c02c2b9d | ||
|
|
0c4aa85e6c | ||
|
|
731b7b07de | ||
|
|
4eb1484dce | ||
|
|
1847ec67ce | ||
|
|
9c2b57232e | ||
|
|
55fb2fc38f | ||
|
|
5a9ac8312e | ||
|
|
7bf812579c | ||
|
|
1209e0ebff | ||
|
|
e7b6f8e3ae | ||
|
|
586a6263e9 | ||
|
|
ec94fbdf45 | ||
|
|
c48f4e8f6c | ||
|
|
e7c99a4dd1 | ||
|
|
e9ddc08da0 | ||
|
|
163e96a0e6 | ||
|
|
0e0a852e91 | ||
|
|
b500277de7 | ||
|
|
002bf86821 | ||
|
|
fcde08534b | ||
|
|
a5db4ba5cb | ||
|
|
20ab569dc3 | ||
|
|
f86e0605d0 | ||
|
|
4423e1743e | ||
|
|
8d087fbb0b | ||
|
|
dc72f4d114 | ||
|
|
576e99a21c | ||
|
|
fc58a8bd98 | ||
|
|
7808b6981b | ||
|
|
852895847f | ||
|
|
b0902369e7 | ||
|
|
da546e69af | ||
|
|
f24b30ec8c | ||
|
|
93906c238d | ||
|
|
9df17e6005 | ||
|
|
efbf4cce0b | ||
|
|
7fe7adcbb9 | ||
|
|
8e10d93d01 | ||
|
|
3cb4693c65 | ||
|
|
48a546b02c | ||
|
|
46da9968df | ||
|
|
29a6964af3 | ||
|
|
62497f0e26 | ||
|
|
c86b0c2149 | ||
|
|
8b6a1a5990 | ||
|
|
8cfcbfddd4 | ||
|
|
e9e94531f0 | ||
|
|
288dd472e3 | ||
|
|
8706301479 | ||
|
|
45ccda1193 | ||
|
|
1689ed4388 | ||
|
|
2af87fa277 | ||
|
|
95a51b93d0 | ||
|
|
f504821589 | ||
|
|
a09e840507 | ||
|
|
eb7e2aa933 | ||
|
|
717a07e208 | ||
|
|
f0a1f78196 | ||
|
|
7f21a4d3f5 | ||
|
|
2bd9c15391 | ||
|
|
481572c63f | ||
|
|
47da28892e | ||
|
|
5c5f62e0dc | ||
|
|
49f3145092 | ||
|
|
ca8cb48d02 | ||
|
|
b4afdd0e28 | ||
|
|
6e8bca8b56 | ||
|
|
00054440c7 | ||
|
|
a2e0cd0c05 | ||
|
|
f6c25db5fe | ||
|
|
6d5cfeb757 | ||
|
|
3de5db2a15 | ||
|
|
db9b81eb6b | ||
|
|
f3c8bc7c3f | ||
|
|
576e1fcd6a | ||
|
|
3125d311e1 | ||
|
|
74ce228f6d | ||
|
|
d28eee6b4f | ||
|
|
d3fd92c6fb | ||
|
|
f7077dd38b | ||
|
|
5cb79ed519 | ||
|
|
b41b004638 | ||
|
|
e3d28d84bd | ||
|
|
2c06a80918 | ||
|
|
570a2c5f3d | ||
|
|
b6979c7278 | ||
|
|
751b61ab25 | ||
|
|
738fb9c2f4 | ||
|
|
0ea6e68655 | ||
|
|
dd549cc257 | ||
|
|
28b44aaacb | ||
|
|
88cb5008a6 | ||
|
|
bff9c3637d | ||
|
|
1fe0c83de4 | ||
|
|
077d7bceff | ||
|
|
162bbcb45f | ||
|
|
69007e652a | ||
|
|
95d7b37a34 | ||
|
|
ddff3e9038 | ||
|
|
47560a0498 | ||
|
|
6e5e4420f4 | ||
|
|
26538c9bfc | ||
|
|
8a834dfa10 | ||
|
|
cf199be81d | ||
|
|
cfebb3cedf | ||
|
|
87369861f9 | ||
|
|
f547c0332d | ||
|
|
57e5a7a1e7 | ||
|
|
f678e47eb0 | ||
|
|
f92cb1fe16 | ||
|
|
beca89bccb | ||
|
|
a40e565719 | ||
|
|
17f99bc6f1 | ||
|
|
7b5e803963 | ||
|
|
20dcc4d122 | ||
|
|
9cf743abf8 | ||
|
|
2f6c03cba2 | ||
|
|
cd7bdd4076 | ||
|
|
d99ecd6c75 | ||
|
|
53358983eb | ||
|
|
7c43775f4f | ||
|
|
df7b55a8f6 | ||
|
|
d8ac237663 | ||
|
|
f39eadac4b | ||
|
|
8ebbef8a15 | ||
|
|
616e421350 | ||
|
|
cbc51277aa | ||
|
|
8c0146d2c9 | ||
|
|
4bfa82acd5 | ||
|
|
d350b509c0 | ||
|
|
383701a590 | ||
|
|
545e4cd69d | ||
|
|
a974e9c997 | ||
|
|
4a3564fe85 | ||
|
|
6bd463c97e | ||
|
|
3c4e51fad6 | ||
|
|
4ac671c49b | ||
|
|
085cace180 | ||
|
|
d36f5a3cc3 | ||
|
|
696338043e | ||
|
|
b997c90f9e | ||
|
|
643a8844a5 | ||
|
|
099f71f78d | ||
|
|
07ef59cab8 | ||
|
|
0708c153e4 | ||
|
|
1cd2725227 | ||
|
|
6a61354ea0 | ||
|
|
273dfb16cc | ||
|
|
2a61a3701f | ||
|
|
5bb0433507 | ||
|
|
8c75b1387a | ||
|
|
debc485626 | ||
|
|
6689e8db4f | ||
|
|
9a82a0215b | ||
|
|
03858cf583 | ||
|
|
7a5a3708cb | ||
|
|
02bf3a96a9 | ||
|
|
79138eaef1 | ||
|
|
d88b2a613f | ||
|
|
1e1fc0336b | ||
|
|
02533d1a60 | ||
|
|
d0dd0473f7 | ||
|
|
8f70a3294c | ||
|
|
a6cc856fbe | ||
|
|
51b272f572 | ||
|
|
1f9b376c90 | ||
|
|
9fe65e2520 | ||
|
|
fa307a6655 | ||
|
|
49bd102a1b | ||
|
|
189e436474 | ||
|
|
9708b248e8 | ||
|
|
afcdb89492 | ||
|
|
aea443b9e8 | ||
|
|
881e5626c5 | ||
|
|
67ae04ba31 | ||
|
|
2807513841 | ||
|
|
bb0af96c54 | ||
|
|
ec586b37e0 | ||
|
|
a7fc5ecead | ||
|
|
649b747913 | ||
|
|
bb971a1e8a | ||
|
|
50a57a0147 | ||
|
|
1584b72ff2 | ||
|
|
065cf0958c | ||
|
|
2a55b4b037 | ||
|
|
27225be1a3 | ||
|
|
73d0d1a0f8 | ||
|
|
ff2bc5c0a1 | ||
|
|
24214ca5d5 | ||
|
|
777042e024 | ||
|
|
1801399830 | ||
|
|
ecd700fbfb | ||
|
|
f1fed3996a | ||
|
|
b32edff5aa | ||
|
|
3913675640 | ||
|
|
b8feb2b142 | ||
|
|
3fe59ed5ef | ||
|
|
5af29cb944 | ||
|
|
7dd57ebdfa | ||
|
|
e23d123b93 | ||
|
|
6398c7a79c | ||
|
|
28e91b48f6 | ||
|
|
3c0bedd494 | ||
|
|
c520964e84 | ||
|
|
acb77ac5bd |
47
.gitignore
vendored
47
.gitignore
vendored
@@ -1,31 +1,32 @@
|
||||
*.a
|
||||
*.[aios]
|
||||
*.[gx]z
|
||||
*.bz2
|
||||
*.cache
|
||||
*.diff
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.orig
|
||||
*.patch
|
||||
*.rej
|
||||
*.so
|
||||
*DISTFILES
|
||||
*~
|
||||
.bootstrap
|
||||
.deps
|
||||
.emacs*
|
||||
.libs
|
||||
ABOUT-NLS
|
||||
ChangeLog
|
||||
INSTALL
|
||||
Make.rules
|
||||
.gdbinit
|
||||
/.bootstrap
|
||||
/ABOUT-NLS
|
||||
/ChangeLog
|
||||
/INSTALL
|
||||
/Make.rules
|
||||
/aclocal.m4
|
||||
/build-aux/
|
||||
/conf*
|
||||
!/configure.ac
|
||||
/gnu/
|
||||
/m4/
|
||||
/rmt/
|
||||
/stamp-h1
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
build-aux
|
||||
build-aux/
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
gnu
|
||||
gnulib
|
||||
libtool
|
||||
m4
|
||||
paxutils
|
||||
stamp-h1
|
||||
TAGS
|
||||
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "gnulib"]
|
||||
path = gnulib
|
||||
url = https://git.savannah.gnu.org/git/gnulib.git
|
||||
[submodule "paxutils"]
|
||||
path = paxutils
|
||||
url = https://git.savannah.gnu.org/git/paxutils.git
|
||||
8
COPYING
8
COPYING
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
29
ChangeLog.1
29
ChangeLog.1
@@ -2,25 +2,22 @@ Currently there is just one ChangeLog file for tar, but
|
||||
there used to be separate ChangeLog files for each subdirectory.
|
||||
This file records what used to be in those separate files.
|
||||
|
||||
Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1989-1997, 2013, 2023-2025 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Tar.
|
||||
This file is part of GNU tar.
|
||||
|
||||
GNU Tar is free software; you can redistribute it and/or modify
|
||||
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.
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Tar is distributed in the hope that it will be useful,
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
----- ChangeLog -----
|
||||
@@ -346,7 +343,7 @@ Boston, MA 02110-1301, USA.
|
||||
* configure.in: For mknod, also include <sys/types.h> prior to
|
||||
<sys/stat.h>, as Ultrix needs this.
|
||||
Reported by Bruce Jerrick, Bryant Fujimoto, Conrad Hughes, Erich
|
||||
Stefan Boleyn, Jason R. Mastaler, Joshua R. Poulson, Jurgen Botz,
|
||||
Stefan Boleyn, Jason R. Mastaler, Joshua R. Poulson, Jürgen Botz,
|
||||
Serge Granik, Simon Wright, Ulrich Drepper and Vince Del Vecchio.
|
||||
|
||||
* configure.in: Replace execlp as needed (for Minix, mainly).
|
||||
@@ -1296,7 +1293,7 @@ Boston, MA 02110-1301, USA.
|
||||
* gmalloc.c: New, from elsewhere. This renames and updates
|
||||
what was previously malloc.c. This also solves __const vs const.
|
||||
* Makefile.in: Distribute gmalloc.c.
|
||||
Reported by Cliff Krumvieda, Francois Pinard, Henrik Bakman,
|
||||
Reported by Cliff Krumvieda, François Pinard, Henrik Bakman,
|
||||
J.T. Conklin, Nelson H.F. Beebe and Tilman Schmidt.
|
||||
|
||||
1994-07-22 François Pinard <pinard@iro.umontreal.ca>
|
||||
@@ -2941,7 +2938,7 @@ Boston, MA 02110-1301, USA.
|
||||
Elmer Fittery, Eric Benson, Eric M. Boehm, Gerd Knorr, Graham
|
||||
Whitted, Harald Milz, Heiko Schlichting, James V. Di Toro III,
|
||||
Jan Carlson, Janne Snabb, Jeff Sorensen, Jens Henrik Jensen,
|
||||
Jim Clausing, John J. Szetela, John R. Vanderpool, Jurgen Botz,
|
||||
Jim Clausing, John J. Szetela, John R. Vanderpool, Jürgen Botz,
|
||||
Karl Berry, Karlos Z. Smith, Karsten Thygesen, Koji Kishi,
|
||||
Luke Mewburn, Manuel Munier, Marc Ewing, Matthew J. D'Errico,
|
||||
Martin Goik, Maxime Taksar, maximum entropy, Michael Hayes,
|
||||
@@ -3189,7 +3186,7 @@ Boston, MA 02110-1301, USA.
|
||||
Reported by Jeffrey Goldberg.
|
||||
|
||||
* rmt.h (_remdev): A filename is not remote if the colon is
|
||||
preceeded by a slash, to take care of `/:/' which is a shorthand
|
||||
preceded by a slash, to take care of `/:/' which is a shorthand
|
||||
for `/.../<CELL-NAME>/fs' on OSF's Distributing Computing
|
||||
Environment (DCE) and Distributed File System (DFS).
|
||||
Reported by Travis L. Priest.
|
||||
@@ -3854,7 +3851,7 @@ Boston, MA 02110-1301, USA.
|
||||
* tar.h: Merely define valloc as being malloc if valloc does
|
||||
not exist.
|
||||
* port.h: Remove valloc, which was only a dummy for malloc.
|
||||
Reported by Cliff Krumvieda, Francois Pinard, Henrik Bakman,
|
||||
Reported by Cliff Krumvieda, François Pinard, Henrik Bakman,
|
||||
J.T. Conklin, Nelson H.F. Beebe and Tilman Schmidt.
|
||||
|
||||
1994-07-22 François Pinard <pinard@iro.umontreal.ca>
|
||||
@@ -5389,7 +5386,7 @@ Boston, MA 02110-1301, USA.
|
||||
* getdate.y : Parse European dates of the form YYMMDD.
|
||||
In ftime(): Init timezone by calling localtime(), and remember that
|
||||
timezone is in seconds, but we want timeb->timezone to be in minutes.
|
||||
Reported by Jörgen Haegg.
|
||||
Reported by Jörgen Hägg.
|
||||
|
||||
* rtape_lib.c (__rmt_open): Also look for /usr/bsd/rsh.
|
||||
Declare signal handler as returning void instead of int if USG is
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
Currently the ChangeLog is generated automatically from the Git
|
||||
revision history, but from 1997 to 2009 the ChangeLog file was
|
||||
maintained by hand, under CVS. This file records the older log.
|
||||
|
||||
Copyright 1997-2001, 2003-2009, 2013, 2023-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
2009-03-05 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/incremen.c: --no-recursive works with --incremental.
|
||||
@@ -913,7 +935,7 @@
|
||||
|
||||
2006-10-02 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* THANKS: Add Joerg Weilbier
|
||||
* THANKS: Add Jörg Weilbier
|
||||
* src/buffer.c (new_volume): Initialize current_block
|
||||
* src/xheader.c (xheader_string_end): Fix diagnostic message.
|
||||
* tests/multiv05.at: New testcase.
|
||||
@@ -1007,7 +1029,7 @@
|
||||
this has undefined behavior. Likewise for assigning arbitrary
|
||||
uintmax_t values to other types.
|
||||
(read_negative_num, read_unsigned_num, read_timespec):
|
||||
New functions, to check input values a bit more carefuly.
|
||||
New functions, to check input values a bit more carefully.
|
||||
(read_num): Use read_unsigned_num. New arg MAX_VAL;
|
||||
all callers changed.
|
||||
(read_incr_db_2): Use these new functions.
|
||||
@@ -1187,7 +1209,7 @@
|
||||
* src/delete.c: Remove second argument from calls to name_scan
|
||||
* src/update.c: Likewise
|
||||
* src/incremen.c (procdir): Use is_individual_file to check for
|
||||
files explicitely specified in the command line. Fixes bug
|
||||
files explicitly specified in the command line. Fixes bug
|
||||
reported by Dat Head on 19 Jun 2006 (descending into mountpoints
|
||||
with --one-file-system in use)
|
||||
* src/misc.c (maybe_backup_file): Second argument is bool
|
||||
@@ -1246,7 +1268,7 @@
|
||||
* src/delete.c (records_skipped): Remove static qualifier, the
|
||||
variable is used by print_total_stats in buffer.c
|
||||
* src/extract.c (check_time): Use volume_start_time when checking
|
||||
for timestamp plausability.
|
||||
for timestamp plausibility.
|
||||
* src/tar.c: (options, parse_opt): Allow for optional argument to
|
||||
the --totals option, which specifies a signal upon delivery of which
|
||||
the statistics must be output.
|
||||
@@ -1304,7 +1326,7 @@
|
||||
|
||||
* src/transform.c (set_transform_expr,_transform_name_to_obstack):
|
||||
Implement NUMBER flag.
|
||||
(add_char_segment): Fix length assignement
|
||||
(add_char_segment): Fix length assignment
|
||||
|
||||
* doc/tar.texi: Update
|
||||
|
||||
@@ -1361,7 +1383,7 @@
|
||||
* doc/tar.texi: Update
|
||||
* configure.ac (AM_INIT_AUTOMAKE): Use tar-ustar option. Raise
|
||||
version requirement to 1.9
|
||||
* src/common.h (struct name): Refactured
|
||||
* src/common.h (struct name): Refactored
|
||||
(warn_regex_usage): New variable.
|
||||
(dump_file): First argument is const char*.
|
||||
(name_init,name_add): Removed
|
||||
@@ -1736,13 +1758,13 @@
|
||||
* src/common.h (struct name): New member `explicit'. Remove unused
|
||||
member `isdir'.
|
||||
* src/incremen.c (procdir): If name_scan() returns something,
|
||||
check if it was explicitely given in the command line
|
||||
check if it was explicitly given in the command line
|
||||
* src/names.c (addname,add_hierarchy_to_namelist): Initialize
|
||||
explicit member appropriately.
|
||||
|
||||
* src/incremen.c (procdir): If --one-file-system is given and a
|
||||
directory is found to be on another device, *and* this directory
|
||||
is explicitely given in the command line, then do not omit it.
|
||||
is explicitly given in the command line, then do not omit it.
|
||||
|
||||
2005-12-11 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
@@ -1777,7 +1799,7 @@
|
||||
(mode_to_chars, off_to_chars, size_to_chars, time_to_chars)
|
||||
(uid_to_chars, uintmax_to_chars): Return bool
|
||||
(to_chars): Return bool
|
||||
(start_header): Check return values of convertion routines. Fail
|
||||
(start_header): Check return values of conversion routines. Fail
|
||||
if unable to store data in the header.
|
||||
|
||||
2005-12-07 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
@@ -2077,13 +2099,13 @@
|
||||
archives.
|
||||
* src/incremen.c (dumpdir_size, get_gnu_dumpdir): New functions.
|
||||
(purge_directory): Use stat_info.dumpdir instead of getting its
|
||||
value explicitely.
|
||||
value explicitly.
|
||||
* src/list.c (list_archive): Handle incremental backups in pax
|
||||
format.
|
||||
(decode_header): Initialize stat_info.dumpdir
|
||||
* src/sparse.c (sparse_diff_file): Bugfix: set seekable.
|
||||
(pax_dump_header): Store sparse map in GNU.sparse.map. If this
|
||||
variable has been explicitely deleted, use GNU.sparse.offset/
|
||||
variable has been explicitly deleted, use GNU.sparse.offset/
|
||||
GNU.sparse.numbytes variables.
|
||||
* src/tar.c (decode_options): Incremental options are allowed with
|
||||
--format=pax
|
||||
@@ -2161,7 +2183,7 @@
|
||||
|
||||
* bootstrap: Fix quoting in help output.
|
||||
(update_po): Use backward-compatible wget option --cache instead
|
||||
of deprecated -C to accomodate for wget 1.10.
|
||||
of deprecated -C to accommodate for wget 1.10.
|
||||
Changes proposed by Eric Blake
|
||||
* THANKS: Add Eric Blake
|
||||
|
||||
@@ -2712,7 +2734,7 @@
|
||||
* src/list.c: Likewise
|
||||
|
||||
* tests/multiv03.at: Modified to match the new behavior
|
||||
* tests/multiv04.at: New file. Test splittind directory members between
|
||||
* tests/multiv04.at: New file. Test splitting directory members between
|
||||
the archive volumes.
|
||||
* tests/Makefile.am: Add multiv04.at
|
||||
* tests/testsuite.at: Likewise.
|
||||
@@ -4466,7 +4488,7 @@
|
||||
|
||||
* src/create.c: Do not zero-terminate name field if
|
||||
the name is exactly 100 characters long.
|
||||
(write_ustar_long_name): Fixed cheking for unsplittable
|
||||
(write_ustar_long_name): Fixed checking for unsplittable
|
||||
names.
|
||||
|
||||
2003-11-14 Sergey Poznyakoff <gray@Mirddin.farlep.net>
|
||||
@@ -4501,7 +4523,7 @@
|
||||
|
||||
2003-11-12 Paul Eggert <eggert@twinsun.com>
|
||||
|
||||
Fix some C compatibility bugs reported by Joerg Schilling.
|
||||
Fix some C compatibility bugs reported by Jörg Schilling.
|
||||
|
||||
* src/common.h (stripped_prefix_len): Fix misspelling
|
||||
"stripped_path_len" in declaration.
|
||||
@@ -5163,7 +5185,7 @@
|
||||
interface.
|
||||
(child_open_for_compress): Do not increase size to BLOCKSIZE.
|
||||
(open_archive): Open index file name.
|
||||
Strip trailing slahes from file names.
|
||||
Strip trailing slashes from file names.
|
||||
(flush_write): Set size to 0 if not saving names.
|
||||
(flush_write, flush_read): Use safer_name_suffix rather than
|
||||
inline code.
|
||||
@@ -5996,7 +6018,7 @@
|
||||
(decode_options): Dates that look like an absolute path name,
|
||||
or that start with '.', are presumed to be file names whose
|
||||
dates are taken.
|
||||
Remove 'I' as an aliase for 'T'.
|
||||
Remove 'I' as an alias for 'T'.
|
||||
Update copyright.
|
||||
|
||||
* src/extract.c (<time.h>): Do not include; system.h now does this.
|
||||
@@ -8806,26 +8828,6 @@
|
||||
See ChangeLog.1 for earlier changes.
|
||||
|
||||
-----
|
||||
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007
|
||||
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 3, 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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
|
||||
Local Variables:
|
||||
mode: change-log
|
||||
|
||||
70
ChangeLog.amend
Normal file
70
ChangeLog.amend
Normal file
@@ -0,0 +1,70 @@
|
||||
# Fix typos in tar ChangeLog entries generated from git log
|
||||
|
||||
f24b30ec8ca1851b7bd14694241de3b38194c99c
|
||||
s/commit 2bd9c153_\./commit 2bd9c153)./
|
||||
|
||||
29a6964af3e1baabe978ce608e0466e1250d08ab
|
||||
s/ORDER \(none, name, or order\)\./ORDER (none, name, or inode)./
|
||||
|
||||
2af87fa2776c8125a587a9b0c2c4fae3bf921ff7
|
||||
s/contant\./content./
|
||||
|
||||
2bd9c15391b0bd6ef0bff76aebf09cfb53003199
|
||||
s/ocurrence/occurrence/
|
||||
|
||||
47da28892e6860a3a6fc06745f640e3bb878c757
|
||||
s/aruond/around/
|
||||
|
||||
f7077dd38b018f19d3a5c7df6accc6b07b8a2356
|
||||
s/absoulte/absolute/
|
||||
|
||||
28b44aaacb45680aa6640e0a6d7ceab04cfdbf11
|
||||
s/warniing/warning/
|
||||
|
||||
47560a0498bde20621ce4e367b1d68bf8cd8f1a3
|
||||
s/interacton/interaction/
|
||||
|
||||
26538c9bfc5fd726d625bef5fa3f08212d50173a
|
||||
s/consuption/consumption/;
|
||||
s/misfunctioned/malfunctioned/;
|
||||
s/misssing/missing/;
|
||||
|
||||
696338043e52f440853e1143c52b81b41cd59723
|
||||
s/suuport/support/
|
||||
|
||||
643a8844a578ff146cfe746fe6091d29502b6c40
|
||||
s/incrfental/incremental/;
|
||||
s/afterwards/afterward/;
|
||||
|
||||
03858cf583ce299b836d8a848967ce290a6bf303
|
||||
s/Peformance/Performance/
|
||||
|
||||
fa307a665545753b6729191fd2559ce872fa470a
|
||||
s/filags/flags/
|
||||
|
||||
73d0d1a0f883be5f67534362c99382f1eae8d178
|
||||
s/contais/contains/
|
||||
|
||||
5af29cb944c84e2d539ce9df527d63c29f6012b9
|
||||
s/appendig/appending/
|
||||
|
||||
7dd57ebdfa9ac0d2af4622449f45b5025f6c184f
|
||||
s/encounted/encountered/
|
||||
|
||||
ecbcb7b6d74c2d69386c8d7e435486a4690c9993
|
||||
s/inadvertantly/inadvertently/
|
||||
|
||||
4dfcd6c054a5e9e1a371c822a3be90564dd9b690
|
||||
s/succesfully/successfully/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
30
Makefile.am
30
Makefile.am
@@ -1,22 +1,21 @@
|
||||
# Main Makefile for GNU tar.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2007,
|
||||
# 2009 Free Software Foundation, Inc.
|
||||
# Copyright 1994-2025 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 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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 3 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = ChangeLog.1 Make.rules
|
||||
@@ -26,7 +25,7 @@ dist-hook:
|
||||
$(MAKE) changelog_dir=$(distdir) ChangeLog
|
||||
-rm -f $(distdir).cpio
|
||||
find $(distdir) | cpio -Hcrc -o | \
|
||||
GZIP=$(GZIP_ENV) gzip -c > $(distdir).cpio.gz
|
||||
eval GZIP= gzip $(GZIP_ENV) -c > $(distdir).cpio.gz
|
||||
|
||||
distclean-local:
|
||||
-rm -f $(distdir).cpio.gz
|
||||
@@ -36,3 +35,4 @@ include Make.rules
|
||||
gen_start_date = 2009-03-06
|
||||
prev_change_log = ChangeLog.CVS
|
||||
changelog_dir = .
|
||||
changelog_amend_file=ChangeLog.amend
|
||||
|
||||
128
README
128
README
@@ -4,31 +4,30 @@ See the end of file for copying conditions.
|
||||
* Introduction
|
||||
|
||||
Please glance through *all* sections of this
|
||||
`README' file before starting configuration. Also make sure you read files
|
||||
`ABOUT-NLS' and `INSTALL' if you are not familiar with them already.
|
||||
'README' file before starting configuration. Also make sure you read files
|
||||
'ABOUT-NLS' and 'INSTALL' if you are not familiar with them already.
|
||||
|
||||
If you got the `tar' distribution in `shar' format, time stamps ought to be
|
||||
properly restored; do not ignore such complaints at `unshar' time.
|
||||
If you got the 'tar' distribution in 'shar' format, time stamps ought to be
|
||||
properly restored; do not ignore such complaints at 'unshar' time.
|
||||
|
||||
GNU `tar' saves many files together into a single tape or disk
|
||||
GNU 'tar' saves many files together into a single tape or disk
|
||||
archive, and can restore individual files from the archive. It includes
|
||||
multivolume support, the ability to archive sparse files, automatic archive
|
||||
compression/decompression, remote archives and special features that allow
|
||||
`tar' to be used for incremental and full backups. This distribution
|
||||
also includes `rmt', the remote tape server. The `mt' tape drive control
|
||||
program is in the GNU `cpio' distribution.
|
||||
'tar' to be used for incremental and full backups. This distribution
|
||||
also includes 'rmt', the remote tape server. The 'mt' tape drive control
|
||||
program is in the GNU 'cpio' distribution.
|
||||
|
||||
GNU `tar' is derived from John Gilmore's public domain `tar'.
|
||||
GNU 'tar' is derived from John Gilmore's public domain 'tar'.
|
||||
|
||||
See file `ABOUT-NLS' for how to customize this program to your language.
|
||||
See file `COPYING' for copying conditions.
|
||||
See file `INSTALL' for compilation and installation instructions.
|
||||
See file `PORTS' for various ports of GNU tar to non-Unix systems.
|
||||
See file `NEWS' for a list of major changes in the current release.
|
||||
See file `THANKS' for a list of contributors.
|
||||
See file 'ABOUT-NLS' for how to customize this program to your language.
|
||||
See file 'COPYING' for copying conditions.
|
||||
See file 'INSTALL' for compilation and installation instructions.
|
||||
See file 'NEWS' for a list of major changes in the current release.
|
||||
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':
|
||||
Besides those configure options documented in files 'INSTALL' and
|
||||
'ABOUT-NLS', an extra option may be accepted after './configure':
|
||||
|
||||
* Install
|
||||
|
||||
@@ -40,11 +39,11 @@ 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'
|
||||
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.
|
||||
The default archive device is now 'stdin' on read and 'stdout' on write.
|
||||
The installer can still override this by presetting 'DEFAULT_ARCHIVE'
|
||||
in the environment before configuring (the behavior of '-[0-7]' or
|
||||
'-[0-7]lmh' options in 'tar' are then derived automatically). Similarly,
|
||||
'DEFAULT_BLOCKING' can be preset to something else than 20.
|
||||
|
||||
** Selecting full pathname of the "rmt" binary.
|
||||
|
||||
@@ -76,13 +75,13 @@ directory.
|
||||
Use option --enable-backup-scripts to compile and install these
|
||||
scripts.
|
||||
|
||||
** `--disable-largefile' omits support for large files, even if the
|
||||
** '--disable-largefile' omits support for large files, even if the
|
||||
operating system supports large files. Typically, large files are
|
||||
those larger than 2 GB on a 32-bit host.
|
||||
|
||||
* Installation hints
|
||||
|
||||
Here are a few hints which might help installing `tar' on some systems.
|
||||
Here are a few hints which might help installing 'tar' on some systems.
|
||||
|
||||
** gzip and bzip2.
|
||||
|
||||
@@ -103,7 +102,7 @@ then you have encountered a gzip incompatibility that should be fixed
|
||||
in gzip test version 1.3, which as of this writing is available at
|
||||
<ftp://alpha.gnu.org/gnu/gzip/>. You can work around the
|
||||
incompatibility by using a shell command like
|
||||
`gzip -d <file.tar.gz | tar -xzf -'.
|
||||
'gzip -d <file.tar.gz | tar -xzf -'.
|
||||
|
||||
** Solaris issues.
|
||||
|
||||
@@ -118,13 +117,13 @@ understand these headers.
|
||||
|
||||
** Static linking.
|
||||
|
||||
Some platform will, by default, prepare a smaller `tar' executable
|
||||
which depends on shared libraries. Since GNU `tar' may be used for
|
||||
Some platform will, by default, prepare a smaller 'tar' executable
|
||||
which depends on shared libraries. Since GNU 'tar' may be used for
|
||||
system-level backups and disaster recovery, installers might prefer to
|
||||
force static linking, making a bigger `tar' executable maybe, but able to
|
||||
force static linking, making a bigger 'tar' executable maybe, but able to
|
||||
work standalone, in situations where shared libraries are not available.
|
||||
The way to achieve static linking varies between systems. Set LDFLAGS
|
||||
to a value from the table below, before configuration (see `INSTALL').
|
||||
to a value from the table below, before configuration (see 'INSTALL').
|
||||
|
||||
Platform Compiler LDFLAGS
|
||||
|
||||
@@ -137,18 +136,18 @@ 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
|
||||
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.
|
||||
|
||||
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).
|
||||
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
|
||||
|
||||
@@ -159,43 +158,43 @@ the simplest workaround is to avoid tarring this file.
|
||||
|
||||
* Special topics
|
||||
|
||||
Here are a few special matters about GNU `tar', not related to build
|
||||
Here are a few special matters about GNU 'tar', not related to build
|
||||
matters. See previous section for such.
|
||||
|
||||
** File attributes.
|
||||
|
||||
About *security*, it is probable that future releases of `tar' will have
|
||||
About *security*, it is probable that future releases of 'tar' will have
|
||||
some behavior changed. There are many pending suggestions to choose from.
|
||||
Today, extracting an archive not being `root', `tar' will restore suid/sgid
|
||||
bits on files but owned by the extracting user. `root' automatically gets
|
||||
a lot of special privileges, `-p' might later become required to get them.
|
||||
Today, extracting an archive not being 'root', 'tar' will restore suid/sgid
|
||||
bits on files but owned by the extracting user. 'root' automatically gets
|
||||
a lot of special privileges, '-p' might later become required to get them.
|
||||
|
||||
GNU `tar' does not properly restore symlink attributes. Various systems
|
||||
GNU 'tar' does not properly restore symlink attributes. Various systems
|
||||
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.
|
||||
the 'lchown' call will be used if available, but that's all.
|
||||
|
||||
** POSIX compliance.
|
||||
|
||||
GNU `tar' is able to create archive in the following formats:
|
||||
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.
|
||||
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
|
||||
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.
|
||||
and new 'tar' features.
|
||||
|
||||
* What's next?
|
||||
|
||||
@@ -216,32 +215,35 @@ 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
|
||||
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, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1990-2025 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
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 3, or (at your option)
|
||||
any later version.
|
||||
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 3 of the License, 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.
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
NOTE ON COPYRIGHT YEARS
|
||||
|
||||
In copyright notices where the copyright holder is the Free Software
|
||||
Foundation, then where a range of years appears, this is an inclusive
|
||||
range that applies to every year in the range. For example: 2005-2008
|
||||
represents the years 2005, 2006, 2007, and 2008.
|
||||
|
||||
Local Variables:
|
||||
mode: outline
|
||||
|
||||
67
README-alpha
67
README-alpha
@@ -3,73 +3,16 @@ 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>.
|
||||
|
||||
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, so please make sure
|
||||
that you have the latest stable version.
|
||||
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Autoconf <http://www.gnu.org/software/autoconf/>
|
||||
- Bison <http://www.gnu.org/software/bison/>
|
||||
- Gettext <http://www.gnu.org/software/gettext/>
|
||||
- Gzip <http://www.gnu.org/software/gzip/>
|
||||
- M4 <http://www.gnu.org/software/m4/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Wget <http://www.gnu.org/software/wget/>
|
||||
|
||||
As of this writing, the latest stable version of Gzip is 1.2.4 but we
|
||||
suggest using test version 1.3.5 (or later, if one becomes available).
|
||||
|
||||
Valgrind <http://valgrind.org/> is also highly recommended, if
|
||||
Valgrind supports your architecture.
|
||||
|
||||
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 and
|
||||
paxutils files from their corresponding CVS repositories on Savannah
|
||||
using anonymous SSH access. Then, it will fetch the po files from tar
|
||||
page at Translation Project, and, finally, it will start autoconfiguration
|
||||
process. Simply running it without arguments should do in most cases.
|
||||
Several options allow to control the behavior of bootstrap:
|
||||
|
||||
--gnulib-srcdir=DIRNAME Specify the local directory where gnulib
|
||||
sources reside. Use this if you already
|
||||
have gnulib sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
|
||||
--paxutils-srcdir=DIRNAME Specify the local directory where paxutils
|
||||
sources reside. Use this if you already
|
||||
have paxutils sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
|
||||
--cvs-auth=METHOD Set the CVS access method used for downloading
|
||||
gnulib files. METHOD is one of the keywords
|
||||
accepted by cvs -d option (see info cvs
|
||||
repository).
|
||||
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
|
||||
--no-po Do not download po files.
|
||||
|
||||
Notice also that when using CVS authentication method "ext", bootstrap
|
||||
will set the variable CVS_RSH to "ssh", unless it is already set to
|
||||
some other value.
|
||||
|
||||
|
||||
|
||||
Copyright (C) 2001, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2001-2025 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 3, or (at your option)
|
||||
any later version.
|
||||
the Free Software Foundation; either version 3 of the License, 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
|
||||
@@ -77,6 +20,4 @@ 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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -8,12 +8,22 @@ tar. We do not make any efforts to accommodate older versions of
|
||||
these packages, so please make sure that you have the latest stable
|
||||
version.
|
||||
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Autoconf <http://www.gnu.org/software/autoconf/>
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Bison <http://www.gnu.org/software/bison/>
|
||||
- M4 <http://www.gnu.org/software/m4/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Gnulib <http://www.gnu.org/software/gnulib>
|
||||
- Gettext <http://www.gnu.org/software/gettext/>
|
||||
- Git <http://git.or.cz>
|
||||
- Gzip <http://www.gnu.org/software/gzip/>
|
||||
- Texinfo <http://www.gnu.org/software/texinfo>
|
||||
- Wget <http://www.gnu.org/software/wget/>
|
||||
|
||||
Up-to-date compilers and libraries are also recommended, for better
|
||||
static checking. You may be able to use an older compiler by building
|
||||
with 'make WERROR_CFLAGS='; if so, don't worry about its false alarms.
|
||||
|
||||
Valgrind <http://valgrind.org/> is also highly recommended, if
|
||||
Valgrind supports your architecture.
|
||||
|
||||
* Bootstrapping
|
||||
|
||||
@@ -33,33 +43,43 @@ Once done, proceed as described in the file README (section
|
||||
INSTALLATION).
|
||||
|
||||
Normally you will have to run bootstrap only once. However, if you
|
||||
intend to hack on GNU tar, you might need to run it again later. In
|
||||
this case, you will probably want to save some time and bandwidth by
|
||||
avoiding downloading the same files again. If so, create in GNU tar
|
||||
root directory the file named `.bootstrap' with the following
|
||||
contents:
|
||||
intend to hack on GNU tar, you might need to run it again later.
|
||||
There are lots of options that you may find useful in this case.
|
||||
See './bootstrap --help' for a detailed list.
|
||||
|
||||
--gnulib-srcdir=$HOME/gnulib
|
||||
Bootstrapping obtains Gnulib and Paxutils files from their Git
|
||||
repositories on Savannah. Then, it fetches translations from the
|
||||
Translation Project, and, finally, it builds files useful for
|
||||
configuration. Simply running ./bootstrap without arguments should do
|
||||
in most cases.
|
||||
|
||||
Replace `$HOME/gnulib' with the actual directory where the Gnulib
|
||||
sources reside.
|
||||
The file bootstrap.conf contains bootstrapping configuration.
|
||||
Several options are provided that modify its behavior.
|
||||
Run './bootstrap --help' for a list.
|
||||
|
||||
For more information about `bootstrap', run `bootstrap --help'.
|
||||
To only fetch auxiliary files from the network, run './bootstrap --pull'.
|
||||
To only generate files such as 'configure', without accessing the
|
||||
network, run './bootstrap --gen'.
|
||||
|
||||
|
||||
* Copyright information
|
||||
|
||||
Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
Copyright 2007-2025 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to anyone to make or distribute verbatim copies
|
||||
of this document as received, in any medium, provided that the
|
||||
copyright notice and this permission notice are preserved,
|
||||
thus giving the recipient permission to redistribute in turn.
|
||||
This file is part of GNU tar.
|
||||
|
||||
Permission is granted to distribute modified versions
|
||||
of this document, or of portions of it,
|
||||
under the above conditions, provided also that they
|
||||
carry prominent notices stating who last changed them.
|
||||
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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
^L
|
||||
Local Variables:
|
||||
|
||||
29
THANKS
29
THANKS
@@ -8,6 +8,7 @@ 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
|
||||
Adam Borowski kilobyte@angband.pl
|
||||
Adye, TJ (Tim) T.J.Adye@rl.ac.uk
|
||||
Akiko Matsushita matusita@sra.co.jp
|
||||
Alan Bawden Alan@lcs.mit.edu
|
||||
@@ -36,6 +37,7 @@ Andrew Torda torda@igc.chem.ethz.ch
|
||||
Andrey A. Chernov ache@astral.msk.su
|
||||
Andy Gay andy@rdl.co.uk
|
||||
Antonio Jose Coutinho ajc@di.uminho.pt
|
||||
Anthony G. Basile blueness@gentoo.org
|
||||
Ariel Faigon ariel@engr.sgi.com
|
||||
Arne Wichmann aw@math.uni-sb.de
|
||||
Arnold Robbins arnold@gnu.org
|
||||
@@ -77,6 +79,7 @@ Cesar Romani romani@ifm.uni-hamburg.de
|
||||
Chad Hurwitz churritz@cts.com
|
||||
Chance Reschke creschke@usra.edu
|
||||
Charles Fu ccwf@klab.caltech.edu
|
||||
Charles McGarvey chazmcgarvey@brokenzipper.com
|
||||
Charles Lopes Charles.Lopes@infm.ulst.ac.uk
|
||||
Charles M. Hannum mycroft@gnu.org
|
||||
Chip Salzenberg tct!chip
|
||||
@@ -91,6 +94,8 @@ 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
|
||||
Christian Wetzel wetzel@phoenix-pacs.de
|
||||
Christian Weisgerber naddy@mips.inka.de
|
||||
Christoph Litauer litauer@mailhost.uni-koblenz.de
|
||||
Christophe Colle colle@krtkg1.rug.ac.be
|
||||
Christophe Kalt Christophe.Kalt@kbcfp.com
|
||||
@@ -100,10 +105,12 @@ Claude Scarpelli claude@genethon.fr
|
||||
Claus Heine Claus_Heine@ac2.maus.de
|
||||
Cliff Krumvieda cliff@cs.cornell.edu
|
||||
Clinton Carr clint@netcom.com
|
||||
Connor Behan connor.behan@gmail.com
|
||||
Conrad Hughes chughes@maths.tcd.ie
|
||||
Constantin Belous const@cris.net
|
||||
Coranth Gryphon gryphon@bur.visidyne.com
|
||||
Cyril Strejc strejc@unicontrols.cz
|
||||
Dagobert Michelsen dam@opencsw.org
|
||||
Dale R. Worley worley@world.std.com
|
||||
Dale Wiles wiles@geordi.calspan.com
|
||||
Dan Bloch dan@transarc.com
|
||||
@@ -111,6 +118,7 @@ Dan Drake dan@dandrake.org
|
||||
Dan Reish dreish@izzy.net
|
||||
Daniel Hagerty hag@gnu.org
|
||||
Daniel Quinlan quinlan@pathname.com
|
||||
Daniel Kahn Gillmor dkg@fifthhorseman.net
|
||||
Daniel R. Guilderson d.guilderson@ma30.bull.com
|
||||
Daniel S. Barclay daniel@compass-da.com
|
||||
Daniel Trinkle trinkle@cs.purdue.edu
|
||||
@@ -118,6 +126,7 @@ Danny R. Johnston danny@cs.weber.edu
|
||||
Dave Barr barr@math.psu.edu
|
||||
Dave Gentzel gentzel@nova.enet.dec.com
|
||||
Dave Gregorich dtg@ipac.caltech.edu
|
||||
David Barri japgolly@gmail.com
|
||||
David Brown davidb@davidb.org
|
||||
David J. MacKenzie djm@uunet.uu.net
|
||||
David Johnson David.W.Johnson@colorado.edu
|
||||
@@ -131,11 +140,13 @@ David Nugent davidn@blaze.net.au
|
||||
David Shaw david.shaw@alcatel.com.au
|
||||
David Steiner dsteiner@ispa.uni-osnabrueck.de
|
||||
David Taylor taylor@think.com
|
||||
Dawid dpc@dpc.pw
|
||||
Dean Gaudet dgaudet@watdragon.uwaterloo.ca
|
||||
Demizu Noritoshi nori-d@is.aist-nara.ac.jp
|
||||
Denis Excoffier denis.excoffier@free.fr
|
||||
Denis Fortin fortin@acm.org
|
||||
Dennis Pixton dennis@math.binghamton.edu
|
||||
Derek Terveer dt@hawkmoon.mn.org
|
||||
Dick Streefland dicks@tasking.nl
|
||||
Dietmar Braun dietmar@highway.bertelsmann.de
|
||||
Dimitri Bougoulias opus@hol.gr
|
||||
@@ -168,6 +179,7 @@ Erik D. Frederick edf@deckard.mc.duke.edu
|
||||
Esa Karell karell@cs.helsinki.fi
|
||||
Ezra Peisach epeisach@mit.edu
|
||||
Fabio d'Alessi cars@civ.bio.unipd.it
|
||||
Flavio Poletti polettix@gmail.com
|
||||
Frank Heckenbach frank@g-n-u.de
|
||||
Frank Koenen koenfr@lidp.com
|
||||
Franz-Werner Gergen gergen@edvulx.mpi-stuttgart.mpg.de
|
||||
@@ -198,6 +210,7 @@ Helmut Waitzmann Helmut.Waitzmann@web.de
|
||||
Henrik Bakman hb@csd.uu.se
|
||||
Hernan Prieto Schmidt hernan@pea.usp.br
|
||||
Hiroyuki Bessho bsh@grotto.iijnet.or.jp
|
||||
Holger Levsen holger@layer-acht.org
|
||||
Holger Teutsch holger@hotbso.rhein-main.de
|
||||
Hugh Secker-Walker hugh@ear.mit.edu
|
||||
Hunyue Yau hunyue.yau@picksys.com
|
||||
@@ -236,11 +249,13 @@ Jeffrey Goldberg J.Goldberg@cranfield.ac.uk
|
||||
Jeffrey Mark Siskind Qobi@emba.uvm.edu
|
||||
Jeffrey W. Parker jwpkr@mcs.com
|
||||
Jens Henrik Jensen recjhl@mediator.uni-c.dk
|
||||
Jérémy Bobbio lunar@debian.org
|
||||
Jim Blandy jimb@totoro.cs.oberlin.edu
|
||||
Jim Clausing jac@postbox.acs.ohio-state.edu
|
||||
Jim Farrell jwf@platinum.com
|
||||
Jim Meyering meyering@na-net.ornl.gov
|
||||
Jim Murray jjm@jjm.com
|
||||
Jivko Angelov jivko@siteground.com
|
||||
Joachim Holzfuss Joachim.Holzfuss@iap.physik.th-darmstadt.de
|
||||
Joachim Seelig joachim@kruemel.han.de
|
||||
Joe DeBattista joed@itsa.ucsf.edu
|
||||
@@ -268,7 +283,7 @@ Joutsiniemi Tommi Il tj75064@cs.tut.fi
|
||||
Joy Kendall jak8@world.std.com
|
||||
Judy Ricker jricker@gdstech.grumman.com
|
||||
Juha Sarlin juha@tds.kth.se
|
||||
Jurgen Botz jbotz@orixa.mtholyoke.edu
|
||||
Jürgen Botz jbotz@orixa.mtholyoke.edu
|
||||
Jyh-Shyang Wang erik@vsp.ee.nctu.edu.tw
|
||||
Jörg Schilling schilling@fokus.fraunhofer.de
|
||||
Jörg Weule weule@cs.uni-duesseldorf.de
|
||||
@@ -293,9 +308,11 @@ Kevin D Quitt drs@netcom.com
|
||||
Kevin Dalley kevin@aimnet.com
|
||||
Kimball Collins kpc@ptolemy.arc.nasa.gov
|
||||
Kimmy Posey kimmyd@bnr.ca
|
||||
Kirill Furman kfurman@astralinux.ru
|
||||
Koji Kishi kis@rqa.sony.co.jp
|
||||
Konno Hiroharu konno@pac.co.jp
|
||||
Kurt Jaeger pi@lf.net
|
||||
James Antill jantill@redhat.com
|
||||
Larry Creech lcreech@lonestar.rcclub.org
|
||||
Larry Schwimmer rosebud@cyclone.stanford.edu
|
||||
Lasse Collin lasse.collin@tukaani.org
|
||||
@@ -311,6 +328,7 @@ Mads Martin Joergensen mmj@suse.de
|
||||
Manfred Weichel Manfred.Weichel@mch.sni.de
|
||||
Manuel Munier Manuel.Munier@loria.fr
|
||||
Marc Boucher marc@cam.org
|
||||
Marc Espie marc.espie.openbsd@gmail.com
|
||||
Marc Ewing marc@redhat.com
|
||||
Marcin Matuszewski marcin@frodo.nask.org.pl
|
||||
Marcus Daniels marcus@sysc.pdx.edu
|
||||
@@ -349,6 +367,7 @@ Michael P Urban urban@cobra.jpl.nasa.gov
|
||||
Michael Schmidt michael@muc.de
|
||||
Michael Schwingen m.schwingen@stochastik.rwth-aachen.de
|
||||
Michael Smolsky fnsiguc@astro.weizmann.ac.il
|
||||
Michal Žejdl zejdl@suas.cz
|
||||
Mike Muuss mike@brl.mil
|
||||
Mike Nolan nolan@lpl.arizona.edu
|
||||
Mike Rogers mike@demon.net
|
||||
@@ -357,11 +376,14 @@ 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
|
||||
Natalie Alifanova na@nxc.no
|
||||
Nate Eldredge nate@cs.hmc.edu
|
||||
Nathan Stratton Treadway nathanst+bugtar@ontko.com
|
||||
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
|
||||
Nicolas Dudebout nicolas.dudebout@gmail.com
|
||||
Noah Friedman friedman@gnu.org
|
||||
Noel Cragg noel@red-bean.com
|
||||
Norbert Kiesel norbert@rwthi3.informatik.rwth-aachen.de
|
||||
@@ -374,7 +396,8 @@ Oswald P. Backus IV backus@lks.csi.com
|
||||
Pascal Meheut pascal@cnam.cnam.fr
|
||||
Patrick Fulconis fulco@sig.uvsq.fr
|
||||
Patrick Timmons timmons@electech.polymtl.ca
|
||||
Paul Eggert eggert@twinsun.com
|
||||
Pavel Raiskup praiskup@redhat.com
|
||||
Paul Eggert eggert@cs.ucla.edu
|
||||
Paul Kanz paul@icx.com
|
||||
Paul Mitchell P.Mitchell@surrey.ac.uk
|
||||
Paul Nevai pali+@osu.edu
|
||||
@@ -395,6 +418,7 @@ Phil Proudman phil@proudman51.freeserve.co.uk
|
||||
Philippe Defert defert@cern.ch
|
||||
Piercarlo Grandi piercarl@sabi.demon.co.uk
|
||||
Pierce Cantrell cantrell@ee.tamu.edu
|
||||
Piotr Rotter piotr.rotter@active24.pl
|
||||
R. Kent Dybvig dyb@cadence.bloomington.in.us
|
||||
R. Scott Butler butler@prism.es.dupont.com
|
||||
Rainer Orth ro@TechFak.Uni-Bielefeld.DE
|
||||
@@ -513,6 +537,7 @@ 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
|
||||
Wicher Minnaard wicher@nontrivialpursuit.org
|
||||
William Bader william@nscs.fast.net
|
||||
William J. Eaton wje@hoffman.rstnu.bcm.tmc.edu
|
||||
William Kucharski kucharsk@netcom.com
|
||||
|
||||
30
TODO
30
TODO
@@ -15,7 +15,7 @@ Suggestions for improving GNU tar.
|
||||
* Add support for a 'pax' command that conforms to POSIX 1003.1-2001.
|
||||
This would unify paxutils with tar.
|
||||
|
||||
* Interoperate better with Joerg Schilling's star implementation.
|
||||
* Interoperate better with Jörg Schilling's star implementation.
|
||||
|
||||
* Add an option to remove files that compare successfully.
|
||||
|
||||
@@ -25,7 +25,7 @@ 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.
|
||||
|
||||
* Add tests for the new functonality.
|
||||
* Add tests for the new functionality.
|
||||
|
||||
* Consider this:
|
||||
|
||||
@@ -45,24 +45,22 @@ Suggestions for improving GNU tar.
|
||||
|
||||
* Copyright notice
|
||||
|
||||
Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2003-2025 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
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 3, or (at your option)
|
||||
any later version.
|
||||
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 3 of the License, 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.
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Local variables:
|
||||
|
||||
50
acinclude.m4
50
acinclude.m4
@@ -1,26 +1,62 @@
|
||||
dnl Special Autoconf macros for GNU Tar -*- autoconf -*-
|
||||
dnl Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
dnl Special Autoconf macros for GNU tar -*- autoconf -*-
|
||||
|
||||
dnl Copyright 2009-2025 Free Software Foundation, Inc.
|
||||
dnl
|
||||
dnl This file is part of GNU tar.
|
||||
dnl
|
||||
dnl GNU tar is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 3, or (at your option)
|
||||
dnl any later version.
|
||||
dnl the Free Software Foundation; either version 3 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl GNU tar is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
dnl GNU General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License along
|
||||
dnl with GNU tar. If not, see <http://www.gnu.org/licenses/>.
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_DEFUN([TAR_COMPR_PROGRAM],[
|
||||
m4_pushdef([tar_compr_define],translit($1,[a-z+-],[A-ZX_])[_PROGRAM])
|
||||
m4_pushdef([tar_compr_var],[tar_cv_compressor_]translit($1,[+-],[x_]))
|
||||
AC_ARG_WITH($1,
|
||||
AC_HELP_STRING([--with-]$1[=PROG],
|
||||
AS_HELP_STRING([--with-]$1[=PROG],
|
||||
[use PROG as ]$1[ compressor program]),
|
||||
[tar_compr_var=${withval}],
|
||||
[tar_compr_var=m4_if($2,,$1,$2)])
|
||||
AC_DEFINE_UNQUOTED(tar_compr_define, "$tar_compr_var",
|
||||
[Define to the program name of ]$1[ compressor program])])
|
||||
|
||||
# Provide <attr/xattr.h>, if necessary
|
||||
|
||||
AC_DEFUN([TAR_HEADERS_ATTR_XATTR_H],
|
||||
[
|
||||
AC_ARG_WITH([xattrs],
|
||||
AS_HELP_STRING([--without-xattrs], [don't use linux extended attributes]),
|
||||
[], [with_xattrs=maybe]
|
||||
)
|
||||
|
||||
# First check for <sys/xattr.h>
|
||||
AC_CHECK_HEADERS([sys/xattr.h])
|
||||
AM_CONDITIONAL([TAR_COND_XATTR_H],[test "$ac_cv_header_sys_xattr_h" = yes])
|
||||
if test "$ac_cv_header_sys_xattr_h" != yes; then
|
||||
AC_CHECK_HEADERS([attr/xattr.h])
|
||||
AM_CONDITIONAL([TAR_COND_XATTR_H],[test "$ac_cv_header_attr_xattr_h" = yes])
|
||||
fi
|
||||
|
||||
if test "$with_xattrs" != no; then
|
||||
for i in getxattr fgetxattr lgetxattr \
|
||||
setxattr fsetxattr lsetxattr \
|
||||
listxattr flistxattr llistxattr
|
||||
do
|
||||
AC_SEARCH_LIBS($i, attr)
|
||||
eval found=\$ac_cv_search_$i
|
||||
test "$found" = "no" && break
|
||||
done
|
||||
|
||||
if test "$found" != no; then
|
||||
AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
# Bootstrap configuration for GNU tar.
|
||||
|
||||
# Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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 3, or (at your option)
|
||||
# any later version.
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
source_base=gnu
|
||||
gnulib_name=libgnu
|
||||
gnulib_mk=Makefile.am
|
||||
|
||||
# We don't need these modules, even though gnulib-tool mistakenly
|
||||
# includes them because of gettext dependencies.
|
||||
# We don't need these modules, even though gnulib-tool ordinarily
|
||||
# includes them because of dependencies on the modules 'exclude' and 'regex'.
|
||||
avoided_gnulib_modules='
|
||||
--avoid=lock
|
||||
--avoid=mbuiter
|
||||
--avoid=mbuiterf
|
||||
'
|
||||
|
||||
# gnulib modules used by this package.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep '^[^#]' gnulib.modules`
|
||||
"
|
||||
|
||||
# Additional xgettext options to use. Use "\\\newline" to break lines.
|
||||
XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
|
||||
@@ -65,10 +62,68 @@ if [ -r .bootstrap ]; then
|
||||
eval set -- "`sed 's/#.*$//;/^$/d' .bootstrap | tr '\n' ' '` $*"
|
||||
fi
|
||||
|
||||
test -d m4 || mkdir m4
|
||||
test -d $source_base || mkdir $source_base
|
||||
bootstrap_post_pull_hook() {
|
||||
mkdir -p m4 $source_base
|
||||
git submodule init
|
||||
git submodule update
|
||||
}
|
||||
|
||||
cat > ChangeLog <<EOT
|
||||
PAXUTILS=paxutils
|
||||
|
||||
# gnulib modules used by this package.
|
||||
# getopt-gnu is for paxutils.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep -h '^[^#]' gnulib.modules`
|
||||
getopt-gnu
|
||||
"
|
||||
|
||||
# copy_files srcdir dstdir
|
||||
copy_files() {
|
||||
for file in `cat $1/DISTFILES`
|
||||
do
|
||||
case $file in
|
||||
"#*") continue;;
|
||||
esac
|
||||
dst=`echo $file | sed 's^.*/^^'`
|
||||
if [ $# -eq 3 ]; then
|
||||
case $dst in
|
||||
${3}*) ;;
|
||||
*) dst=${3}$dst;;
|
||||
esac
|
||||
fi
|
||||
if [ "$2" = '.' ]; then
|
||||
ln -sf $1/$file $2
|
||||
else
|
||||
symlink_to_dir "$1" "$file" "$2/$dst" || exit
|
||||
fi
|
||||
# FIXME ignorefile $2 $dst
|
||||
done
|
||||
}
|
||||
|
||||
bootstrap_post_import_hook() {
|
||||
|
||||
test -f ChangeLog || cat > ChangeLog <<EOT
|
||||
This file is a placeholder. It will be replaced with the actual ChangeLog
|
||||
by make dist. Run make ChangeLog if you wish to create it earlier.
|
||||
EOT
|
||||
|
||||
# Import from paxutils
|
||||
copy_files ${PAXUTILS} .
|
||||
copy_files ${PAXUTILS}/am m4
|
||||
|
||||
echo "$0: Creating m4/paxutils.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([${package}_PAXUTILS],["
|
||||
cat ${PAXUTILS}/am/DISTFILES | sed '/^#/d;s/\(.*\)\.m4/pu_\1/' | tr a-z A-Z
|
||||
echo "])") > ./m4/paxutils.m4
|
||||
#FIXME ignorefile m4 paxutils.m4
|
||||
|
||||
mkdir -p rmt
|
||||
|
||||
for dir in doc rmt lib tests; do
|
||||
copy_files ${PAXUTILS}/$dir $dir
|
||||
done
|
||||
|
||||
copy_files ${PAXUTILS}/paxlib lib pax
|
||||
}
|
||||
|
||||
249
configure.ac
249
configure.ac
@@ -1,30 +1,28 @@
|
||||
# Configure template for GNU tar. -*- autoconf -*-
|
||||
|
||||
# Copyright (C) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright 1991, 1994-2010, 2013-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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 3, or (at your option)
|
||||
# any later version.
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT([GNU tar], [1.24], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.35], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREREQ([2.63])
|
||||
AM_INIT_AUTOMAKE([1.11 gnits tar-ustar dist-bzip2 dist-xz dist-shar std-options silent-rules])
|
||||
AC_PREREQ([2.71])
|
||||
AM_INIT_AUTOMAKE([1.15 gnits tar-ustar dist-bzip2 dist-xz std-options silent-rules])
|
||||
|
||||
# Enable silent rules by default:
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -34,69 +32,202 @@ AC_EXEEXT
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_YACC
|
||||
gl_EARLY
|
||||
AC_CHECK_TOOLS([AR], [ar])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_ISC_POSIX
|
||||
AC_C_INLINE
|
||||
AC_CHECK_HEADERS_ONCE([linux/fd.h sys/mtio.h])
|
||||
|
||||
AC_CHECK_HEADERS_ONCE(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 locale.h)
|
||||
|
||||
AC_CHECK_HEADERS([sys/buf.h], [], [],
|
||||
[#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif])
|
||||
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_MAJOR
|
||||
AC_HEADER_STAT
|
||||
AC_HEADER_STDC
|
||||
|
||||
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_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#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
|
||||
# even if we use gnulib's acl.h with integrated m4 file later on (used because
|
||||
# of very useful file_has_acl() function) we need following checks that restrict
|
||||
# tar to use POSIX.1e ACLs only.
|
||||
AC_ARG_WITH([posix-acls],
|
||||
AS_HELP_STRING([--without-posix-acls],
|
||||
[do not use POSIX.1e access control lists]),
|
||||
[],
|
||||
[with_posix_acls=yes])
|
||||
if test "x$with_posix_acls" != "xno"; then
|
||||
AC_CHECK_HEADERS(sys/acl.h,, [with_posix_acls=no])
|
||||
for tar_acl_func in acl_get_file acl_get_fd acl_set_file acl_set_fd \
|
||||
acl_to_text acl_from_text acl_delete_def_file \
|
||||
acl_free; do \
|
||||
test "x$with_posix_acls" = xno && break
|
||||
AC_SEARCH_LIBS([$tar_acl_func], [acl pacl], [], [with_posix_acls=no])
|
||||
done
|
||||
if test "x$with_posix_acls" != xno; then
|
||||
AC_DEFINE(HAVE_POSIX_ACLS,,[Define when we have working POSIX acls])
|
||||
fi
|
||||
else
|
||||
# disable acls in gnulib's checks
|
||||
export enable_acl=no
|
||||
fi
|
||||
|
||||
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)
|
||||
|
||||
# Taken from GNU/Linux, and should be good enough on platforms
|
||||
# lacking these types.
|
||||
AC_CHECK_TYPE([dev_t], [unsigned long long int])
|
||||
AC_CHECK_TYPE([ino_t], [unsigned long long int])
|
||||
|
||||
# Taken from GNU/Linux, and should be good enough on platforms
|
||||
# lacking these types.
|
||||
AC_CHECK_TYPE([major_t], [unsigned int])
|
||||
AC_CHECK_TYPE([minor_t], [unsigned int])
|
||||
|
||||
gt_TYPE_SSIZE_T
|
||||
|
||||
# gnulib modules
|
||||
gl_INIT
|
||||
|
||||
AC_DEFINE([GNULIB_EXCLUDE_SINGLE_THREAD], [1],
|
||||
[Define if all programs in this package call functions of the Gnulib
|
||||
'exclude' module only from a single thread.])
|
||||
AC_DEFINE([GNULIB_MBRTOWC_SINGLE_THREAD], [1],
|
||||
[Define if all programs in this package call functions of the Gnulib
|
||||
'mbtowc' module only from a single thread.])
|
||||
AC_DEFINE([GNULIB_REGEX_SINGLE_THREAD], [1],
|
||||
[Define if all programs in this package call functions of the Gnulib
|
||||
'regex' module only from a single thread.])
|
||||
AC_DEFINE([GNULIB_WCHAR_SINGLE_LOCALE], [1],
|
||||
[Define if all programs in this package call locale-sensitive functions
|
||||
like mbrtowc only after setting the locale, and never change the
|
||||
locale once set.])
|
||||
|
||||
if test $COMPILE_ERROR_C = 1; then
|
||||
# This means that Gnulib's 'error' function will be used. It precedes
|
||||
# error messages it prints with the program name as returned by getprogname()
|
||||
# call, instead of using the name set by set_program_name.
|
||||
# Install workaround.
|
||||
AC_DEFINE([ENABLE_ERROR_PRINT_PROGNAME],[1],
|
||||
[Enable the use of error_print_progname to print program name with error messages.
|
||||
See comment to function tar_print_progname in src/tar.c])
|
||||
fi
|
||||
|
||||
# paxutils modules
|
||||
tar_PAXUTILS
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
|
||||
AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
|
||||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||||
AC_CHECK_DECLS([time],,, [#include <time.h>])
|
||||
# gl_GCC_VERSION_IFELSE([major], [minor], [run-if-found], [run-if-not-found])
|
||||
# ------------------------------------------------
|
||||
# If $CPP is gcc-MAJOR.MINOR or newer, then run RUN-IF-FOUND.
|
||||
# Otherwise, run RUN-IF-NOT-FOUND.
|
||||
AC_DEFUN([gl_GCC_VERSION_IFELSE],
|
||||
[AC_PREPROC_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#if ($1) < __GNUC__ || (($1) == __GNUC__ && ($2) <= __GNUC_MINOR__)
|
||||
/* ok */
|
||||
#else
|
||||
# error "your version of gcc is older than $1.$2"
|
||||
#endif
|
||||
]]),
|
||||
], [$3], [$4])
|
||||
]
|
||||
)
|
||||
|
||||
AC_REPLACE_FUNCS(waitpid)
|
||||
AC_ARG_ENABLE([gcc-warnings],
|
||||
[AS_HELP_STRING([--enable-gcc-warnings],
|
||||
[turn on many GCC warnings (for developers; best with GNU make)])],
|
||||
[case $enableval in
|
||||
yes|no) ;;
|
||||
*) AC_MSG_ERROR([bad value $enableval for gcc-warnings option]) ;;
|
||||
esac
|
||||
gl_gcc_warnings=$enableval],
|
||||
[gl_gcc_warnings=no
|
||||
if test -d "$srcdir"/.git; then
|
||||
gl_GCC_VERSION_IFELSE([11], [2], [gl_gcc_warnings=yes])
|
||||
fi]
|
||||
)
|
||||
|
||||
if test "$gl_gcc_warnings" = yes; then
|
||||
gl_WARN_ADD([-Werror], [WERROR_CFLAGS])
|
||||
AC_SUBST([WERROR_CFLAGS])
|
||||
|
||||
nw=
|
||||
# This, $nw, is the list of warnings we disable.
|
||||
nw="$nw -Wformat-nonliteral" # warnings in Fedora 17 stdio.h
|
||||
nw="$nw -Wvla" # warnings in gettext.h
|
||||
nw="$nw -Wswitch-default" # Too many warnings for now
|
||||
nw="$nw -Wunsafe-loop-optimizations" # It's OK to omit unsafe optimizations.
|
||||
nw="$nw -Winline" # It's OK to not inline.
|
||||
nw="$nw -Wstrict-overflow" # It's OK to optimize strictly.
|
||||
nw="$nw -Wsuggest-attribute=pure" # Too many warnings for now.
|
||||
nw="$nw -Wstack-protector"
|
||||
|
||||
gl_MANYWARN_ALL_GCC([ws])
|
||||
gl_MANYWARN_COMPLEMENT([ws], [$ws], [$nw])
|
||||
for w in $ws; do
|
||||
gl_WARN_ADD([$w])
|
||||
done
|
||||
gl_WARN_ADD([-Wno-sign-compare]) # Too many warnings for now
|
||||
gl_WARN_ADD([-Wno-type-limits]) # It's OK to optimize based on types.
|
||||
gl_WARN_ADD([-Wno-format-nonliteral])
|
||||
|
||||
gl_WARN_ADD([-fdiagnostics-show-option])
|
||||
gl_WARN_ADD([-funit-at-a-time])
|
||||
|
||||
|
||||
AC_SUBST([WARN_CFLAGS])
|
||||
|
||||
AC_DEFINE([lint], [1], [Define to 1 if the compiler is checking for lint.])
|
||||
AH_VERBATIM([FORTIFY_SOURCE],
|
||||
[/* Enable compile-time and run-time bounds-checking, and some warnings,
|
||||
without upsetting glibc 2.15+. */
|
||||
#if !defined _FORTIFY_SOURCE && defined __OPTIMIZE__ && __OPTIMIZE__
|
||||
# define _FORTIFY_SOURCE 2
|
||||
#endif
|
||||
])
|
||||
AC_DEFINE([GNULIB_PORTCHECK], [1], [enable some gnulib portability checks])
|
||||
|
||||
# Use a slightly smaller set of warning options for lib/.
|
||||
# Remove the following and save the result in GNULIB_WARN_CFLAGS.
|
||||
nw=
|
||||
nw="$nw -Wmissing-prototypes"
|
||||
nw="$nw -Wunused-macros"
|
||||
#
|
||||
# These are for argp.
|
||||
nw="$nw -Wmissing-field-initializers"
|
||||
nw="$nw -Wshadow"
|
||||
#
|
||||
gl_MANYWARN_COMPLEMENT([GNULIB_WARN_CFLAGS], [$WARN_CFLAGS], [$nw])
|
||||
|
||||
# This is also for argp.
|
||||
gl_WARN_ADD([-Wno-missing-field-initializers], [GNULIB_WARN_CFLAGS])
|
||||
|
||||
AC_SUBST([GNULIB_WARN_CFLAGS])
|
||||
|
||||
# For gnulib-tests, the set is slightly smaller still.
|
||||
nw=
|
||||
# It's not worth being this picky about test programs.
|
||||
nw="$nw -Wsuggest-attribute=const"
|
||||
gl_MANYWARN_COMPLEMENT([GNULIB_TEST_WARN_CFLAGS],
|
||||
[$GNULIB_WARN_CFLAGS], [$nw])
|
||||
AC_SUBST([GNULIB_TEST_WARN_CFLAGS])
|
||||
fi
|
||||
|
||||
TAR_HEADERS_ATTR_XATTR_H
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([fchmod fchown fsync mkfifo waitpid])
|
||||
|
||||
AC_ARG_VAR([RSH], [Configure absolute path to default remote shell binary])
|
||||
AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
|
||||
[if test -n "$RSH"; then
|
||||
tar_cv_path_RSH=$RSH
|
||||
@@ -118,9 +249,7 @@ AC_CACHE_CHECK(for remote shell, tar_cv_path_RSH,
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
if test $tar_cv_path_RSH = no; then
|
||||
AC_CHECK_HEADERS(netdb.h)
|
||||
else
|
||||
if test $tar_cv_path_RSH != "no"; then
|
||||
AC_DEFINE_UNQUOTED(REMOTE_SHELL, "$tar_cv_path_RSH",
|
||||
[Define to the full path of your rsh, if any.])
|
||||
fi
|
||||
@@ -132,6 +261,7 @@ TAR_COMPR_PROGRAM(lzip)
|
||||
TAR_COMPR_PROGRAM(lzma)
|
||||
TAR_COMPR_PROGRAM(lzop)
|
||||
TAR_COMPR_PROGRAM(xz)
|
||||
TAR_COMPR_PROGRAM(zstd)
|
||||
|
||||
AC_MSG_CHECKING(for default archive format)
|
||||
|
||||
@@ -157,7 +287,7 @@ if test -z "$DEFAULT_ARCHIVE"; then
|
||||
DEFAULT_ARCHIVE=-
|
||||
else
|
||||
if test -z "`ls $DEFAULT_ARCHIVE 2>/dev/null`"; then
|
||||
AC_MSG_WARN(DEFAULT_ARCHIVE \`$DEFAULT_ARCHIVE' not found on this system)
|
||||
AC_MSG_WARN(DEFAULT_ARCHIVE '$DEFAULT_ARCHIVE' not found on this system)
|
||||
fi
|
||||
# FIXME: Look for DEFTAPE in <sys/mtio.h>.
|
||||
# FIXME: Let DEVICE_PREFIX be configured from the environment.
|
||||
@@ -213,7 +343,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_QUOTING_STYLE, $DEFAULT_QUOTING_STYLE,
|
||||
|
||||
# Iconv
|
||||
AM_ICONV
|
||||
AC_CHECK_HEADERS(iconv.h)
|
||||
AC_CHECK_HEADERS_ONCE([iconv.h])
|
||||
AC_CHECK_TYPE(iconv_t,:,
|
||||
AC_DEFINE(iconv_t, int,
|
||||
[Conversion descriptor type]),
|
||||
@@ -225,7 +355,7 @@ AC_CHECK_TYPE(iconv_t,:,
|
||||
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-formatstring-macros])
|
||||
AM_GNU_GETTEXT_VERSION([0.16])
|
||||
AM_GNU_GETTEXT_VERSION([0.21])
|
||||
|
||||
# Initialize the test suite.
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
@@ -235,8 +365,8 @@ AM_MISSING_PROG([AUTOM4TE], [autom4te])
|
||||
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]),
|
||||
AS_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)'
|
||||
@@ -250,7 +380,7 @@ else
|
||||
BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d'
|
||||
fi
|
||||
|
||||
AC_OUTPUT([Makefile\
|
||||
AC_CONFIG_FILES([Makefile\
|
||||
doc/Makefile\
|
||||
gnu/Makefile\
|
||||
lib/Makefile\
|
||||
@@ -258,3 +388,4 @@ AC_OUTPUT([Makefile\
|
||||
scripts/Makefile\
|
||||
rmt/Makefile\
|
||||
src/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
12
directory
12
directory
@@ -1,11 +1,11 @@
|
||||
%%comments:
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
Copyright 2004-2025 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2 or
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
Texts. A copy of the license is included in the file COPYING.
|
||||
Texts. For a copy of the license, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
%%name: tar
|
||||
|
||||
@@ -59,12 +59,12 @@ programs (using pipes); tar can even access remote devices or files
|
||||
%%developers:
|
||||
John Gilmore,
|
||||
Thomas Bushnell,
|
||||
Paul Eggert <eggert@twinsun.com>,
|
||||
Sergey Poznyakoff <gray@Mirddin.farlep.net>
|
||||
Paul Eggert <eggert@cs.ucla.edu>,
|
||||
Sergey Poznyakoff <gray@gnu.org>
|
||||
|
||||
%%contributors: Jay Fenlason,
|
||||
Joy Kendall,
|
||||
Francois Pinard <pinard@iro.umontreal.ca>
|
||||
François Pinard
|
||||
|
||||
%%source-tarball: ftp://ftp.gnu.org/pub/gnu/tar/tar-1.15.1.tar.gz
|
||||
%%source-info: http://savannah.gnu.org/projects/tar
|
||||
|
||||
3
doc/.gitignore
vendored
3
doc/.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
genfile.texi
|
||||
header.texi
|
||||
manual
|
||||
parse-datetime.texi
|
||||
stamp-vti
|
||||
tar.aux
|
||||
tar.cp
|
||||
@@ -24,3 +23,5 @@ tar.toc
|
||||
tar.tp
|
||||
tar.vr
|
||||
version.texi
|
||||
/parse-datetime.texi
|
||||
/rmt.8
|
||||
|
||||
@@ -1,40 +1,46 @@
|
||||
# Makefile for GNU tar documentation.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2006,
|
||||
# 2007 Free Software Foundation, Inc.
|
||||
# Copyright 1994-2025 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 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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 3 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
# 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
info_TEXINFOS = tar.texi
|
||||
tar_TEXINFOS = \
|
||||
dumpdir.texi\
|
||||
tar-snapshot-edit.texi\
|
||||
fdl.texi\
|
||||
freemanuals.texi\
|
||||
genfile.texi\
|
||||
header.texi\
|
||||
intern.texi\
|
||||
parse-datetime.texi\
|
||||
recipes.texi\
|
||||
rendition.texi\
|
||||
snapshot.texi\
|
||||
sparse.texi\
|
||||
value.texi
|
||||
EXTRA_DIST = gendocs_template mastermenu.el texify.sed untabify.el
|
||||
|
||||
dist_man_MANS=tar.1 $(RMT_8)
|
||||
if PU_RMT_COND
|
||||
RMT_8=rmt.8
|
||||
endif
|
||||
|
||||
EXTRA_DIST = gendocs_template mastermenu.el texify.sed untabify.el rmt.8
|
||||
|
||||
# The rendering level is anyone of PUBLISH, DISTRIB or PROOF.
|
||||
# Just call `make RENDITION=PROOF [target]' if you want PROOF rendition.
|
||||
# Just call 'make RENDITION=PROOF [target]' if you want PROOF rendition.
|
||||
RENDITION = DISTRIB
|
||||
|
||||
MAKEINFOFLAGS=-D$(RENDITION)
|
||||
@@ -132,9 +138,9 @@ check-docs:
|
||||
clean-local:
|
||||
rm -rf manual
|
||||
|
||||
GENDOCS=gendocs.sh
|
||||
GENDOCS=$(srcdir)/gendocs.sh
|
||||
|
||||
TEXI2DVI=texi2dvi -t '@set $(RENDITION)' -E
|
||||
TEXI2DVI=texi2dvi -E
|
||||
|
||||
# Make sure you set TEXINPUTS
|
||||
# Usual value is:
|
||||
@@ -142,5 +148,8 @@ TEXI2DVI=texi2dvi -t '@set $(RENDITION)' -E
|
||||
manual:
|
||||
TEXINPUTS=$(srcdir):$(top_srcdir)/build-tex:$(TEXINPUTS) \
|
||||
MAKEINFO="$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
TEXI2DVI="$(TEXI2DVI) -t @finalout" \
|
||||
TEXI2DVI="$(TEXI2DVI) -t '@set DISTRIB' -t @finalout" \
|
||||
$(GENDOCS) --texi2html tar 'GNU tar manual'
|
||||
|
||||
manual-rebuild: clean-local manual
|
||||
|
||||
|
||||
91
doc/README.manual
Normal file
91
doc/README.manual
Normal file
@@ -0,0 +1,91 @@
|
||||
* Overview
|
||||
|
||||
This file is a short instruction for maintainers on how to create and
|
||||
publish the online version of the Tar Manual.
|
||||
|
||||
In the sections below we assume that the tar project has been properly
|
||||
cloned from the git repo, bootstrapped and configured. We also assume
|
||||
that top-level directory of the project is the current local directory.
|
||||
|
||||
* Creating the web manual
|
||||
|
||||
To create the online version of the documentation, run
|
||||
|
||||
make -C doc manual-rebuild
|
||||
|
||||
This will create the directory doc/manual populated with the tar
|
||||
documentation files in various formats. If the doc/manual directory
|
||||
already exists, it will be removed prior to rebuilding.
|
||||
|
||||
The command produces very copious output. We advise you to examine it
|
||||
closely to make sure no error messages slip your attention.
|
||||
|
||||
For the completeness sake, there are two more Makefile goals related
|
||||
to the online manual:
|
||||
|
||||
** make -C doc clean-local
|
||||
|
||||
Removes the doc/manual directory, if it exists.
|
||||
|
||||
** make -C doc manual
|
||||
|
||||
Builds the doc/manual, unless it already exists.
|
||||
|
||||
* CVS Repository
|
||||
|
||||
The online tar manual[1] is a part of tar web pages[2] and is
|
||||
traditionally maintained in the CVS repository[3]. To publish the
|
||||
generated documentation, you will need first to check out tar web
|
||||
pages from the CVS. To do so, run
|
||||
|
||||
cvs -z3 -d:ext:<username>@cvs.savannah.gnu.org:/web/tar co tar
|
||||
|
||||
where <username> is your user name on Savannah. For the rest of this
|
||||
document we will assume that the checked out version of the tar web
|
||||
pages resides in the ~/websrc/tar directory.
|
||||
|
||||
If you have already checked out the web pages, be sure to update them
|
||||
before publishing:
|
||||
|
||||
cd ~/websrc/tar
|
||||
cvs update
|
||||
|
||||
* Publishing
|
||||
|
||||
To publish the created manual, change to the tar top-level directory
|
||||
and run:
|
||||
|
||||
rsync -avz --exclude CVS --delete manual ~/websrc/tar
|
||||
|
||||
This will synchronize the newly created manual pages with the content
|
||||
of the CVS sandbox. Then, change to the ~/websrc/tar directory and
|
||||
schedule any removed files for removal and any new files for addition
|
||||
to the repository:
|
||||
|
||||
cvs diff --brief 2>&1 | sed -n 's/.*cannot find //p' | xargs cvs rm
|
||||
cvs diff --brief 2>&1 | sed -n 's/^? //p' | xargs cvs add
|
||||
|
||||
Then commit your changes:
|
||||
|
||||
cvs commit
|
||||
|
||||
Once the changes are committed to CVS a job is scheduled on the server,
|
||||
which synchronizes them with the content of the directory served by
|
||||
the httpd daemon. Normally such synchronization happens within
|
||||
several seconds from the commit.
|
||||
|
||||
For more information about CVS, please see its documentation[4].
|
||||
|
||||
* References
|
||||
|
||||
[1] https://www.gnu.org/software/tar/manual/
|
||||
[2] https://www.gnu.org/software/tar/
|
||||
[3] https://web.cvs.savannah.gnu.org/viewvc/tar/
|
||||
[4] https://www.nongnu.org/cvs/#documentation
|
||||
|
||||
|
||||
Local Variables:
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
version-control: never
|
||||
End:
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2025 Free Software Foundation, Inc.
|
||||
@c Written by Sergey Poznyakoff
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
12
doc/fdl.texi
12
doc/fdl.texi
@@ -5,8 +5,9 @@
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
Copyright @copyright{} 2000--2002, 2007--2008, 2022 Free Software
|
||||
Foundation, Inc.
|
||||
@uref{https://fsf.org/}
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
@@ -97,7 +98,7 @@ format, SGML or XML using a publicly available
|
||||
DTD, and standard-conforming simple HTML,
|
||||
PostScript or PDF designed for human modification. Examples
|
||||
of transparent image formats include PNG, XCF and
|
||||
JPG. Opaque formats include proprietary formats that can be
|
||||
JPG@. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, SGML or
|
||||
XML for which the DTD and/or processing tools are
|
||||
not generally available, and the machine-generated HTML,
|
||||
@@ -414,7 +415,7 @@ 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/}.
|
||||
@uref{https://www.gnu.org/licenses/}.
|
||||
|
||||
Each version of the License is given a distinguishing version number.
|
||||
If the Document specifies that a particular numbered version of this
|
||||
@@ -481,7 +482,7 @@ license notices just after the title page:
|
||||
@end smallexample
|
||||
|
||||
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
|
||||
replace the ``with@dots{}Texts.'' line with this:
|
||||
replace the ``with@dots{}Texts.''@: line with this:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -503,4 +504,3 @@ to permit their use in free software.
|
||||
@c Local Variables:
|
||||
@c ispell-local-pdict: "ispell-dict"
|
||||
@c End:
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
@cindex free documentation
|
||||
|
||||
The biggest deficiency in the free software community today is not in
|
||||
the software---it is the lack of good free documentation that we can
|
||||
include with the free software. Many of our most important
|
||||
programs do not come with free reference manuals and free introductory
|
||||
texts. Documentation is an essential part of any software package;
|
||||
when an important free software package does not come with a free
|
||||
manual and a free tutorial, that is a major gap. We have many such
|
||||
gaps today.
|
||||
|
||||
Consider Perl, for instance. The tutorial manuals that people
|
||||
normally use are non-free. How did this come about? Because the
|
||||
authors of those manuals published them with restrictive terms---no
|
||||
copying, no modification, source files not available---which exclude
|
||||
them from the free software world.
|
||||
|
||||
That wasn't the first time this sort of thing happened, and it was far
|
||||
from the last. Many times we have heard a GNU user eagerly describe a
|
||||
manual that he is writing, his intended contribution to the community,
|
||||
only to learn that he had ruined everything by signing a publication
|
||||
contract to make it non-free.
|
||||
|
||||
Free documentation, like free software, is a matter of freedom, not
|
||||
price. The problem with the non-free manual is not that publishers
|
||||
charge a price for printed copies---that in itself is fine. (The Free
|
||||
Software Foundation sells printed copies of manuals, too.) The
|
||||
problem is the restrictions on the use of the manual. Free manuals
|
||||
are available in source code form, and give you permission to copy and
|
||||
modify. Non-free manuals do not allow this.
|
||||
|
||||
The criteria of freedom for a free manual are roughly the same as for
|
||||
free software. Redistribution (including the normal kinds of
|
||||
commercial redistribution) must be permitted, so that the manual can
|
||||
accompany every copy of the program, both on-line and on paper.
|
||||
|
||||
Permission for modification of the technical content is crucial too.
|
||||
When people modify the software, adding or changing features, if they
|
||||
are conscientious they will change the manual too---so they can
|
||||
provide accurate and clear documentation for the modified program. A
|
||||
manual that leaves you no choice but to write a new manual to document
|
||||
a changed version of the program is not really available to our
|
||||
community.
|
||||
|
||||
Some kinds of limits on the way modification is handled are
|
||||
acceptable. For example, requirements to preserve the original
|
||||
author's copyright notice, the distribution terms, or the list of
|
||||
authors, are ok. It is also no problem to require modified versions
|
||||
to include notice that they were modified. Even entire sections that
|
||||
may not be deleted or changed are acceptable, as long as they deal
|
||||
with nontechnical topics (like this one). These kinds of restrictions
|
||||
are acceptable because they don't obstruct the community's normal use
|
||||
of the manual.
|
||||
|
||||
However, it must be possible to modify all the @emph{technical}
|
||||
content of the manual, and then distribute the result in all the usual
|
||||
media, through all the usual channels. Otherwise, the restrictions
|
||||
obstruct the use of the manual, it is not free, and we need another
|
||||
manual to replace it.
|
||||
|
||||
Please spread the word about this issue. Our community continues to
|
||||
lose manuals to proprietary publishing. If we spread the word that
|
||||
free software needs free reference manuals and free tutorials, perhaps
|
||||
the next person who wants to contribute by writing documentation will
|
||||
realize, before it is too late, that only free manuals contribute to
|
||||
the free software community.
|
||||
|
||||
If you are writing documentation, please insist on publishing it under
|
||||
the GNU Free Documentation License or another free documentation
|
||||
license. Remember that this decision requires your approval---you
|
||||
don't have to let the publisher decide. Some commercial publishers
|
||||
will use a free license if you insist, but they will not propose the
|
||||
option; it is up to you to raise the issue and say firmly that this is
|
||||
what you want. If the publisher you are dealing with refuses, please
|
||||
try other publishers. If you're not sure whether a proposed license
|
||||
is free, write to @email{licensing@@gnu.org}.
|
||||
|
||||
You can encourage commercial publishers to sell more free, copylefted
|
||||
manuals and tutorials by buying them, and particularly by buying
|
||||
copies from the publishers that paid for their writing or for major
|
||||
improvements. Meanwhile, try to avoid buying non-free documentation
|
||||
at all. Check the distribution terms of a manual before you buy it,
|
||||
and insist that whoever seeks your business must respect your freedom.
|
||||
Check the history of the book, and try reward the publishers that have
|
||||
paid or pay the authors to work on it.
|
||||
|
||||
The Free Software Foundation maintains a list of free documentation
|
||||
published by other publishers, at
|
||||
@url{http://www.fsf.org/doc/other-free-books.html}.
|
||||
512
doc/gendocs.sh
Executable file
512
doc/gendocs.sh
Executable file
@@ -0,0 +1,512 @@
|
||||
#!/bin/sh -e
|
||||
# gendocs.sh -- generate a GNU manual in many formats. This script is
|
||||
# mentioned in maintain.texi. See the help message below for usage details.
|
||||
|
||||
scriptversion=2021-03-01.13
|
||||
|
||||
# Copyright 2003-2025 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 3 of the License, 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, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Original author: Mohit Agarwal.
|
||||
# Send bug reports and any other correspondence to bug-gnulib@gnu.org.
|
||||
#
|
||||
# The latest version of this script, and the companion template, is
|
||||
# available from the Gnulib repository:
|
||||
#
|
||||
# https://git.savannah.gnu.org/cgit/gnulib.git/tree/build-aux/gendocs.sh
|
||||
# https://git.savannah.gnu.org/cgit/gnulib.git/tree/doc/gendocs_template
|
||||
|
||||
# TODO:
|
||||
# - image importing was only implemented for HTML generated by
|
||||
# makeinfo. But it should be simple enough to adjust.
|
||||
# - images are not imported in the source tarball. All the needed
|
||||
# formats (PDF, PNG, etc.) should be included.
|
||||
|
||||
prog=`basename "$0"`
|
||||
srcdir=`pwd`
|
||||
|
||||
scripturl="https://git.savannah.gnu.org/cgit/gnulib.git/plain/build-aux/gendocs.sh"
|
||||
templateurl="https://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/gendocs_template"
|
||||
|
||||
: ${SETLANG="env LANG= LC_MESSAGES= LC_ALL= LANGUAGE="}
|
||||
: ${MAKEINFO="makeinfo"}
|
||||
: ${TEXI2DVI="texi2dvi"}
|
||||
: ${DOCBOOK2HTML="docbook2html"}
|
||||
: ${DOCBOOK2PDF="docbook2pdf"}
|
||||
: ${DOCBOOK2TXT="docbook2txt"}
|
||||
: ${GENDOCS_TEMPLATE_DIR="."}
|
||||
: ${PERL='perl'}
|
||||
: ${TEXI2HTML="texi2html"}
|
||||
unset CDPATH
|
||||
unset use_texi2html
|
||||
|
||||
MANUAL_TITLE=
|
||||
PACKAGE=
|
||||
EMAIL=webmasters@gnu.org # please override with --email
|
||||
commonarg= # passed to all makeinfo/texi2html invcations.
|
||||
dirargs= # passed to all tools (-I dir).
|
||||
dirs= # -I directories.
|
||||
htmlarg="--css-ref=/software/gnulib/manual.css -c TOP_NODE_UP_URL=/manual"
|
||||
default_htmlarg=true
|
||||
infoarg=--no-split
|
||||
generate_ascii=true
|
||||
generate_html=true
|
||||
generate_info=true
|
||||
generate_tex=true
|
||||
outdir=manual
|
||||
source_extra=
|
||||
split=node
|
||||
srcfile=
|
||||
texarg="-t @finalout"
|
||||
|
||||
version="gendocs.sh $scriptversion
|
||||
|
||||
Copyright 2021, 2025 Free Software Foundation, Inc.
|
||||
There is NO warranty. You may redistribute this software
|
||||
under the terms of the GNU General Public License.
|
||||
For more information about these matters, see the files named COPYING."
|
||||
|
||||
usage="Usage: $prog [OPTION]... PACKAGE MANUAL-TITLE
|
||||
|
||||
Generate output in various formats from PACKAGE.texinfo (or .texi or
|
||||
.txi) source. See the GNU Maintainers document for a more extensive
|
||||
discussion:
|
||||
https://www.gnu.org/prep/maintain_toc.html
|
||||
|
||||
Options:
|
||||
--email ADR use ADR as contact in generated web pages; always give this.
|
||||
|
||||
-s SRCFILE read Texinfo from SRCFILE, instead of PACKAGE.{texinfo|texi|txi}
|
||||
-o OUTDIR write files into OUTDIR, instead of manual/.
|
||||
-I DIR append DIR to the Texinfo search path.
|
||||
--common ARG pass ARG in all invocations.
|
||||
--html ARG pass ARG to makeinfo or texi2html for HTML targets,
|
||||
instead of '$htmlarg'.
|
||||
--info ARG pass ARG to makeinfo for Info, instead of --no-split.
|
||||
--no-ascii skip generating the plain text output.
|
||||
--no-html skip generating the html output.
|
||||
--no-info skip generating the info output.
|
||||
--no-tex skip generating the dvi and pdf output.
|
||||
--source ARG include ARG in tar archive of sources.
|
||||
--split HOW make split HTML by node, section, chapter; default node.
|
||||
--tex ARG pass ARG to texi2dvi for DVI and PDF, instead of -t @finalout.
|
||||
|
||||
--texi2html use texi2html to make HTML target, with all split versions.
|
||||
--docbook convert through DocBook too (xml, txt, html, pdf).
|
||||
|
||||
--help display this help and exit successfully.
|
||||
--version display version information and exit successfully.
|
||||
|
||||
Simple example: $prog --email bug-gnu-emacs@gnu.org emacs \"GNU Emacs Manual\"
|
||||
|
||||
Typical sequence:
|
||||
cd PACKAGESOURCE/doc
|
||||
wget \"$scripturl\"
|
||||
wget \"$templateurl\"
|
||||
$prog --email BUGLIST MANUAL \"GNU MANUAL - One-line description\"
|
||||
|
||||
Output will be in a new subdirectory \"manual\" (by default;
|
||||
use -o OUTDIR to override). Move all the new files into your web CVS
|
||||
tree, as explained in the Web Pages node of maintain.texi.
|
||||
|
||||
Please use the --email ADDRESS option so your own bug-reporting
|
||||
address will be used in the generated HTML pages.
|
||||
|
||||
MANUAL-TITLE is included as part of the HTML <title> of the overall
|
||||
manual/index.html file. It should include the name of the package being
|
||||
documented. manual/index.html is created by substitution from the file
|
||||
$GENDOCS_TEMPLATE_DIR/gendocs_template. (Feel free to modify the
|
||||
generic template for your own purposes.)
|
||||
|
||||
If you have several manuals, you'll need to run this script several
|
||||
times with different MANUAL values, specifying a different output
|
||||
directory with -o each time. Then write (by hand) an overall index.html
|
||||
with links to them all.
|
||||
|
||||
If a manual's Texinfo sources are spread across several directories,
|
||||
first copy or symlink all Texinfo sources into a single directory.
|
||||
(Part of the script's work is to make a tar.gz of the sources.)
|
||||
|
||||
As implied above, by default monolithic Info files are generated.
|
||||
If you want split Info, or other Info options, use --info to override.
|
||||
|
||||
You can set the environment variables MAKEINFO, TEXI2DVI, TEXI2HTML,
|
||||
and PERL to control the programs that get executed, and
|
||||
GENDOCS_TEMPLATE_DIR to control where the gendocs_template file is
|
||||
looked for. With --docbook, the environment variables DOCBOOK2HTML,
|
||||
DOCBOOK2PDF, and DOCBOOK2TXT are also consulted.
|
||||
|
||||
By default, makeinfo and texi2dvi are run in the default (English)
|
||||
locale, since that's the language of most Texinfo manuals. If you
|
||||
happen to have a non-English manual and non-English web site, see the
|
||||
SETLANG setting in the source.
|
||||
|
||||
Email bug reports or enhancement requests to bug-gnulib@gnu.org.
|
||||
"
|
||||
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
-s) shift; srcfile=$1;;
|
||||
-o) shift; outdir=$1;;
|
||||
-I) shift; dirargs="$dirargs -I '$1'"; dirs="$dirs $1";;
|
||||
--common) shift; commonarg=$1;;
|
||||
--docbook) docbook=yes;;
|
||||
--email) shift; EMAIL=$1;;
|
||||
--html) shift; default_htmlarg=false; htmlarg=$1;;
|
||||
--info) shift; infoarg=$1;;
|
||||
--no-ascii) generate_ascii=false;;
|
||||
--no-html) generate_ascii=false;;
|
||||
--no-info) generate_info=false;;
|
||||
--no-tex) generate_tex=false;;
|
||||
--source) shift; source_extra=$1;;
|
||||
--split) shift; split=$1;;
|
||||
--tex) shift; texarg=$1;;
|
||||
--texi2html) use_texi2html=1;;
|
||||
|
||||
--help) echo "$usage"; exit 0;;
|
||||
--version) echo "$version"; exit 0;;
|
||||
-*)
|
||||
echo "$0: Unknown option \`$1'." >&2
|
||||
echo "$0: Try \`--help' for more information." >&2
|
||||
exit 1;;
|
||||
*)
|
||||
if test -z "$PACKAGE"; then
|
||||
PACKAGE=$1
|
||||
elif test -z "$MANUAL_TITLE"; then
|
||||
MANUAL_TITLE=$1
|
||||
else
|
||||
echo "$0: extra non-option argument \`$1'." >&2
|
||||
exit 1
|
||||
fi;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# makeinfo uses the dirargs, but texi2dvi doesn't.
|
||||
commonarg=" $dirargs $commonarg"
|
||||
|
||||
# For most of the following, the base name is just $PACKAGE
|
||||
base=$PACKAGE
|
||||
|
||||
if $default_htmlarg && test -n "$use_texi2html"; then
|
||||
# The legacy texi2html doesn't support TOP_NODE_UP_URL
|
||||
htmlarg="--css-ref=/software/gnulib/manual.css"
|
||||
fi
|
||||
|
||||
if test -n "$srcfile"; then
|
||||
# but here, we use the basename of $srcfile
|
||||
base=`basename "$srcfile"`
|
||||
case $base in
|
||||
*.txi|*.texi|*.texinfo) base=`echo "$base"|sed 's/\.[texinfo]*$//'`;;
|
||||
esac
|
||||
PACKAGE=$base
|
||||
elif test -s "$srcdir/$PACKAGE.texinfo"; then
|
||||
srcfile=$srcdir/$PACKAGE.texinfo
|
||||
elif test -s "$srcdir/$PACKAGE.texi"; then
|
||||
srcfile=$srcdir/$PACKAGE.texi
|
||||
elif test -s "$srcdir/$PACKAGE.txi"; then
|
||||
srcfile=$srcdir/$PACKAGE.txi
|
||||
else
|
||||
echo "$0: cannot find .texinfo or .texi or .txi for $PACKAGE in $srcdir." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test ! -r $GENDOCS_TEMPLATE_DIR/gendocs_template; then
|
||||
echo "$0: cannot read $GENDOCS_TEMPLATE_DIR/gendocs_template." >&2
|
||||
echo "$0: it is available from $templateurl." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to return size of $1 in something resembling kilobytes.
|
||||
calcsize()
|
||||
{
|
||||
size=`ls -ksl $1 | awk '{print $1}'`
|
||||
echo $size
|
||||
}
|
||||
|
||||
# copy_images OUTDIR HTML-FILE...
|
||||
# -------------------------------
|
||||
# Copy all the images needed by the HTML-FILEs into OUTDIR.
|
||||
# Look for them in . and the -I directories; this is simpler than what
|
||||
# makeinfo supports with -I, but hopefully it will suffice.
|
||||
copy_images()
|
||||
{
|
||||
local odir
|
||||
odir=$1
|
||||
shift
|
||||
$PERL -n -e "
|
||||
BEGIN {
|
||||
\$me = '$prog';
|
||||
\$odir = '$odir';
|
||||
@dirs = qw(. $dirs);
|
||||
}
|
||||
" -e '
|
||||
/<img src="(.*?)"/g && ++$need{$1};
|
||||
|
||||
END {
|
||||
#print "$me: @{[keys %need]}\n"; # for debugging, show images found.
|
||||
FILE: for my $f (keys %need) {
|
||||
for my $d (@dirs) {
|
||||
if (-f "$d/$f") {
|
||||
use File::Basename;
|
||||
my $dest = dirname ("$odir/$f");
|
||||
#
|
||||
use File::Path;
|
||||
-d $dest || mkpath ($dest)
|
||||
|| die "$me: cannot mkdir $dest: $!\n";
|
||||
#
|
||||
use File::Copy;
|
||||
copy ("$d/$f", $dest)
|
||||
|| die "$me: cannot copy $d/$f to $dest: $!\n";
|
||||
next FILE;
|
||||
}
|
||||
}
|
||||
die "$me: $ARGV: cannot find image $f\n";
|
||||
}
|
||||
}
|
||||
' -- "$@" || exit 1
|
||||
}
|
||||
|
||||
case $outdir in
|
||||
/*) abs_outdir=$outdir;;
|
||||
*) abs_outdir=$srcdir/$outdir;;
|
||||
esac
|
||||
|
||||
echo "Making output for $srcfile"
|
||||
echo " in `pwd`"
|
||||
mkdir -p "$outdir/"
|
||||
|
||||
#
|
||||
if $generate_info; then
|
||||
cmd="$SETLANG $MAKEINFO -o $PACKAGE.info $commonarg $infoarg \"$srcfile\""
|
||||
echo "Generating info... ($cmd)"
|
||||
rm -f $PACKAGE.info* # get rid of any strays
|
||||
eval "$cmd"
|
||||
tar czf "$outdir/$PACKAGE.info.tar.gz" $PACKAGE.info*
|
||||
ls -l "$outdir/$PACKAGE.info.tar.gz"
|
||||
info_tgz_size=`calcsize "$outdir/$PACKAGE.info.tar.gz"`
|
||||
# do not mv the info files, there's no point in having them available
|
||||
# separately on the web.
|
||||
fi # end info
|
||||
|
||||
#
|
||||
if $generate_tex; then
|
||||
cmd="$SETLANG $TEXI2DVI $dirargs $texarg \"$srcfile\""
|
||||
printf "\nGenerating dvi... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
# compress/finish dvi:
|
||||
gzip -f -9 $PACKAGE.dvi
|
||||
dvi_gz_size=`calcsize $PACKAGE.dvi.gz`
|
||||
mv $PACKAGE.dvi.gz "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.dvi.gz"
|
||||
|
||||
cmd="$SETLANG $TEXI2DVI --pdf $dirargs $texarg \"$srcfile\""
|
||||
printf "\nGenerating pdf... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
pdf_size=`calcsize $PACKAGE.pdf`
|
||||
mv $PACKAGE.pdf "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.pdf"
|
||||
fi # end tex (dvi + pdf)
|
||||
|
||||
#
|
||||
if $generate_ascii; then
|
||||
opt="-o $PACKAGE.txt --no-split --no-headers $commonarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
|
||||
printf "\nGenerating ascii... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
ascii_size=`calcsize $PACKAGE.txt`
|
||||
gzip -f -9 -c $PACKAGE.txt >"$outdir/$PACKAGE.txt.gz"
|
||||
ascii_gz_size=`calcsize "$outdir/$PACKAGE.txt.gz"`
|
||||
mv $PACKAGE.txt "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.txt" "$outdir/$PACKAGE.txt.gz"
|
||||
fi
|
||||
|
||||
#
|
||||
|
||||
if $generate_html; then
|
||||
# Split HTML at level $1. Used for texi2html.
|
||||
html_split()
|
||||
{
|
||||
opt="--split=$1 --node-files $commonarg $htmlarg"
|
||||
cmd="$SETLANG $TEXI2HTML --output $PACKAGE.html $opt \"$srcfile\""
|
||||
printf "\nGenerating html by $1... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
split_html_dir=$PACKAGE.html
|
||||
(
|
||||
cd ${split_html_dir} || exit 1
|
||||
if [ ! -f index.html ]; then
|
||||
ln -sf ${PACKAGE}.html index.html
|
||||
fi
|
||||
tar -czf "$abs_outdir/${PACKAGE}.html_$1.tar.gz" -- *.html
|
||||
)
|
||||
eval html_$1_tgz_size=`calcsize "$outdir/${PACKAGE}.html_$1.tar.gz"`
|
||||
rm -f "$outdir"/html_$1/*.html
|
||||
mkdir -p "$outdir/html_$1/"
|
||||
mv ${split_html_dir}/*.html "$outdir/html_$1/"
|
||||
rmdir ${split_html_dir}
|
||||
}
|
||||
|
||||
if test -z "$use_texi2html"; then
|
||||
opt="--no-split --html -o $PACKAGE.html $commonarg $htmlarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
|
||||
printf "\nGenerating monolithic html... ($cmd)\n"
|
||||
rm -rf $PACKAGE.html # in case a directory is left over
|
||||
eval "$cmd"
|
||||
html_mono_size=`calcsize $PACKAGE.html`
|
||||
gzip -f -9 -c $PACKAGE.html >"$outdir/$PACKAGE.html.gz"
|
||||
html_mono_gz_size=`calcsize "$outdir/$PACKAGE.html.gz"`
|
||||
copy_images "$outdir/" $PACKAGE.html
|
||||
mv $PACKAGE.html "$outdir/"
|
||||
ls -l "$outdir/$PACKAGE.html" "$outdir/$PACKAGE.html.gz"
|
||||
|
||||
# Before Texinfo 5.0, makeinfo did not accept a --split=HOW option,
|
||||
# it just always split by node. So if we're splitting by node anyway,
|
||||
# leave it out.
|
||||
if test "x$split" = xnode; then
|
||||
split_arg=
|
||||
else
|
||||
split_arg=--split=$split
|
||||
fi
|
||||
#
|
||||
opt="--html -o $PACKAGE.html $split_arg $commonarg $htmlarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
|
||||
printf "\nGenerating html by $split... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
split_html_dir=$PACKAGE.html
|
||||
copy_images $split_html_dir/ $split_html_dir/*.html
|
||||
(
|
||||
cd $split_html_dir || exit 1
|
||||
tar -czf "$abs_outdir/$PACKAGE.html_$split.tar.gz" -- *
|
||||
)
|
||||
eval \
|
||||
html_${split}_tgz_size=`calcsize "$outdir/$PACKAGE.html_$split.tar.gz"`
|
||||
rm -rf "$outdir/html_$split/"
|
||||
mv $split_html_dir "$outdir/html_$split/"
|
||||
du -s "$outdir/html_$split/"
|
||||
ls -l "$outdir/$PACKAGE.html_$split.tar.gz"
|
||||
|
||||
else # use texi2html:
|
||||
opt="--output $PACKAGE.html $commonarg $htmlarg"
|
||||
cmd="$SETLANG $TEXI2HTML $opt \"$srcfile\""
|
||||
printf "\nGenerating monolithic html with texi2html... ($cmd)\n"
|
||||
rm -rf $PACKAGE.html # in case a directory is left over
|
||||
eval "$cmd"
|
||||
html_mono_size=`calcsize $PACKAGE.html`
|
||||
gzip -f -9 -c $PACKAGE.html >"$outdir/$PACKAGE.html.gz"
|
||||
html_mono_gz_size=`calcsize "$outdir/$PACKAGE.html.gz"`
|
||||
mv $PACKAGE.html "$outdir/"
|
||||
|
||||
html_split node
|
||||
html_split chapter
|
||||
html_split section
|
||||
fi
|
||||
fi # end html
|
||||
|
||||
#
|
||||
printf "\nMaking .tar.gz for sources...\n"
|
||||
d=`dirname $srcfile`
|
||||
(
|
||||
cd "$d"
|
||||
srcfiles=`ls -d *.texinfo *.texi *.txi *.eps $source_extra 2>/dev/null` || true
|
||||
tar czfh "$abs_outdir/$PACKAGE.texi.tar.gz" $srcfiles
|
||||
ls -l "$abs_outdir/$PACKAGE.texi.tar.gz"
|
||||
)
|
||||
texi_tgz_size=`calcsize "$outdir/$PACKAGE.texi.tar.gz"`
|
||||
|
||||
#
|
||||
# Do everything again through docbook.
|
||||
if test -n "$docbook"; then
|
||||
opt="-o - --docbook $commonarg"
|
||||
cmd="$SETLANG $MAKEINFO $opt \"$srcfile\" >${srcdir}/$PACKAGE-db.xml"
|
||||
printf "\nGenerating docbook XML... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
docbook_xml_size=`calcsize $PACKAGE-db.xml`
|
||||
gzip -f -9 -c $PACKAGE-db.xml >"$outdir/$PACKAGE-db.xml.gz"
|
||||
docbook_xml_gz_size=`calcsize "$outdir/$PACKAGE-db.xml.gz"`
|
||||
mv $PACKAGE-db.xml "$outdir/"
|
||||
|
||||
split_html_db_dir=html_node_db
|
||||
opt="$commonarg -o $split_html_db_dir"
|
||||
cmd="$DOCBOOK2HTML $opt \"${outdir}/$PACKAGE-db.xml\""
|
||||
printf "\nGenerating docbook HTML... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
(
|
||||
cd ${split_html_db_dir} || exit 1
|
||||
tar -czf "$abs_outdir/${PACKAGE}.html_node_db.tar.gz" -- *.html
|
||||
)
|
||||
html_node_db_tgz_size=`calcsize "$outdir/${PACKAGE}.html_node_db.tar.gz"`
|
||||
rm -f "$outdir"/html_node_db/*.html
|
||||
mkdir -p "$outdir/html_node_db"
|
||||
mv ${split_html_db_dir}/*.html "$outdir/html_node_db/"
|
||||
rmdir ${split_html_db_dir}
|
||||
|
||||
cmd="$DOCBOOK2TXT \"${outdir}/$PACKAGE-db.xml\""
|
||||
printf "\nGenerating docbook ASCII... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
docbook_ascii_size=`calcsize $PACKAGE-db.txt`
|
||||
mv $PACKAGE-db.txt "$outdir/"
|
||||
|
||||
cmd="$DOCBOOK2PDF \"${outdir}/$PACKAGE-db.xml\""
|
||||
printf "\nGenerating docbook PDF... ($cmd)\n"
|
||||
eval "$cmd"
|
||||
docbook_pdf_size=`calcsize $PACKAGE-db.pdf`
|
||||
mv $PACKAGE-db.pdf "$outdir/"
|
||||
fi
|
||||
|
||||
#
|
||||
printf "\nMaking index.html for $PACKAGE...\n"
|
||||
if test -z "$use_texi2html"; then
|
||||
CONDS="/%%IF *HTML_SECTION%%/,/%%ENDIF *HTML_SECTION%%/d;\
|
||||
/%%IF *HTML_CHAPTER%%/,/%%ENDIF *HTML_CHAPTER%%/d"
|
||||
else
|
||||
# should take account of --split here.
|
||||
CONDS="/%%ENDIF.*%%/d;/%%IF *HTML_SECTION%%/d;/%%IF *HTML_CHAPTER%%/d"
|
||||
fi
|
||||
|
||||
curdate=`$SETLANG date '+%B %d, %Y'`
|
||||
sed \
|
||||
-e "s!%%TITLE%%!$MANUAL_TITLE!g" \
|
||||
-e "s!%%EMAIL%%!$EMAIL!g" \
|
||||
-e "s!%%PACKAGE%%!$PACKAGE!g" \
|
||||
-e "s!%%DATE%%!$curdate!g" \
|
||||
-e "s!%%HTML_MONO_SIZE%%!$html_mono_size!g" \
|
||||
-e "s!%%HTML_MONO_GZ_SIZE%%!$html_mono_gz_size!g" \
|
||||
-e "s!%%HTML_NODE_TGZ_SIZE%%!$html_node_tgz_size!g" \
|
||||
-e "s!%%HTML_SECTION_TGZ_SIZE%%!$html_section_tgz_size!g" \
|
||||
-e "s!%%HTML_CHAPTER_TGZ_SIZE%%!$html_chapter_tgz_size!g" \
|
||||
-e "s!%%INFO_TGZ_SIZE%%!$info_tgz_size!g" \
|
||||
-e "s!%%DVI_GZ_SIZE%%!$dvi_gz_size!g" \
|
||||
-e "s!%%PDF_SIZE%%!$pdf_size!g" \
|
||||
-e "s!%%ASCII_SIZE%%!$ascii_size!g" \
|
||||
-e "s!%%ASCII_GZ_SIZE%%!$ascii_gz_size!g" \
|
||||
-e "s!%%TEXI_TGZ_SIZE%%!$texi_tgz_size!g" \
|
||||
-e "s!%%DOCBOOK_HTML_NODE_TGZ_SIZE%%!$html_node_db_tgz_size!g" \
|
||||
-e "s!%%DOCBOOK_ASCII_SIZE%%!$docbook_ascii_size!g" \
|
||||
-e "s!%%DOCBOOK_PDF_SIZE%%!$docbook_pdf_size!g" \
|
||||
-e "s!%%DOCBOOK_XML_SIZE%%!$docbook_xml_size!g" \
|
||||
-e "s!%%DOCBOOK_XML_GZ_SIZE%%!$docbook_xml_gz_size!g" \
|
||||
-e "s,%%SCRIPTURL%%,$scripturl,g" \
|
||||
-e "s!%%SCRIPTNAME%%!$prog!g" \
|
||||
-e "$CONDS" \
|
||||
$GENDOCS_TEMPLATE_DIR/gendocs_template >"$outdir/index.html"
|
||||
|
||||
echo "Done, see $outdir/ subdirectory for new files."
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
||||
174
doc/gendocs_template
Executable file → Normal file
174
doc/gendocs_template
Executable file → Normal file
@@ -1,125 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!-- $Id: gendocs_template,v 1.5 2007/10/30 14:58:52 gray Exp $ -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<!--#include virtual="/server/header.html" -->
|
||||
<!-- Parent-Version: 1.78 -->
|
||||
|
||||
<head>
|
||||
<title>%%TITLE%% - GNU Project - Free Software Foundation (FSF)</title>
|
||||
<meta http-equiv="content-type" content='text/html; charset=utf-8' />
|
||||
<link rel="stylesheet" type="text/css" href="/gnu.css" />
|
||||
<link rev="made" href="mailto:gray@gnu.org" />
|
||||
<link rel="icon" type="image/png" href="/graphics/gnu-head-icon.png" />
|
||||
</head>
|
||||
<!--
|
||||
Copyright (C) 2006-2025 Free Software Foundation, Inc.
|
||||
|
||||
<!-- This document is in XML, and xhtml 1.0 -->
|
||||
<!-- Please make sure to properly nest your tags -->
|
||||
<!-- and ensure that your final document validates -->
|
||||
<!-- consistent with W3C xhtml 1.0 and CSS standards -->
|
||||
<!-- See validator.w3.org -->
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without any warranty.
|
||||
-->
|
||||
|
||||
<body>
|
||||
|
||||
<h3>%%TITLE%%</h3>
|
||||
<title>%%TITLE%% - GNU Project - Free Software Foundation</title>
|
||||
<!--#include virtual="/server/banner.html" -->
|
||||
<h2>%%TITLE%%</h2>
|
||||
|
||||
<address>Free Software Foundation</address>
|
||||
<address>last updated %%DATE%%</address>
|
||||
<p>
|
||||
<a href="/graphics/gnu-head.jpg">
|
||||
<img src="/graphics/gnu-head-sm.jpg"
|
||||
alt=" [image of the head of a GNU] "
|
||||
width="129" height="122" />
|
||||
</a>
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<p>The manual for %%PACKAGE%% is available in the following formats:</p>
|
||||
<p>This manual (%%PACKAGE%%) is available in the following formats:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="%%PACKAGE%%.html">HTML
|
||||
(%%HTML_MONO_SIZE%%K bytes)</a> - entirely on one web page.</li>
|
||||
<li><a href="html_node/index.html">HTML</a> - with one web page per
|
||||
node.</li>
|
||||
<li><a href="%%PACKAGE%%.html">HTML
|
||||
(%%HTML_MONO_SIZE%%K bytes)</a> - entirely on one web page.</li>
|
||||
<li><a href="html_node/index.html">HTML</a> - with one web page per
|
||||
node.</li>
|
||||
%%IF HTML_SECTION%%
|
||||
<li><a href="html_section/index.html">HTML</a> - with one web page per
|
||||
section.</li>
|
||||
<li><a href="html_section/index.html">HTML</a> - with one web page per
|
||||
section.</li>
|
||||
%%ENDIF HTML_SECTION%%
|
||||
%%IF HTML_CHAPTER%%
|
||||
<li><a href="html_chapter/index.html">HTML</a> - with one web page per
|
||||
chapter.</li>
|
||||
<li><a href="html_chapter/index.html">HTML</a> - with one web page per
|
||||
chapter.</li>
|
||||
%%ENDIF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.html.gz">HTML compressed
|
||||
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
|
||||
one web page.</li>
|
||||
<li><a href="%%PACKAGE%%.html_node.tar.gz">HTML compressed
|
||||
(%%HTML_NODE_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per node.</li>
|
||||
<li><a href="%%PACKAGE%%.html.gz">HTML compressed
|
||||
(%%HTML_MONO_GZ_SIZE%%K gzipped characters)</a> - entirely on
|
||||
one web page.</li>
|
||||
<li><a href="%%PACKAGE%%.html_node.tar.gz">HTML compressed
|
||||
(%%HTML_NODE_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per node.</li>
|
||||
%%IF HTML_SECTION%%
|
||||
<li><a href="%%PACKAGE%%.html_section.tar.gz">HTML compressed
|
||||
(%%HTML_SECTION_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per section.</li>
|
||||
<li><a href="%%PACKAGE%%.html_section.tar.gz">HTML compressed
|
||||
(%%HTML_SECTION_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per section.</li>
|
||||
%%ENDIF HTML_SECTION%%
|
||||
%%IF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.html_chapter.tar.gz">HTML compressed
|
||||
(%%HTML_CHAPTER_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per chapter.</li>
|
||||
<li><a href="%%PACKAGE%%.html_chapter.tar.gz">HTML compressed
|
||||
(%%HTML_CHAPTER_TGZ_SIZE%%K gzipped tar file)</a> -
|
||||
with one web page per chapter.</li>
|
||||
%%ENDIF HTML_CHAPTER%%
|
||||
<li><a href="%%PACKAGE%%.info.tar.gz">Info document
|
||||
(%%INFO_TGZ_SIZE%%K characters gzipped tar file)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt">ASCII text
|
||||
(%%ASCII_SIZE%%K characters)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt.gz">ASCII text compressed
|
||||
(%%ASCII_GZ_SIZE%%K gzipped characters)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.dvi.gz">TeX dvi file
|
||||
(%%DVI_GZ_SIZE%%K characters gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.ps.gz">PostScript file
|
||||
(%%PS_GZ_SIZE%%K characters gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.pdf">PDF file
|
||||
(%%PDF_SIZE%%K characters)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.texi.tar.gz">Texinfo source
|
||||
(%%TEXI_TGZ_SIZE%%K characters gzipped tar file)</a></li>
|
||||
<li><a href="%%PACKAGE%%.info.tar.gz">Info document
|
||||
(%%INFO_TGZ_SIZE%%K bytes gzipped tar file)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt">ASCII text
|
||||
(%%ASCII_SIZE%%K bytes)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.txt.gz">ASCII text compressed
|
||||
(%%ASCII_GZ_SIZE%%K bytes gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.dvi.gz">TeX dvi file
|
||||
(%%DVI_GZ_SIZE%%K bytes gzipped)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.pdf">PDF file
|
||||
(%%PDF_SIZE%%K bytes)</a>.</li>
|
||||
<li><a href="%%PACKAGE%%.texi.tar.gz">Texinfo source
|
||||
(%%TEXI_TGZ_SIZE%%K bytes gzipped tar file).</a></li>
|
||||
</ul>
|
||||
|
||||
<p>(This page generated by the <a
|
||||
href="%%SCRIPTURL%%">%%SCRIPTNAME%%</a> script.)
|
||||
</p>
|
||||
<p>You can <a href="https://shop.fsf.org/">buy printed copies of
|
||||
some manuals</a> (among other items) from the Free Software Foundation;
|
||||
this helps support FSF activities.</p>
|
||||
|
||||
<p>
|
||||
<a href="http://validator.w3.org/check?uri=referer"><img
|
||||
src="http://www.w3.org/Icons/valid-xhtml10"
|
||||
alt="Valid XHTML 1.0!" height="31" width="88" /></a>
|
||||
</p>
|
||||
<p>(This page generated by the <a href="%%SCRIPTURL%%">%%SCRIPTNAME%%
|
||||
script</a>.)</p>
|
||||
|
||||
<div class="copyright">
|
||||
<p>
|
||||
Return to the <a href="/home.html">GNU Project home page</a>.
|
||||
</p>
|
||||
<!-- If needed, change the copyright block at the bottom. In general,
|
||||
all pages on the GNU web server should have the section about
|
||||
verbatim copying. Please do NOT remove this without talking
|
||||
with the webmasters first.
|
||||
Please make sure the copyright date is consistent with the document
|
||||
and that it is like this: "2001, 2002", not this: "2001-2002". -->
|
||||
</div><!-- for id="content", starts in the include above -->
|
||||
<!--#include virtual="/server/footer.html" -->
|
||||
<div id="footer">
|
||||
<div class="unprintable">
|
||||
|
||||
<p>
|
||||
Please send FSF & GNU inquiries to
|
||||
<a href="mailto:gnu@gnu.org"><em>gnu@gnu.org</em></a>.
|
||||
There are also <a href="/home.html#ContactInfo">other ways to contact</a>
|
||||
the FSF.
|
||||
<br />
|
||||
Please send broken links and other corrections (or suggestions) to
|
||||
<a href="mailto:webmasters@gnu.org"><em>webmasters@gnu.org</em></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02111, USA
|
||||
<br />
|
||||
Verbatim copying and distribution of this entire article is
|
||||
permitted in any medium, provided this notice is preserved.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Updated:
|
||||
<!-- timestamp start -->
|
||||
$Date: 2007/10/30 14:58:52 $ $Author: gray $
|
||||
<!-- timestamp end -->
|
||||
</p>
|
||||
<p>Please send general FSF & GNU inquiries to
|
||||
<a href="mailto:gnu@gnu.org"><gnu@gnu.org></a>.
|
||||
There are also <a href="/contact/">other ways to contact</a>
|
||||
the FSF. Broken links and other corrections or suggestions can be sent
|
||||
to <a href="mailto:%%EMAIL%%"><%%EMAIL%%></a>.</p>
|
||||
</div>
|
||||
|
||||
<p>Copyright © 2020, 2025 Free Software Foundation, Inc.</p>
|
||||
|
||||
<p>This page is licensed under a <a rel="license"
|
||||
href="https://creativecommons.org/licenses/by-nd/3.0/us/">Creative
|
||||
Commons Attribution-NoDerivs 3.0 United States License</a>.</p>
|
||||
|
||||
<!--#include virtual="/server/bottom-notes.html" -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2025 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
@node Standard
|
||||
@unnumberedsec Basic Tar Format
|
||||
@UNREVISED
|
||||
@UNREVISED{}
|
||||
|
||||
While an archive may contain many files, the archive itself is a
|
||||
single ordinary file. Like any other file, an archive file can be
|
||||
@@ -51,7 +51,10 @@ of the file. At the end of the archive file there are two 512-byte blocks
|
||||
filled with binary zeros as an end-of-file marker. A reasonable system
|
||||
should write such end-of-file marker at the end of an archive, but
|
||||
must not assume that such a block exists when reading an archive. In
|
||||
particular @GNUTAR{} always issues a warning if it does not encounter it.
|
||||
particular, @GNUTAR{} does not treat missing end-of-file marker as an
|
||||
error and silently ignores the fact. You can instruct it to issue
|
||||
a warning, however, by using the @option{--warning=missing-zero-blocks}
|
||||
option (@pxref{General Warnings, missing-zero-blocks}).
|
||||
|
||||
The blocks may be @dfn{blocked} for physical I/O operations.
|
||||
Each record of @var{n} blocks (where @var{n} is set by the
|
||||
@@ -87,6 +90,8 @@ The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and
|
||||
@code{gname} are null-terminated character strings. All other fields
|
||||
are zero-filled octal numbers in ASCII. Each numeric field of width
|
||||
@var{w} contains @var{w} minus 1 digits, and a null.
|
||||
(In the extended @acronym{GNU} format, the numeric fields can take
|
||||
other forms.)
|
||||
|
||||
The @code{name} field is the file name of the file, with directory names
|
||||
(if any) preceding the file name, separated by slashes.
|
||||
@@ -109,21 +114,20 @@ The @code{uid} and @code{gid} fields are the numeric user and group
|
||||
not support numeric user or group @acronym{ID}s, these fields should
|
||||
be ignored.
|
||||
|
||||
The @code{size} field is the size of the file in bytes; linked files
|
||||
are archived with this field specified as zero.
|
||||
The @code{size} field is the size of the file in bytes; for archive
|
||||
members that are symbolic or hard links to another file, this field
|
||||
is specified as zero.
|
||||
|
||||
The @code{mtime} field is the data modification time of the file at
|
||||
the time it was archived. It is the ASCII representation of the octal
|
||||
value of the last time the file's contents were modified, represented
|
||||
as an integer number of
|
||||
The @code{mtime} field represents the data modification time of the file at
|
||||
the time it was archived. It represents the integer number of
|
||||
seconds since January 1, 1970, 00:00 Coordinated Universal Time.
|
||||
|
||||
The @code{chksum} field is the ASCII representation of the octal value
|
||||
of the simple sum of all bytes in the header block. Each 8-bit
|
||||
The @code{chksum} field represents
|
||||
the simple sum of all bytes in the header block. Each 8-bit
|
||||
byte in the header is added to an unsigned integer, initialized to
|
||||
zero, the precision of which shall be no less than seventeen bits.
|
||||
When calculating the checksum, the @code{chksum} field is treated as
|
||||
if it were all blanks.
|
||||
if it were filled with spaces (ASCII 32).
|
||||
|
||||
The @code{typeflag} field specifies the type of file archived. If a
|
||||
particular implementation does not recognize or permit the specified
|
||||
@@ -266,7 +270,7 @@ IEEE Std 1003.2-1992, pages 380-388 (section 4.48) and pages 936-940
|
||||
|
||||
@node Extensions
|
||||
@unnumberedsec @acronym{GNU} Extensions to the Archive Format
|
||||
@UNREVISED
|
||||
@UNREVISED{}
|
||||
|
||||
The @acronym{GNU} format uses additional file types to describe new types of
|
||||
files in an archive. These are listed below.
|
||||
@@ -310,6 +314,18 @@ of an archive should have this type.
|
||||
|
||||
@end table
|
||||
|
||||
For fields containing numbers or timestamps that are out of range for
|
||||
the basic format, the @acronym{GNU} format uses a base-256
|
||||
representation instead of an ASCII octal number. If the leading byte
|
||||
is 0xff (255), all the bytes of the field (including the leading byte)
|
||||
are concatenated in big-endian order, with the result being a negative
|
||||
number expressed in two's complement form. If the leading byte is
|
||||
0x80 (128), the non-leading bytes of the field are concatenated in
|
||||
big-endian order, with the result being a positive number expressed in
|
||||
binary form. Leading bytes other than 0xff, 0x80 and ASCII octal
|
||||
digits are reserved for future use, as are base-256 representations of
|
||||
values that would be in range for the basic format.
|
||||
|
||||
You may have trouble reading a @acronym{GNU} format archive on a
|
||||
non-@acronym{GNU} system if the options @option{--incremental} (@option{-G}),
|
||||
@option{--multi-volume} (@option{-M}), @option{--sparse} (@option{-S}), or @option{--label=@var{archive-label}} (@option{-V @var{archive-label}}) were
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
;;; mastermenu.el --- Redefinition of texinfo-master-menu-list
|
||||
|
||||
;; Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
;; Copyright 2006-2025 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Sergey Poznyakoff
|
||||
;; Maintainer: bug-tar@gnu.org
|
||||
;; Keywords: maint, tex, docs
|
||||
|
||||
;; This file is part of GNU tar documentation suite
|
||||
;; This file is part of GNU tar.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; 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 3, or (at your option)
|
||||
;; any later version.
|
||||
;; the Free Software Foundation; either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; 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 this program; if not, write to the Free Software Foundation,
|
||||
;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
|
||||
134
doc/recipes.texi
Normal file
134
doc/recipes.texi
Normal file
@@ -0,0 +1,134 @@
|
||||
@c This is part of the GNU tar manual.
|
||||
@c Copyright (C) 2017--2025 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.3 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
This appendix provides several recipes for performing common tasks
|
||||
using @GNUTAR{}.
|
||||
|
||||
@menu
|
||||
* copy directory hierarchy::
|
||||
* intermediate directories::
|
||||
@end menu
|
||||
|
||||
@node copy directory hierarchy
|
||||
@appendixsec Copying directory hierarchies
|
||||
|
||||
This is a traditional way to copy a directory hierarchy preserving
|
||||
the dates, modes, owners and link-structure of all the files therein.
|
||||
It was used back when the @command{cp} command lacked the @option{-a}
|
||||
option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{(cd sourcedir; tar -cf - .) | (cd targetdir; tar -xf -)}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
You can avoid subshells by using @option{-C} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar -C sourcedir -cf - . | tar -C targetdir -xf -}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
The same command using long option forms:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{(cd sourcedir; tar --create --file=- . ) \
|
||||
| (cd targetdir; tar --extract --file=-)}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
or
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
$ @kbd{tar --directory sourcedir --create --file=- . \
|
||||
| tar --directory targetdir --extract --file=-}
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@node intermediate directories
|
||||
@appendixsec Restoring Intermediate Directories
|
||||
|
||||
A common concern is how to extract permissions and ownerships of
|
||||
intermediate directories when extracting only selected members from
|
||||
the archive. To illustrate this, consider the following archive:
|
||||
|
||||
@example
|
||||
@group
|
||||
# tar tvf A.tar
|
||||
drwxr-xr-x root/root 0 2017-11-16 14:39 foo/
|
||||
dr-xr-x--- gray/user 0 2017-11-16 14:39 foo/bar/
|
||||
-rw-r--r-- gray/user 10 2017-11-16 14:40 foo/bar/file
|
||||
@end group
|
||||
@end example
|
||||
|
||||
Suppose you extract only the file @file{foo/bar/file}, while being
|
||||
@samp{root}:
|
||||
|
||||
@example
|
||||
# @kbd{tar xvf A.tar foo/bar/file}
|
||||
foo/bar/file
|
||||
@end example
|
||||
|
||||
Now, let's inspect the content of the created directories:
|
||||
|
||||
@example
|
||||
@group
|
||||
# find foo -ls
|
||||
427257 0 drwxr-xr-x 3 root root 16 Nov 17 16:10 foo
|
||||
427258 0 drwxr-xr-x 2 root root 17 Nov 17 16:10 foo/bar
|
||||
427259 0 -rw-r--r-- 1 gray user 10 Nov 6 14:40 foo/bar/file
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The requested file is restored, including its ownership and
|
||||
permissions. The intermediate directories, however, are created with
|
||||
the default permissions, current timestamp and owned by the current
|
||||
user. This is because by the time @command{tar} has reached the requested file,
|
||||
it had already skipped the entries for its parent directories, so it
|
||||
has no iformation about their ownership and modes.
|
||||
|
||||
To restore meta information about the intermediate directories,
|
||||
you'll need to specify them explicitly in the command line and use the
|
||||
@option{--no-recursive} option (@pxref{recurse}) to avoid extracting
|
||||
their content.
|
||||
|
||||
To automate this process, @cite{Neal P. Murphy} proposed the following
|
||||
shell script@footnote{The original version of the script can be
|
||||
seen at @uref{http://lists.gnu.org/archive/html/bug-tar/2016-11/msg00024.html}}:
|
||||
|
||||
@example
|
||||
@group
|
||||
#! /bin/sh
|
||||
(while read path
|
||||
do
|
||||
path=`dirname $path`
|
||||
while [ -n "$path" -a "$path" != "." ]
|
||||
do
|
||||
echo $path
|
||||
path=`dirname $path`
|
||||
done
|
||||
done < $2 | sort | uniq) |
|
||||
tar -x --no-recursion -v -f $1 -T - -T $2
|
||||
@end group
|
||||
@end example
|
||||
|
||||
The script takes two arguments: the name of the archive file, and the
|
||||
name of the file list file.
|
||||
|
||||
To complete our example, the file list will contain single line:
|
||||
|
||||
@example
|
||||
foo/bar/file
|
||||
@end example
|
||||
|
||||
Supposing its name is @file{file.list} and the script is named
|
||||
@file{restore.sh}, you can invoke it as follows:
|
||||
|
||||
@example
|
||||
# @kbd{sh restore.sh A.tar file.list}
|
||||
@end example
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright (C) 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
@c 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
@c Copyright 1992--2025 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@c This file contains support for 'renditions' by Fran@,{c}ois Pinard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2005, 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2005--2025 Free Software Foundation, Inc.
|
||||
@c Written by Sergey Poznyakoff
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
@@ -11,11 +11,11 @@ used to determine which files were modified since the last backup.
|
||||
|
||||
@GNUTAR{} version @value{VERSION} supports three snapshot file
|
||||
formats. The first format, called @dfn{format 0}, is the one used by
|
||||
@GNUTAR{} versions up to 1.15.1. The second format, called @dfn{format
|
||||
1} is an extended version of this format, that contains more metadata
|
||||
and allows for further extensions. It was used by version
|
||||
1.15.1. Starting from version 1.16 and up to @value{VERSION}, the
|
||||
@dfn{format 2} is used.
|
||||
@GNUTAR{} versions up to and including 1.15.1. The second format, called
|
||||
@dfn{format 1} is an extended version of this format, that contains more
|
||||
metadata and allows for further extensions. It was used by alpha release
|
||||
version 1.15.90. For alpha version 1.15.91 and stable releases
|
||||
version 1.16 up through @value{VERSION}, the @dfn{format 2} is used.
|
||||
|
||||
@GNUTAR{} is able to read all three formats, but will create
|
||||
snapshots only in format 2.
|
||||
@@ -33,7 +33,7 @@ metadata descriptions, one per line. Each description has the
|
||||
following format:
|
||||
|
||||
@smallexample
|
||||
@var{nfs}@var{dev} @var{inode} @var{name}
|
||||
[@var{nfs}]@var{dev} @var{inode} @var{name}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
@@ -42,7 +42,10 @@ where:
|
||||
@table @var
|
||||
@item nfs
|
||||
A single plus character (@samp{+}), if this directory is located on
|
||||
an @acronym{NFS}-mounted partition, or a single space otherwise;
|
||||
an @acronym{NFS}-mounted partition, otherwise empty.
|
||||
|
||||
(That is, for non-NFS directories, the first character on the
|
||||
description line contains the start of the @var{dev} field.)
|
||||
|
||||
@item dev
|
||||
Device number of the directory;
|
||||
@@ -91,7 +94,6 @@ as with @samp{format 0}.
|
||||
|
||||
@cindex format 2, snapshot file
|
||||
@cindex snapshot file, format 2
|
||||
@FIXME{}
|
||||
@item
|
||||
@samp{Format 2} snapshot file begins with a format identifier, as described for
|
||||
version 1, e.g.:
|
||||
@@ -105,7 +107,7 @@ records, separated by null (@acronym{ASCII} 0)
|
||||
characters. Thus, in contrast to the previous formats, format 2
|
||||
snapshot is a binary file.
|
||||
|
||||
First two records are decimal numbers, representing the
|
||||
First two records are decimal integers, representing the
|
||||
time of the last backup. First number is the number of seconds, the
|
||||
second one is the number of nanoseconds, since the beginning of the
|
||||
epoch. These are followed by arbitrary number of directory records.
|
||||
@@ -113,17 +115,18 @@ epoch. These are followed by arbitrary number of directory records.
|
||||
Each @dfn{directory record} contains a set of metadata describing a
|
||||
particular directory. Parts of a directory record are delimited with
|
||||
@acronym{ASCII} 0 characters. The following table describes each
|
||||
part. The @dfn{Number} type in this table stands for a decimal number
|
||||
in @acronym{ASCII} notation.
|
||||
part. The @dfn{Number} type in this table stands for a decimal integer
|
||||
in @acronym{ASCII} notation. (Negative values are preceded with a "-"
|
||||
character, while positive values have no leading punctuation.)
|
||||
|
||||
@multitable @columnfractions 0.2 0.2 0.6
|
||||
@multitable @columnfractions 0.25 0.15 0.6
|
||||
@headitem Field @tab Type @tab Description
|
||||
@item nfs @tab Character @tab @samp{1} if the directory is located on
|
||||
an @acronym{NFS}-mounted partition, or @samp{0} otherwise;
|
||||
@item mtime-sec @tab Number @tab Modification time, seconds;
|
||||
@item mtime-nano @tab Number @tab Modification time, nanoseconds;
|
||||
@item dev-no @tab Number @tab Device number;
|
||||
@item i-no @tab Number @tab I-node number;
|
||||
@item timestamp_sec @tab Number @tab Modification time, seconds;
|
||||
@item timestamp_nsec @tab Number @tab Modification time, nanoseconds;
|
||||
@item dev @tab Number @tab Device number;
|
||||
@item ino @tab Number @tab I-node number;
|
||||
@item name @tab String @tab Directory name; in contrast to the
|
||||
previous versions it is not quoted;
|
||||
@item contents @tab Dumpdir @tab Contents of the directory;
|
||||
@@ -134,6 +137,28 @@ previous versions it is not quoted;
|
||||
Dumpdirs stored in snapshot files contain only records of types
|
||||
@samp{Y}, @samp{N} and @samp{D}.
|
||||
|
||||
@cindex snapshot file field ranges
|
||||
@opindex show-snapshot-field-ranges
|
||||
The specific range of values allowed in each of the @dfn{Number} fields
|
||||
depends on the underlying C datatypes as determined when @command{tar}
|
||||
is compiled. To see the specific ranges allowed for a particular
|
||||
@command{tar} binary, you can use the
|
||||
@option{--show-snapshot-field-ranges} option:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --show-snapshot-field-ranges}
|
||||
This tar's snapshot file field ranges are
|
||||
(field name => [ min, max ]):
|
||||
|
||||
nfs => [ 0, 1 ],
|
||||
timestamp_sec => [ -9223372036854775808, 9223372036854775807 ],
|
||||
timestamp_nsec => [ 0, 999999999 ],
|
||||
dev => [ 0, 18446744073709551615 ],
|
||||
ino => [ 0, 18446744073709551615 ],
|
||||
@end smallexample
|
||||
|
||||
(This example is from a GNU/Linux x86_64 system.)
|
||||
|
||||
@end enumerate
|
||||
|
||||
@c End of snapshot.texi
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2006--2025 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@@ -143,7 +143,7 @@ format, it will also extract a file containing extension header
|
||||
attributes. This file can be used to expand the file to its original
|
||||
state. However, posix-aware @command{tar}s will usually ignore the
|
||||
unknown variables, which makes restoring the file more
|
||||
difficult. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
difficult. @xref{extracting sparse v0x, Extraction of sparse
|
||||
members in v.0.0 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
@end enumerate
|
||||
@@ -175,7 +175,7 @@ The real name of the sparse file is stored in the variable
|
||||
@code{GNU.sparse.name}. Thus, those @command{tar} implementations
|
||||
that are not aware of GNU extensions will at least extract the files
|
||||
into separate directories, giving the user a possibility to expand it
|
||||
afterwards. @xref{extracting sparse v.0.x, Extraction of sparse
|
||||
afterwards. @xref{extracting sparse v0x, Extraction of sparse
|
||||
members in v.0.1 format}, for the detailed description of how to
|
||||
restore such members using non-GNU @command{tar}s.
|
||||
|
||||
@@ -218,12 +218,12 @@ The real name of the sparse file is stored in the variable
|
||||
variable @code{GNU.sparse.realsize}.
|
||||
|
||||
The sparse map itself is stored in the file data block, preceding the actual
|
||||
file data. It consists of a series of octal numbers of arbitrary length, delimited
|
||||
file data. It consists of a series of decimal numbers delimited
|
||||
by newlines. The map is padded with nulls to the nearest block boundary.
|
||||
|
||||
The first number gives the number of entries in the map. Following are map entries,
|
||||
each one consisting of two numbers giving the offset and size of the
|
||||
data block it describes.
|
||||
The first number gives the number of entries in the map. Following are
|
||||
map entries, each one consisting of two numbers giving the offset and
|
||||
size of the data block it describes.
|
||||
|
||||
The format is designed in such a way that non-posix aware @command{tar}s and @command{tar}s not
|
||||
supporting @code{GNU.sparse.*} keywords will extract each sparse file
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
@c This is part of the paxutils manual.
|
||||
@c Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
@c Copyright (C) 2007--2025 Free Software Foundation, Inc.
|
||||
@c This file is distributed under GFDL 1.1 or any later version
|
||||
@c published by the Free Software Foundation.
|
||||
|
||||
@cindex Device numbers, changing
|
||||
@cindex snapshot files, editing
|
||||
@cindex snapshot files, fixing device numbers
|
||||
Sometimes device numbers can change after upgrading your kernel
|
||||
version or reconfiguring the hardware. Reportedly this is the case with
|
||||
some newer @i{Linux} kernels, when using @acronym{LVM}. In majority of
|
||||
Various situations can cause device numbers to change: upgrading your
|
||||
kernel version, reconfiguring your hardware, loading kernel modules in a
|
||||
different order, using virtual volumes that are assembled dynamically
|
||||
(such as with @acronym{LVM} or @acronym{RAID}), hot-plugging drives
|
||||
(e.g. external USB or Firewire drives), etc. In the majority of
|
||||
cases this change is unnoticed by the users. However, it influences
|
||||
@command{tar} incremental backups: the device number is stored in tar
|
||||
snapshot files (@pxref{Snapshot Files}) and is used to determine whether
|
||||
the file has changed since the last backup. If the device numbers
|
||||
change for some reason, the next backup you run will be a full backup.
|
||||
change for some reason, by default the next backup you run will be a
|
||||
full backup.
|
||||
|
||||
|
||||
@pindex tar-snapshot-edit
|
||||
To minimize the impact in these cases, GNU @command{tar} comes with
|
||||
the @command{tar-snapshot-edit} utility for inspecting and updating
|
||||
device numbers in snapshot files. The utility, written by
|
||||
Dustin J.@: Mitchell, is available from
|
||||
device numbers in snapshot files. (The utility, written by
|
||||
Dustin J.@: Mitchell, is also available from the
|
||||
@uref{http://www.gnu.org/@/software/@/tar/@/utils/@/tar-snapshot-edit.html,
|
||||
@GNUTAR{} home page}.
|
||||
@GNUTAR{} home page}.)
|
||||
|
||||
To obtain the device numbers used in the snapshot file, run
|
||||
To obtain a summary of the device numbers found in the snapshot file, run
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar-snapshot-edit @var{snapfile}}
|
||||
@@ -31,10 +35,19 @@ $ @kbd{tar-snapshot-edit @var{snapfile}}
|
||||
|
||||
@noindent
|
||||
where @var{snapfile} is the name of the snapshot file (you can supply as many
|
||||
files as you wish in a single command line).
|
||||
files as you wish in a single command line). You can then compare the
|
||||
numbers across snapshot files, or against those currently in use on the
|
||||
live filesystem (using @command{ls -l} or @command{stat}).
|
||||
|
||||
To update all occurrences of the given device number in the file, use
|
||||
@option{-r} option. It takes a single argument of the form
|
||||
Assuming the device numbers have indeed changed, it's often possible
|
||||
to simply tell @GNUTAR{} to ignore the device number when processing the
|
||||
incremental snapshot files for these backups, using the
|
||||
@option{--no-check-device} option (@pxref{device numbers}).
|
||||
|
||||
Alternatively, you can use the @command{tar-edit-snapshot} script's
|
||||
@option{-r} option to update all occurrences of the given device
|
||||
number in the snapshot file(s). It takes a single argument
|
||||
of the form
|
||||
@samp{@var{olddev}-@var{newdev}}, where @var{olddev} is the device number
|
||||
used in the snapshot file, and @var{newdev} is the corresponding new device
|
||||
number. Both numbers may be specified in hex (e.g., @samp{0xfe01}),
|
||||
@@ -49,9 +62,30 @@ backup file is obtained by appending @samp{~} to the original file name.
|
||||
|
||||
An example session:
|
||||
@smallexample
|
||||
$ @kbd{tar-snapshot-edit /var/backup/snap.a}
|
||||
file version 2
|
||||
/tmp/snap: Device 0x0306 occurs 634 times.
|
||||
$ @kbd{tar-snapshot-edit -b -r 0x0306-0x4500 /var/backup/snap.a}
|
||||
file version 2
|
||||
$ @kbd{tar-snapshot-edit root_snap.0 boot_snap.0}
|
||||
File: root_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Device 0x0000 occurs 1 times.
|
||||
Device 0x0003 occurs 1 times.
|
||||
Device 0x0005 occurs 1 times.
|
||||
Device 0x0013 occurs 1 times.
|
||||
Device 0x6801 occurs 1 times.
|
||||
Device 0x6803 occurs 6626 times.
|
||||
Device 0xfb00 occurs 1 times.
|
||||
|
||||
File: boot_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Device 0x6801 occurs 3 times.
|
||||
$ @kbd{tar-snapshot-edit -b -r 0x6801-0x6901,0x6803-0x6903 root_snap.0 boot_snap.0}
|
||||
File: root_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Updated 6627 records.
|
||||
|
||||
File: boot_snap.0
|
||||
Detected snapshot file version: 2
|
||||
|
||||
Updated 3 records.
|
||||
@end smallexample
|
||||
|
||||
2823
doc/tar.texi
2823
doc/tar.texi
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,19 @@
|
||||
# Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
#
|
||||
# GNU tar is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 3, 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.
|
||||
#
|
||||
# Copyright 2006-2025 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# GNU tar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU tar; if not, write to the Free Software
|
||||
# Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
1{s,/\*,@comment ,
|
||||
b
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
@c This is part of GNU tar manual.
|
||||
@c Copyright (C) 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
|
||||
@c 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
@c Copyright 1992--2025 Free Software Foundation, Inc.
|
||||
@c See file tar.texi for copying conditions.
|
||||
|
||||
@macro GNUTAR
|
||||
|
||||
1
gnulib
Submodule
1
gnulib
Submodule
Submodule gnulib added at 4619f63e6f
@@ -1,37 +1,82 @@
|
||||
# List of gnulib modules needed for GNU tar.
|
||||
# A module name per line. Empty lines and comments are ignored.
|
||||
|
||||
alloca
|
||||
# Copyright 2005-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
areadlinkat-with-size
|
||||
argmatch
|
||||
argp
|
||||
argp-version-etc
|
||||
assert-h
|
||||
attribute
|
||||
backupfile
|
||||
bool
|
||||
c-ctype
|
||||
c32rtomb
|
||||
c32tolower
|
||||
c32toupper
|
||||
closeout
|
||||
configmake
|
||||
dirname
|
||||
dup2
|
||||
errno-h
|
||||
error
|
||||
exclude
|
||||
extern-inline
|
||||
exitfail
|
||||
faccessat
|
||||
fchmodat
|
||||
fchownat
|
||||
fcntl-h
|
||||
fdopendir
|
||||
fdutimensat
|
||||
file-has-acl
|
||||
fileblocks
|
||||
flexmember
|
||||
fnmatch-gnu
|
||||
fprintftime
|
||||
free-posix
|
||||
fseeko
|
||||
fstatat
|
||||
full-write
|
||||
futimens
|
||||
getline
|
||||
getopt-gnu
|
||||
getpagesize
|
||||
gettext
|
||||
gettext-h
|
||||
gettime
|
||||
gitlog-to-changelog
|
||||
hash
|
||||
human
|
||||
ialloc
|
||||
idx
|
||||
intprops
|
||||
inttostr
|
||||
inttypes
|
||||
inttypes-h
|
||||
largefile
|
||||
lchown
|
||||
limits-h
|
||||
linkat
|
||||
localcharset
|
||||
manywarnings
|
||||
mbrtoc32-regular
|
||||
mcel-prefer
|
||||
mkdirat
|
||||
mkdtemp
|
||||
mkfifoat
|
||||
modechange
|
||||
@@ -43,28 +88,39 @@ progname
|
||||
quote
|
||||
quotearg
|
||||
readlinkat
|
||||
reallocarray
|
||||
renameat
|
||||
root-uid
|
||||
rpmatch
|
||||
full-read
|
||||
safe-read
|
||||
same-inode
|
||||
savedir
|
||||
selinux-at
|
||||
setenv
|
||||
snprintf
|
||||
stat-time
|
||||
stdbool
|
||||
stdint
|
||||
std-gnu23
|
||||
stddef-h
|
||||
stdint-h
|
||||
stpcpy
|
||||
stdopen
|
||||
strdup-posix
|
||||
strerror
|
||||
strtol
|
||||
strtoul
|
||||
strnlen
|
||||
symlinkat
|
||||
sys_stat-h
|
||||
timespec
|
||||
timespec-sub
|
||||
unlinkat
|
||||
unlinkdir
|
||||
unlocked-io
|
||||
utimensat
|
||||
version-etc-fsf
|
||||
verror
|
||||
xalignalloc
|
||||
xalloc
|
||||
xalloc-die
|
||||
xgetcwd
|
||||
xstrtoumax
|
||||
xvasprintf
|
||||
year2038-recommended
|
||||
|
||||
9
lib/.gitignore
vendored
Normal file
9
lib/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
paxerror.c
|
||||
paxexit-status.c
|
||||
paxexit.c
|
||||
paxlib.h
|
||||
paxnames.c
|
||||
rmt-command.h
|
||||
rmt.h
|
||||
rtapelib.c
|
||||
system.h
|
||||
@@ -1,21 +1,21 @@
|
||||
# Makefile for GNU tar library. -*- Makefile -*-
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004,
|
||||
# 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||
# Copyright 1994-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
noinst_LIBRARIES=libtar.a
|
||||
rmt-command.h : Makefile
|
||||
@@ -26,13 +26,32 @@ rmt-command.h : Makefile
|
||||
$(AM_V_at)mv $@-t $@
|
||||
BUILT_SOURCES = rmt-command.h
|
||||
CLEANFILES = rmt-command.h rmt-command.h-t
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/gnu -I../ -I../gnu
|
||||
AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
paxlib.h\
|
||||
rmt.h\
|
||||
system.h\
|
||||
wordsplit.h\
|
||||
xattr-at.h
|
||||
|
||||
noinst_HEADERS = system.h system-ioctl.h rmt.h paxlib.h stdopen.h
|
||||
libtar_a_SOURCES = \
|
||||
paxerror.c paxexit.c paxlib.h paxnames.c \
|
||||
prepargs.c prepargs.h \
|
||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h
|
||||
system.h \
|
||||
wordsplit.c\
|
||||
xattr-at.c
|
||||
|
||||
if !TAR_COND_XATTR_H
|
||||
BUILT_SOURCES += attr/xattr.h
|
||||
attr/xattr.h: attr-xattr.in.h $(top_builddir)/config.status
|
||||
$(AM_V_at)$(MKDIR_P) attr
|
||||
$(AM_V_GEN)rm -f $@-t $@ && \
|
||||
cp $(srcdir)/attr-xattr.in.h attr/xattr.h
|
||||
endif
|
||||
|
||||
MOSTLYCLEANFILES = attr/xattr.h
|
||||
|
||||
EXTRA_DIST = attr-xattr.in.h
|
||||
|
||||
60
lib/attr-xattr.in.h
Normal file
60
lib/attr-xattr.in.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* Replacement <attr/xattr.h> for platforms that lack it.
|
||||
Copyright 2012-2025 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef TAR_ATTR_XATTR_H
|
||||
#define TAR_ATTR_XATTR_H
|
||||
#include <errno.h>
|
||||
#ifndef ENOATTR
|
||||
# define ENOATTR ENODATA /* No such attribute */
|
||||
#endif
|
||||
|
||||
/* setting */
|
||||
static int setxattr (const char *path, const char *name, const void
|
||||
*value, size_t size, int flags)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static int lsetxattr (const char *path, const char *name, const void
|
||||
*value, size_t size, int flags)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static int fsetxattr (int filedes, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
|
||||
/* getting */
|
||||
static ssize_t getxattr (const char *path, const char *name, void *value,
|
||||
size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static ssize_t lgetxattr (const char *path, const char *name, void
|
||||
*value, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static ssize_t fgetxattr (int filedes, const char *name, void *value,
|
||||
size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
|
||||
/* listing */
|
||||
static ssize_t listxattr (const char *path, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static ssize_t llistxattr (const char *path, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static ssize_t flistxattr (int filedes, char *list, size_t size)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
/* Parse arguments from a string and prepend them to an argv.
|
||||
Copyright 1999, 2000, 2001, 2007 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 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA. */
|
||||
|
||||
/* Written by Paul Eggert <eggert@twinsun.com>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include "prepargs.h"
|
||||
#include <sys/types.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#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". */
|
||||
#ifdef STDC_HEADERS
|
||||
# define IN_CTYPE_DOMAIN(c) 1
|
||||
#else
|
||||
# define IN_CTYPE_DOMAIN(c) ((c) <= 0177)
|
||||
#endif
|
||||
|
||||
#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
|
||||
|
||||
/* Find the white-space-separated options specified by OPTIONS, and
|
||||
using BUF to store copies of these options, set ARGV[0], ARGV[1],
|
||||
etc. to the option copies. Return the number N of options found.
|
||||
Do not set ARGV[N]. If ARGV is null, do not store ARGV[0]
|
||||
etc. Backslash can be used to escape whitespace (and backslashes). */
|
||||
static int
|
||||
prepend_args (char const *options, char *buf, char **argv)
|
||||
{
|
||||
char const *o = options;
|
||||
char *b = buf;
|
||||
int n = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (ISSPACE ((unsigned char) *o))
|
||||
o++;
|
||||
if (!*o)
|
||||
return n;
|
||||
if (argv)
|
||||
argv[n] = b;
|
||||
n++;
|
||||
|
||||
do
|
||||
if ((*b++ = *o++) == '\\' && *o)
|
||||
b[-1] = *o++;
|
||||
while (*o && ! ISSPACE ((unsigned char) *o));
|
||||
|
||||
*b++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepend the whitespace-separated options in OPTIONS to the argument
|
||||
vector of a main program with argument count *PARGC and argument
|
||||
vector *PARGV. */
|
||||
void
|
||||
prepend_default_options (char const *options, int *pargc, char ***pargv)
|
||||
{
|
||||
if (options)
|
||||
{
|
||||
char *buf = xmalloc (strlen (options) + 1);
|
||||
int prepended = prepend_args (options, buf, (char **) 0);
|
||||
int argc = *pargc;
|
||||
char * const *argv = *pargv;
|
||||
char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
|
||||
*pargc = prepended + argc;
|
||||
*pargv = pp;
|
||||
*pp++ = *argv++;
|
||||
pp += prepend_args (options, buf, pp);
|
||||
while ((*pp++ = *argv++))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
/* Parse arguments from a string and prepend them to an argv. */
|
||||
|
||||
void prepend_default_options (char const *, int *, char ***);
|
||||
@@ -1,77 +0,0 @@
|
||||
/* stdopen.c - ensure that the three standard file descriptors are in use
|
||||
|
||||
Copyright (C) 2005, 2007 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 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Written by Paul Eggert and Jim Meyering. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "stdopen.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Try to ensure that all of the standard file numbers (0, 1, 2)
|
||||
are in use. Without this, each application would have to guard
|
||||
every call to open, dup, fopen, etc. with tests to ensure they
|
||||
don't use one of the special file numbers when opening a file.
|
||||
Return false if at least one of the file descriptors is initially
|
||||
closed and an attempt to reopen it fails. Otherwise, return true. */
|
||||
bool
|
||||
stdopen (void)
|
||||
{
|
||||
int fd;
|
||||
bool ok = true;
|
||||
|
||||
for (fd = 0; fd <= 2; fd++)
|
||||
{
|
||||
if (fcntl (fd, F_GETFD) < 0)
|
||||
{
|
||||
if (errno != EBADF)
|
||||
ok = false;
|
||||
else
|
||||
{
|
||||
static const int contrary_mode[]
|
||||
= { O_WRONLY, O_RDONLY, O_RDONLY };
|
||||
int mode = contrary_mode[fd];
|
||||
int new_fd;
|
||||
/* Open /dev/null with the contrary mode so that the typical
|
||||
read (stdin) or write (stdout, stderr) operation will fail.
|
||||
With descriptor 0, we can do even better on systems that
|
||||
have /dev/full, by opening that write-only instead of
|
||||
/dev/null. The only drawback is that a write-provoked
|
||||
failure comes with a misleading errno value, ENOSPC. */
|
||||
if (mode == O_RDONLY
|
||||
|| (new_fd = open ("/dev/full", mode) != fd))
|
||||
new_fd = open ("/dev/null", mode);
|
||||
if (new_fd != fd)
|
||||
{
|
||||
if (0 <= new_fd)
|
||||
close (new_fd);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef STDOPEN_H
|
||||
# define STDOPEN_H 1
|
||||
|
||||
# include <stdbool.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
bool stdopen (void);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
2620
lib/wordsplit.c
Normal file
2620
lib/wordsplit.c
Normal file
File diff suppressed because it is too large
Load Diff
266
lib/wordsplit.h
Normal file
266
lib/wordsplit.h
Normal file
@@ -0,0 +1,266 @@
|
||||
/* wordsplit - a word splitter
|
||||
Copyright (C) 2009-2018 Sergey Poznyakoff
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef __WORDSPLIT_H
|
||||
#define __WORDSPLIT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <idx.h>
|
||||
|
||||
/* This wordsplit code has been tuned for GNU Tar.
|
||||
Define _WORDSPLIT_EXTRAS before including wordsplit.h
|
||||
to define extras that GNU Tar does not need. */
|
||||
|
||||
#ifdef _WORDSPLIT_EXTRAS
|
||||
typedef struct wordsplit wordsplit_t;
|
||||
#endif
|
||||
|
||||
/* Structure used to direct the splitting. Members marked with [Input]
|
||||
can be defined before calling wordsplit(), those marked with [Output]
|
||||
provide return values when the function returns. If neither mark is
|
||||
used, the member is internal and must not be used by the caller.
|
||||
|
||||
In the comments below, the identifiers in parentheses indicate bits that
|
||||
must be set (or unset, if starting with !) in ws_flags (if starting with
|
||||
WRDSF_) or ws_options (if starting with WRDSO_) to initialize or use the
|
||||
given member.
|
||||
|
||||
If not redefined explicitly, most of them are set to some reasonable
|
||||
default value upon entry to wordsplit(). */
|
||||
struct wordsplit
|
||||
{
|
||||
idx_t ws_wordc; /* [Output] Number of words in ws_wordv. */
|
||||
char **ws_wordv; /* [Output] Array of parsed out words. */
|
||||
idx_t ws_offs; /* [Input] (WRDSF_DOOFFS) Number of initial
|
||||
elements in ws_wordv to fill with NULLs. */
|
||||
idx_t ws_wordn; /* Number of elements ws_wordv can accommodate. */
|
||||
unsigned ws_flags; /* [Input] Flags passed to wordsplit. */
|
||||
unsigned ws_options; /* [Input] (WRDSF_OPTIONS)
|
||||
Additional options. */
|
||||
idx_t ws_maxwords; /* [Input] (WRDSO_MAXWORDS) Return at most that
|
||||
many words */
|
||||
idx_t ws_wordi; /* [Output] (WRDSF_INCREMENTAL) Total number of
|
||||
words returned so far */
|
||||
|
||||
const char *ws_delim; /* [Input] (WRDSF_DELIM) Word delimiters. */
|
||||
const char *ws_comment; /* [Input] (WRDSF_COMMENT) Comment characters. */
|
||||
const char *ws_escape[2]; /* [Input] (WRDSF_ESCAPE) Characters to be escaped
|
||||
with backslash. */
|
||||
void (*ws_alloc_die) (struct wordsplit *wsp);
|
||||
/* [Input] (WRDSF_ALLOC_DIE) Function called when
|
||||
out of memory. Must not return. */
|
||||
void (*ws_error) (const char *, ...)
|
||||
_GL_ATTRIBUTE_FORMAT ((printf, 1, 2));
|
||||
/* [Input] (WRDSF_ERROR) Function used for error
|
||||
reporting */
|
||||
void (*ws_debug) (const char *, ...)
|
||||
_GL_ATTRIBUTE_FORMAT ((printf, 1, 2));
|
||||
/* [Input] (WRDSF_DEBUG) Function used for debug
|
||||
output. */
|
||||
const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of
|
||||
environment variables. */
|
||||
|
||||
char **ws_envbuf;
|
||||
idx_t ws_envidx;
|
||||
idx_t ws_envsiz;
|
||||
|
||||
int (*ws_getvar) (char **ret, const char *var, idx_t len, void *clos);
|
||||
/* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up
|
||||
the name VAR (LEN bytes long) in the table of
|
||||
variables and if found returns in memory
|
||||
location pointed to by RET the value of that
|
||||
variable. Returns WRDSE_OK (0) on success,
|
||||
and an error code (see WRDSE_* defines below)
|
||||
on error. User-specific errors can be returned
|
||||
by storing the error diagnostic string in RET
|
||||
and returning WRDSE_USERERR.
|
||||
Whatever is stored in RET, it must be allocated
|
||||
using malloc(3). */
|
||||
void *ws_closure; /* [Input] (WRDSF_CLOSURE) Passed as the CLOS
|
||||
argument to ws_getvar and ws_command. */
|
||||
int (*ws_command) (char **ret, const char *cmd, idx_t len, char **argv,
|
||||
void *clos);
|
||||
/* [Input] (!WRDSF_NOCMD) Returns in the memory
|
||||
location pointed to by RET the expansion of
|
||||
the command CMD (LEN bytes long). If WRDSO_ARGV
|
||||
option is set, ARGV contains CMD split out to
|
||||
words. Otherwise ARGV is NULL.
|
||||
|
||||
See ws_getvar for a discussion of possible
|
||||
return values. */
|
||||
|
||||
const char *ws_input; /* Input string (the S argument to wordsplit. */
|
||||
idx_t ws_len; /* Length of ws_input. */
|
||||
idx_t ws_endp; /* Points past the last processed byte in
|
||||
ws_input. */
|
||||
int ws_errno; /* [Output] Error code, if an error occurred.
|
||||
This is not the same as a POSIX errno value. */
|
||||
char *ws_usererr; /* Points to textual description of
|
||||
the error, if ws_errno is WRDSE_USERERR. Must
|
||||
be allocated with malloc(3). */
|
||||
struct wordsplit_node *ws_head, *ws_tail;
|
||||
/* Doubly-linked list of parsed out nodes. */
|
||||
idx_t ws_lvl; /* Invocation nesting level. */
|
||||
};
|
||||
|
||||
/* Wordsplit flags. */
|
||||
/* Append the words found to the array resulting from a previous
|
||||
call. */
|
||||
#define WRDSF_APPEND 0x00000001
|
||||
/* Insert ws_offs initial NULLs in the array ws_wordv.
|
||||
(These are not counted in the returned ws_wordc.) */
|
||||
#define WRDSF_DOOFFS 0x00000002
|
||||
/* Don't do command substitution. */
|
||||
#define WRDSF_NOCMD 0x00000004
|
||||
/* The parameter p resulted from a previous call to
|
||||
wordsplit(), and wordsplit_free() was not called. Reuse the
|
||||
allocated storage. */
|
||||
#define WRDSF_REUSE 0x00000008
|
||||
/* Print errors */
|
||||
#define WRDSF_SHOWERR 0x00000010
|
||||
/* Consider it an error if an undefined variable is expanded. */
|
||||
#define WRDSF_UNDEF 0x00000020
|
||||
/* Don't do variable expansion. */
|
||||
#define WRDSF_NOVAR 0x00000040
|
||||
/* Abort on ENOMEM error */
|
||||
#define WRDSF_ENOMEMABRT 0x00000080
|
||||
/* Trim off any leading and trailind whitespace */
|
||||
#define WRDSF_WS 0x00000100
|
||||
/* Handle single quotes */
|
||||
#define WRDSF_SQUOTE 0x00000200
|
||||
/* Handle double quotes */
|
||||
#define WRDSF_DQUOTE 0x00000400
|
||||
/* Handle single and double quotes */
|
||||
#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE)
|
||||
/* Replace each input sequence of repeated delimiters with a single
|
||||
delimiter */
|
||||
#define WRDSF_SQUEEZE_DELIMS 0x00000800
|
||||
/* Return delimiters */
|
||||
#define WRDSF_RETURN_DELIMS 0x00001000
|
||||
/* Treat sed expressions as words */
|
||||
#define WRDSF_SED_EXPR 0x00002000
|
||||
/* ws_delim field is initialized */
|
||||
#define WRDSF_DELIM 0x00004000
|
||||
/* ws_comment field is initialized */
|
||||
#define WRDSF_COMMENT 0x00008000
|
||||
/* ws_alloc_die field is initialized */
|
||||
#define WRDSF_ALLOC_DIE 0x00010000
|
||||
/* ws_error field is initialized */
|
||||
#define WRDSF_ERROR 0x00020000
|
||||
/* ws_debug field is initialized */
|
||||
#define WRDSF_DEBUG 0x00040000
|
||||
/* ws_env field is initialized */
|
||||
#define WRDSF_ENV 0x00080000
|
||||
/* ws_getvar field is initialized */
|
||||
#define WRDSF_GETVAR 0x00100000
|
||||
/* enable debugging */
|
||||
#define WRDSF_SHOWDBG 0x00200000
|
||||
/* Don't split input into words. Useful for side effects. */
|
||||
#define WRDSF_NOSPLIT 0x00400000
|
||||
/* Keep undefined variables in place, instead of expanding them to
|
||||
empty strings. */
|
||||
#define WRDSF_KEEPUNDEF 0x00800000
|
||||
/* Warn about undefined variables */
|
||||
#define WRDSF_WARNUNDEF 0x01000000
|
||||
/* Handle C escapes */
|
||||
#define WRDSF_CESCAPES 0x02000000
|
||||
/* ws_closure is set */
|
||||
#define WRDSF_CLOSURE 0x04000000
|
||||
/* ws_env is a Key/Value environment, i.e. the value of a variable is
|
||||
stored in the element that follows its name. */
|
||||
#define WRDSF_ENV_KV 0x08000000
|
||||
/* ws_escape is set */
|
||||
#define WRDSF_ESCAPE 0x10000000
|
||||
/* Incremental mode */
|
||||
#define WRDSF_INCREMENTAL 0x20000000
|
||||
/* Perform pathname and tilde expansion */
|
||||
#define WRDSF_PATHEXPAND 0x40000000
|
||||
/* ws_options is initialized */
|
||||
#define WRDSF_OPTIONS 0x80000000
|
||||
|
||||
#define WRDSF_DEFFLAGS \
|
||||
(WRDSF_NOVAR | WRDSF_NOCMD | \
|
||||
WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES)
|
||||
|
||||
/* Remove the word that produces empty string after path expansion */
|
||||
#define WRDSO_NULLGLOB 0x00000001
|
||||
/* Print error message if path expansion produces empty string */
|
||||
#define WRDSO_FAILGLOB 0x00000002
|
||||
/* Allow a leading period to be matched by metacharacters. */
|
||||
#define WRDSO_DOTGLOB 0x00000004
|
||||
/* ws_command needs argv parameter */
|
||||
#define WRDSO_ARGV 0x00000008
|
||||
/* Keep backslash in unrecognized escape sequences in words */
|
||||
#define WRDSO_BSKEEP_WORD 0x00000010
|
||||
/* Handle octal escapes in words */
|
||||
#define WRDSO_OESC_WORD 0x00000020
|
||||
/* Handle hex escapes in words */
|
||||
#define WRDSO_XESC_WORD 0x00000040
|
||||
|
||||
/* ws_maxwords field is initialized */
|
||||
#define WRDSO_MAXWORDS 0x00000080
|
||||
|
||||
/* Keep backslash in unrecognized escape sequences in quoted strings */
|
||||
#define WRDSO_BSKEEP_QUOTE 0x00000100
|
||||
/* Handle octal escapes in quoted strings */
|
||||
#define WRDSO_OESC_QUOTE 0x00000200
|
||||
/* Handle hex escapes in quoted strings */
|
||||
#define WRDSO_XESC_QUOTE 0x00000400
|
||||
|
||||
#define WRDSO_BSKEEP WRDSO_BSKEEP_WORD
|
||||
#define WRDSO_OESC WRDSO_OESC_WORD
|
||||
#define WRDSO_XESC WRDSO_XESC_WORD
|
||||
|
||||
/* Indices into ws_escape */
|
||||
#define WRDSX_WORD 0
|
||||
#define WRDSX_QUOTE 1
|
||||
|
||||
/* Error codes. */
|
||||
#define WRDSE_OK 0
|
||||
#define WRDSE_EOF WRDSE_OK
|
||||
#define WRDSE_QUOTE 1
|
||||
#define WRDSE_NOSPACE 2
|
||||
#define WRDSE_USAGE 3
|
||||
#define WRDSE_CBRACE 4
|
||||
#define WRDSE_UNDEF 5
|
||||
#define WRDSE_NOINPUT 6
|
||||
#define WRDSE_PAREN 7
|
||||
#define WRDSE_GLOBERR 8
|
||||
#define WRDSE_USERERR 9
|
||||
|
||||
int wordsplit (char const *s, struct wordsplit *ws, unsigned flags);
|
||||
void wordsplit_free (struct wordsplit *ws);
|
||||
char const *wordsplit_strerror (struct wordsplit const *ws);
|
||||
|
||||
#ifdef _WORDSPLIT_EXTRAS
|
||||
int wordsplit_len (const char *s, idx_t len, wordsplit_t *ws, unsigned flags);
|
||||
void wordsplit_free_words (wordsplit_t *ws);
|
||||
void wordsplit_free_envbuf (wordsplit_t *ws);
|
||||
void wordsplit_get_words (wordsplit_t *ws, idx_t *wordc, char ***wordv);
|
||||
|
||||
int wordsplit_append (wordsplit_t *wsp, int argc, char **argv);
|
||||
|
||||
char wordsplit_c_unquote_char (char c);
|
||||
char wordsplit_c_quote_char (char c);
|
||||
idx_t wordsplit_c_quoted_length (const char *str, bool quote_hex, bool *quote);
|
||||
void wordsplit_c_quote_copy (char *dst, const char *src, bool quote_hex);
|
||||
|
||||
void wordsplit_perror (wordsplit_t *ws);
|
||||
|
||||
void wordsplit_clearerr (wordsplit_t *ws);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
114
lib/xattr-at.c
Normal file
114
lib/xattr-at.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/* openat-style fd-relative functions for operating with extended file
|
||||
attributes.
|
||||
|
||||
Copyright 2012-2025 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "xattr-at.h"
|
||||
#include "openat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
#include "save-cwd.h"
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
|
||||
/* setxattrat */
|
||||
#define AT_FUNC_NAME setxattrat
|
||||
#define AT_FUNC_F1 setxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, const void *value \
|
||||
, size_t size, int flags
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size, flags
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* lsetxattrat */
|
||||
#define AT_FUNC_NAME lsetxattrat
|
||||
#define AT_FUNC_F1 lsetxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, const void *value \
|
||||
, size_t size, int flags
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size, flags
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* getxattrat */
|
||||
#define AT_FUNC_NAME getxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 getxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, void *value \
|
||||
, size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* lgetxattrat */
|
||||
#define AT_FUNC_NAME lgetxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 lgetxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, void *value \
|
||||
, size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , name, value, size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* listxattrat */
|
||||
#define AT_FUNC_NAME listxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 listxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , char *list , size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , list , size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* llistxattrat */
|
||||
#define AT_FUNC_NAME llistxattrat
|
||||
#define AT_FUNC_RESULT ssize_t
|
||||
#define AT_FUNC_F1 llistxattr
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , char *list , size_t size
|
||||
#define AT_FUNC_POST_FILE_ARGS , list , size
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#endif /* HAVE_XATTRS */
|
||||
75
lib/xattr-at.h
Normal file
75
lib/xattr-at.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Prototypes for openat-style fd-relative functions for operating with
|
||||
extended file attributes.
|
||||
|
||||
Copyright 2012-2025 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef XATTRS_AT_H
|
||||
#define XATTRS_AT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(HAVE_SYS_XATTR_H)
|
||||
# include <sys/xattr.h>
|
||||
#elif defined(HAVE_ATTR_XATTR_H)
|
||||
# include <attr/xattr.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef ENOATTR
|
||||
# define ENOATTR ENODATA /* No such attribute */
|
||||
#endif
|
||||
|
||||
/* These are the dir-fd-relative variants of the functions without the
|
||||
"at" suffix. For example, setxattrat (AT_FDCWD, path, name, value, size,
|
||||
flags &c) is usually equivalent to setxattr (file, name, value, size,
|
||||
flags). For more info use the setxattr(2), getxattr(2) or listxattr(2)
|
||||
manpages. */
|
||||
|
||||
/* dir-fd-relative setxattr. Operation sets the VALUE of the extended
|
||||
attribute identified by NAME and associated with the given PATH in the
|
||||
filesystem relatively to directory identified by DIR_FD. See the
|
||||
setxattr(2) manpage for the description of all parameters. */
|
||||
int setxattrat (int dir_fd, const char *path, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
|
||||
/* dir-fd-relative lsetxattr. This function is just like setxattrat,
|
||||
except when DIR_FD and FILE specify a symlink: lsetxattrat operates on the
|
||||
symlink, while the setxattrat operates on the referent of the symlink. */
|
||||
int lsetxattrat (int dir_fd, const char *path, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
|
||||
/* dir-fd-relative getxattr. Operation gets the VALUE of the extended
|
||||
attribute identified by NAME and associated with the given PATH in the
|
||||
filesystem relatively to directory identified by DIR_FD. For more info
|
||||
about all parameters see the getxattr(2) manpage. */
|
||||
ssize_t getxattrat (int dir_fd, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
|
||||
/* dir-fd-relative lgetxattr. This function is just like getxattrat,
|
||||
except when DIR_FD and FILE specify a symlink: lgetxattrat operates on the
|
||||
symlink, while the getxattrat operates on the referent of the symlink. */
|
||||
ssize_t lgetxattrat (int dir_fd, const char *path, const char *name,
|
||||
void *value, size_t size);
|
||||
|
||||
/* dir-fd-relative listxattr. Obtain the list of extended attributes names. For
|
||||
more info see the listxattr(2) manpage. */
|
||||
ssize_t listxattrat (int dir_fd, const char *path, char *list, size_t size);
|
||||
|
||||
/* dir-fd-relative llistxattr. This function is just like listxattrat,
|
||||
except when DIR_FD and FILE specify a symlink: llistxattr operates on the
|
||||
symlink, while the listxattrat operates on the referent of the symlink. */
|
||||
ssize_t llistxattrat (int dir_fd, const char *path, char *list, size_t size);
|
||||
|
||||
#endif /* XATTRS_AT_H */
|
||||
1
paxutils
Submodule
1
paxutils
Submodule
Submodule paxutils added at 063408cc6f
21
po/.gitignore
vendored
21
po/.gitignore
vendored
@@ -1,22 +1,23 @@
|
||||
/Makefile.in.in
|
||||
/Makevars.template
|
||||
/Rules-quot
|
||||
/boldquot.sed
|
||||
/en@boldquot.header
|
||||
/en@quot.header
|
||||
/insert-header.sin
|
||||
/quot.sed
|
||||
/remove-potcdate.sed
|
||||
/remove-potcdate.sin
|
||||
*.gmo
|
||||
*.mo
|
||||
*.po
|
||||
*~
|
||||
.reference
|
||||
LINGUAS
|
||||
Makefile
|
||||
Makefile.in
|
||||
Makefile.in.in
|
||||
Makevars
|
||||
Makevars.template
|
||||
POTFILES
|
||||
Rules-quot
|
||||
boldquot.sed
|
||||
en@boldquot.header
|
||||
en@quot.header
|
||||
insert-header.sed
|
||||
insert-header.sin
|
||||
quot.sed
|
||||
remove-potcdate.sed
|
||||
remove-potcdate.sin
|
||||
stamp-po
|
||||
tar.pot
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
# List of files which contain translatable strings.
|
||||
|
||||
# Copyright (C) 1996, 1999, 2000, 2003, 2004, 2005, 2007 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright 1996-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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 3, or (at your option)
|
||||
# any later version.
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Library files
|
||||
gnu/argmatch.c
|
||||
@@ -37,7 +36,6 @@ gnu/version-etc.c
|
||||
gnu/xalloc-die.c
|
||||
|
||||
lib/paxerror.c
|
||||
lib/paxexit.c
|
||||
lib/paxnames.c
|
||||
lib/rtapelib.c
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
# Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
# Make GNU tar scripts.
|
||||
|
||||
## 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 3, or (at your option)
|
||||
## any later version.
|
||||
# Copyright 2004-2025 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 file is part of GNU tar.
|
||||
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
BACKUP_LIBEXEC_SCRIPTS_LIST=backup.sh dump-remind
|
||||
BACKUP_SBIN_SCRIPTS_LIST=backup restore
|
||||
|
||||
@@ -11,12 +11,12 @@ TAR=/bin/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
|
||||
RSH=/usr/bin/ssh
|
||||
|
||||
# (Optional) Path to rsh binary on remote mashines. This will be
|
||||
# (Optional) Path to rsh binary on remote machines. This will be
|
||||
# passed via --rsh-command option to the remote invocation of
|
||||
# tar
|
||||
RSH_COMMAND=/usr/local/bin/ssh
|
||||
RSH_COMMAND=/usr/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.
|
||||
@@ -43,7 +43,7 @@ BACKUP_DIRS='remote1:/etc remote1:/var/spool/crontab'
|
||||
# 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.
|
||||
# These should be accessible 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
|
||||
@@ -82,19 +82,19 @@ SLEEP_MESSAGE="`awk '
|
||||
}' /dev/null`"
|
||||
|
||||
|
||||
# Copyright (C) 2004, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2004-2025 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 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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 3 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright (C) 2004, 2005, 2006 Free Software Foundation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2006, 2013, 2019 Free Software Foundation
|
||||
|
||||
# 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 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# the Free Software Foundation; either version 3 of the License, 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
@@ -72,8 +73,9 @@ do
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l?*) DUMP_LEVEL=`expr $option : '-l\(.*\)'`;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
prev=--level
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
@@ -81,14 +83,13 @@ do
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
-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
|
||||
-t?*) TIME=`expr $option : '-t\(.*\)'`;;
|
||||
-t|--t|--ti|--tim|--time)
|
||||
prev=--time
|
||||
;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "backup (@PACKAGE_NAME@) @VERSION@"
|
||||
@@ -148,13 +149,16 @@ 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
|
||||
# The bunch 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}"
|
||||
if ! $MT_BEGIN "${TAPE_FILE}"; then
|
||||
echo >&2 "$0: tape initialization failed"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "${VOLNO_FILE}"
|
||||
|
||||
message 1 "processing backup directories"
|
||||
@@ -187,10 +191,10 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
"--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
|
||||
# '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
|
||||
echo "$0: 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
|
||||
@@ -237,17 +241,17 @@ message 20 "BACKUP_FILES=$BACKUP_FILES"
|
||||
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}"
|
||||
RC=$?
|
||||
|
||||
if test "${ADMINISTRATOR}" != NONE; then
|
||||
echo "Sending the dump log to ${ADMINISTRATOR}"
|
||||
mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
|
||||
fi
|
||||
|
||||
exit $RC
|
||||
# EOF
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Make backups.
|
||||
|
||||
# Copyright 2004-2025 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 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# the Free Software Foundation; either version 3 of the License, 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PROGNAME=`basename $0`
|
||||
CONFIGPATH="$SYSCONFDIR/backup"
|
||||
@@ -48,7 +49,7 @@ MT_REWIND=mt_rewind
|
||||
MT_OFFLINE=mt_offline
|
||||
MT_STATUS=mt_status
|
||||
|
||||
# Insure `mail' is in PATH.
|
||||
# Insure 'mail' is in PATH.
|
||||
PATH="/usr/ucb:${PATH}"
|
||||
export PATH
|
||||
# Put startdate in the subject line of mailed report, since if it happens
|
||||
@@ -211,8 +212,8 @@ init_backup() {
|
||||
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'.
|
||||
# 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}"
|
||||
@@ -305,12 +306,14 @@ backup_host() {
|
||||
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
|
||||
# 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: $?"
|
||||
RC=$?
|
||||
message 10 "RC: $RC"
|
||||
return $RC
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -339,9 +342,9 @@ remote_run() {
|
||||
|
||||
license() {
|
||||
cat - <<EOF
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
This is free software. You may redistribute copies of it under the terms of
|
||||
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
|
||||
Copyright (C) 2013, 2025 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -7,9 +7,25 @@
|
||||
# This script should be run by tar with --info-script (-F) to inform
|
||||
# interested parties that a tape for the next volume of the backup needs to
|
||||
# be put in the tape drive.
|
||||
#
|
||||
|
||||
# Include location of `sendmail' and GNU finger.
|
||||
# Copyright 2004-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Include location of 'sendmail' and GNU finger.
|
||||
PATH="/usr/lib:/usr/local/gnubin:${PATH}"
|
||||
export PATH
|
||||
|
||||
@@ -25,8 +41,8 @@ MT_OFFLINE
|
||||
# which users are logged into consoles (and thus in the office and capable
|
||||
# of changing tapes).
|
||||
#
|
||||
# Certain users (like `root') aren't real users, and shouldn't be notified.
|
||||
# Neither should `zippy', `elvis', etc. (on the GNU machines) since they're
|
||||
# Certain users (like 'root') aren't real users, and shouldn't be notified.
|
||||
# Neither should 'zippy', 'elvis', etc. (on the GNU machines) since they're
|
||||
# just test accounts.
|
||||
recipients="`
|
||||
finger .clients 2> /dev/null \
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#! /bin/sh
|
||||
# This program is part of GNU tar
|
||||
# Copyright (C) 2004, 2006 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Restore backups.
|
||||
|
||||
# Copyright 2004-2025 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 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# the Free Software Foundation; either version 3 of the License, 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Load library routines
|
||||
SYSCONFDIR=${SYSCONFDIR-@sysconfdir@}
|
||||
@@ -60,8 +61,9 @@ do
|
||||
--l=*|--le=*|--lev=*|--leve=*|--level=*)
|
||||
DUMP_LEVEL=$optarg
|
||||
;;
|
||||
-l?*) DUMP_LEVEL=`expr $option : '-l\(.*\)'`;;
|
||||
-l|--l|--le|--lev|--leve|--level)
|
||||
prev=$option
|
||||
prev=--level
|
||||
;;
|
||||
--verb=*|--verbo=*|--verbos=*|--verbose=*)
|
||||
VERBOSE=$optarg
|
||||
@@ -69,7 +71,7 @@ do
|
||||
-v|--verb|--verbo|--verbos|--verbose)
|
||||
VERBOSE=100
|
||||
;;
|
||||
-v*) VERBOSE=`expr $option : "-v\(.*\)"`;;
|
||||
-v*) VERBOSE=`expr $option : '-v\(.*\)'`;;
|
||||
-V|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "restore (@PACKAGE_NAME@) @VERSION@"
|
||||
license
|
||||
@@ -181,7 +183,7 @@ restore_files()
|
||||
done
|
||||
}
|
||||
|
||||
# Operation Overwiew:
|
||||
# Operation Overview:
|
||||
#
|
||||
# 1. Determine the time of the last backup
|
||||
# 2. Create list of incremental listings to process
|
||||
|
||||
@@ -1,31 +1,66 @@
|
||||
#! /usr/bin/perl -w
|
||||
# Display and edit the 'dev' field in tar's snapshots
|
||||
# Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# Copyright 2007-2025 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 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# the Free Software Foundation; either version 3 of the License, 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
#
|
||||
# Author: Dustin J. Mitchell <dustin@zmanda.com>
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# tar-snapshot-edit
|
||||
#
|
||||
# This script is capable of replacing values in the 'dev' field of an
|
||||
# incremental backup 'snapshot' file. This is useful when the device
|
||||
# used to store files in a tar archive changes, without the files
|
||||
# themselves changing. This may happen when, for example, a device
|
||||
# driver changes major or minor numbers.
|
||||
#
|
||||
# It can also run a check on all the field values found in the
|
||||
# snapshot file, printing out a detailed message when it finds values
|
||||
# that would cause an "Unexpected field value in snapshot file",
|
||||
# "Numerical result out of range", or "Invalid argument" error
|
||||
# if tar were run using that snapshot file as input. (See the
|
||||
# comments included in the definition of the check_field_values
|
||||
# routine for more detailed information regarding these checks.)
|
||||
#
|
||||
#
|
||||
#
|
||||
# Author: Dustin J. Mitchell <dustin@zmanda.com>
|
||||
#
|
||||
# Modified Aug 25, 2011 by Nathan Stratton Treadway <nathanst AT ontko.com>:
|
||||
# * update Perl syntax to work correctly with more recent versions of
|
||||
# Perl. (The original code worked with in the v5.8 timeframe but
|
||||
# not with Perl v5.10.1 and later.)
|
||||
# * added a "-c" option to check the snapshot file for invalid field values.
|
||||
# * handle NFS indicator character ("+") in version 0 and 1 files
|
||||
# * preserve the original header/version line when editing version 1
|
||||
# or 2 files.
|
||||
# * tweak output formatting
|
||||
#
|
||||
# Modified March 13, 2013 by Nathan Stratton Treadway <nathanst AT ontko.com>:
|
||||
# * configure field ranges used for -c option based on the system
|
||||
# architecture (in response to the December 2012 update to GNU tar
|
||||
# enabling support for systems with signed dev_t values).
|
||||
# * when printing the list of device ids found in the snapshot file
|
||||
# (when run in the default mode), print the raw device id values
|
||||
# instead of the hex-string version in those cases where they
|
||||
# can't be converted successfully.
|
||||
|
||||
use Getopt::Std;
|
||||
use Config;
|
||||
|
||||
my %snapshot_field_ranges; # used in check_field_values function
|
||||
|
||||
## reading
|
||||
|
||||
@@ -41,14 +76,15 @@ sub read_incr_db ($) {
|
||||
$file_version = 0;
|
||||
}
|
||||
|
||||
print "file version $file_version\n";
|
||||
print "\nFile: $filename\n";
|
||||
print " Detected snapshot file version: $file_version\n\n";
|
||||
|
||||
if ($file_version == 0) {
|
||||
return read_incr_db_0($file, $header_str);
|
||||
} elsif ($file_version == 1) {
|
||||
return read_incr_db_1($file);
|
||||
return read_incr_db_1($file, $header_str);
|
||||
} elsif ($file_version == 2) {
|
||||
return read_incr_db_2($file);
|
||||
return read_incr_db_2($file, $header_str);
|
||||
} else {
|
||||
die "Unrecognized snapshot version in header '$header_str'";
|
||||
}
|
||||
@@ -62,48 +98,66 @@ sub read_incr_db_0 ($$) {
|
||||
chop $hdr_timestamp_sec;
|
||||
my $hdr_timestamp_nsec = ''; # not present in file format 0
|
||||
|
||||
my $nfs;
|
||||
my @dirs;
|
||||
|
||||
while (<$file>) {
|
||||
/^([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
/^(\+?)([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
|
||||
push @dirs, { dev=>$1,
|
||||
ino=>$2,
|
||||
name=>$3 };
|
||||
if ( $1 eq "+" ) {
|
||||
$nfs="1";
|
||||
} else {
|
||||
$nfs="0";
|
||||
}
|
||||
push @dirs, { nfs=>$nfs,
|
||||
dev=>$2,
|
||||
ino=>$3,
|
||||
name=>$4 };
|
||||
}
|
||||
|
||||
close($file);
|
||||
|
||||
# file version, timestamp, timestamp, dir list
|
||||
return [ 0, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs ];
|
||||
# file version, timestamp, timestamp, dir list, file header line
|
||||
return [ 0, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs, ""];
|
||||
}
|
||||
|
||||
sub read_incr_db_1 ($) {
|
||||
sub read_incr_db_1 ($$) {
|
||||
my $file = shift;
|
||||
my $header_str = shift;
|
||||
|
||||
|
||||
my $timestamp = <$file>; # "sec nsec"
|
||||
my ($hdr_timestamp_sec, $hdr_timestamp_nsec) = ($timestamp =~ /([0-9]*) ([0-9]*)/);
|
||||
|
||||
my $nfs;
|
||||
my @dirs;
|
||||
|
||||
while (<$file>) {
|
||||
/^([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
/^(\+?)([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*) (.*)\n$/ || die("Bad snapshot line $_");
|
||||
|
||||
push @dirs, { timestamp_sec=>$1,
|
||||
timestamp_nsec=>$2,
|
||||
dev=>$3,
|
||||
ino=>$4,
|
||||
name=>$5 };
|
||||
if ( $1 eq "+" ) {
|
||||
$nfs="1";
|
||||
} else {
|
||||
$nfs="0";
|
||||
}
|
||||
|
||||
push @dirs, { nfs=>$nfs,
|
||||
timestamp_sec=>$2,
|
||||
timestamp_nsec=>$3,
|
||||
dev=>$4,
|
||||
ino=>$5,
|
||||
name=>$6 };
|
||||
}
|
||||
|
||||
close($file);
|
||||
|
||||
# file version, timestamp, timestamp, dir list
|
||||
return [ 1, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs ];
|
||||
# file version, timestamp, timestamp, dir list, file header line
|
||||
return [ 1, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs, $header_str ];
|
||||
}
|
||||
|
||||
sub read_incr_db_2 ($) {
|
||||
sub read_incr_db_2 ($$) {
|
||||
my $file = shift;
|
||||
my $header_str = shift;
|
||||
|
||||
$/="\0"; # $INPUT_RECORD_SEPARATOR
|
||||
my $hdr_timestamp_sec = <$file>;
|
||||
@@ -150,40 +204,257 @@ sub read_incr_db_2 ($) {
|
||||
close($file);
|
||||
$/ = "\n"; # reset to normal
|
||||
|
||||
# file version, timestamp, timestamp, dir list
|
||||
return [ 2, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs ];
|
||||
# file version, timestamp, timestamp, dir list, file header line
|
||||
return [ 2, $hdr_timestamp_sec, $hdr_timestamp_nsec, \@dirs, $header_str];
|
||||
}
|
||||
|
||||
## display
|
||||
|
||||
sub show_device_counts ($$) {
|
||||
sub show_device_counts ($) {
|
||||
my $info = shift;
|
||||
my $filename = shift;
|
||||
my %devices;
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
my $dev = ${%$dir}{'dev'};
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
my $dev = $dir->{'dev'};
|
||||
$devices{$dev}++;
|
||||
}
|
||||
|
||||
foreach $dev (sort keys %devices) {
|
||||
printf "$filename: Device 0x%04x occurs $devices{$dev} times.\n", $dev;
|
||||
my $devstr;
|
||||
foreach $dev (sort {$a <=> $b} keys %devices) {
|
||||
$devstr = sprintf ("0x%04x", $dev);
|
||||
if ( $dev > 0xffffffff or $dev < 0 or hex($devstr) != $dev ) {
|
||||
# sprintf "%x" will not return a useful value for device ids
|
||||
# that are negative or which overflow the integer size on this
|
||||
# instance of Perl, so we convert the hex string back to a
|
||||
# number, and if it doesn't (numerically) equal the original
|
||||
# device id value, we know the hex conversion hasn't worked.
|
||||
#
|
||||
# Unfortunately, since we're running in "-w" mode, Perl will
|
||||
# also print a warning message if the hex() routine is called
|
||||
# on anything larger than "0xffffffff", even in 64-bit Perl
|
||||
# where such values are actually supported... so we have to
|
||||
# avoid calling hex() at all if the device id is too large or
|
||||
# negative. (If it's negative, the conversion to an unsigned
|
||||
# integer for the "%x" specifier will mean the result will
|
||||
# always trigger hex()'s warning on a 64-bit machine.)
|
||||
#
|
||||
# These situations don't seem to occur very often, so for now
|
||||
# when they do occur, we simply print the original text value
|
||||
# that was read from the snapshot file; it will look a bit
|
||||
# funny next to the values that do print in hex, but that's
|
||||
# preferable to printing values that aren't actually correct.
|
||||
$devstr = $dev;
|
||||
}
|
||||
printf " Device %s occurs $devices{$dev} times.\n", $devstr;
|
||||
}
|
||||
}
|
||||
|
||||
## check field values
|
||||
|
||||
# initializes the global %snapshot_field_ranges hash, based on the "-a"
|
||||
# command-line option if given, otherwise based on the "archname" of
|
||||
# the current system.
|
||||
#
|
||||
# Each value in the hash is a two-element array containing the minimum
|
||||
# and maximum allowed values, respectively, for that field in the snapshot
|
||||
# file. GNU tar's allowed values for each architecture are determined
|
||||
# in the incremen.c source file, where the TYPE_MIN and TYPE_MAX
|
||||
# pre-processor expressions are used to determine the range that can be
|
||||
# expressed by the C data type used for each field; the values in the
|
||||
# array defined below should match those calculations. (For tar v1.27
|
||||
# and later, the valid ranges for a particular tar binary can easily
|
||||
# be determined using the "tar --show-snapshot-field-ranges" command.)
|
||||
|
||||
sub choose_architecture ($) {
|
||||
my $opt_a = shift;
|
||||
|
||||
my $arch = $opt_a ? $opt_a : $Config{'archname'};
|
||||
|
||||
# These ranges apply to Linux 2.4/2.6 on iX86 systems, but are used
|
||||
# by default on unrecognized/unsupported systems, too.
|
||||
%iX86_linux_field_ranges = (
|
||||
timestamp_sec => [ -2147483648, 2147483647 ], # min/max of time_t
|
||||
timestamp_nsec => [ 0, 999999999 ], # 0 to BILLION-1
|
||||
nfs => [ 0, 1 ],
|
||||
dev => [ 0, 18446744073709551615 ], # min/max of dev_t
|
||||
ino => [ 0, 4294967295 ], # min/max of ino_t
|
||||
);
|
||||
|
||||
|
||||
if ( $arch =~ m/^i[\dxX]86-linux/i ) {
|
||||
%snapshot_field_ranges = %iX86_linux_field_ranges;
|
||||
print "Checking snapshot field values using \"iX86-linux\" ranges.\n\n";
|
||||
} elsif ( $arch =~ m/^x86_64-linux/i ) {
|
||||
%snapshot_field_ranges = (
|
||||
timestamp_sec => [ -9223372036854775808, 9223372036854775807 ],
|
||||
timestamp_nsec => [ 0, 999999999 ],
|
||||
nfs => [ 0, 1 ],
|
||||
dev => [ 0, 18446744073709551615 ],
|
||||
ino => [ 0, 18446744073709551615 ],
|
||||
);
|
||||
print "Checking snapshot field values using \"x86_64-linux\" ranges.\n\n";
|
||||
} elsif ( $arch =~ m/^IA64.ARCHREV_0/i ) {
|
||||
# HP/UX running on Itanium/ia64 architecture
|
||||
%snapshot_field_ranges = (
|
||||
timestamp_sec => [ -2147483648, 2147483647 ],
|
||||
timestamp_nsec => [ 0, 999999999 ],
|
||||
nfs => [ 0, 1 ],
|
||||
dev => [ -2147483648, 2147483647 ],
|
||||
ino => [ 0, 4294967295 ],
|
||||
);
|
||||
print "Checking snapshot field values using \"IA64.ARCHREV_0\" (HP/UX) ranges.\n\n";
|
||||
} else {
|
||||
%snapshot_field_ranges = %iX86_linux_field_ranges;
|
||||
print "Unrecognized architecture \"$arch\"; defaulting to \"iX86-linux\".\n";
|
||||
print "(Use -a option to override.)\n" unless $opt_a;
|
||||
print "\n";
|
||||
}
|
||||
|
||||
if ( ref(1) ne "" ) {
|
||||
print "(\"bignum\" mode is in effect; skipping 64-bit-integer check.)\n\n"
|
||||
} else {
|
||||
# find the largest max value in the current set of ranges
|
||||
my $maxmax = 0;
|
||||
for $v (values %snapshot_field_ranges ) {
|
||||
$maxmax = $v->[1] if ($v->[1] > $maxmax);
|
||||
}
|
||||
|
||||
# "~0" translates into a platform-native integer with all bits turned
|
||||
# on -- that is, the largest value that can be represented as
|
||||
# an integer. We print a warning if our $maxmax value is greater
|
||||
# than that largest integer, since in that case Perl will switch
|
||||
# to using floats for those large max values. The wording of
|
||||
# the message assumes that the only way this situation can exist
|
||||
# is that the platform uses 32-bit integers but some of the
|
||||
# snapshot-file fields have 64-bit values.
|
||||
if ( ~0 < $maxmax ) {
|
||||
print <<EOF
|
||||
Note: this version of Perl uses 32-bit integers, which means that it
|
||||
will switch to using floating-point numbers when checking the ranges
|
||||
for 64-bit snapshot-file fields. This normally will work fine, but
|
||||
might fail to detect cases where the value in the input field value is
|
||||
only slightly out of range. (For example, a "9223372036854775808"
|
||||
might not be recognized as being larger than 9223372036854775807.)
|
||||
If you suspect you are experiencing this problem, you can try running
|
||||
the program using the "-Mbignum" option, as in
|
||||
\$ perl $0 -Mbignum -c [FILES]
|
||||
(but doing so will make the program run *much* slower).
|
||||
|
||||
EOF
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
# returns a warning message if $field_value isn't a valid string
|
||||
# representation of an integer, or if the resulting integer is out of range
|
||||
# defined by the two-element array retrieved using up the $field_name key in
|
||||
# the global %snapshot_field_ranges hash.
|
||||
sub validate_integer_field ($$) {
|
||||
my $field_value = shift;
|
||||
my $field_name = shift;
|
||||
|
||||
my ($min, $max) = @{$snapshot_field_ranges{$field_name}};
|
||||
|
||||
my $msg = "";
|
||||
|
||||
if ( not $field_value =~ /^-?\d+$/ ) {
|
||||
$msg = " $field_name value contains invalid characters: \"$field_value\"\n";
|
||||
} else {
|
||||
if ( $field_value < $min ) {
|
||||
$msg = " $field_name value too low: \"$field_value\" < $min \n";
|
||||
} elsif ( $field_value > $max ) {
|
||||
$msg = " $field_name value too high: \"$field_value\" > $max \n";
|
||||
}
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
|
||||
# This routine loops through each directory entry in the $info data
|
||||
# structure and prints a warning message if tar would abort with an
|
||||
# "Unexpected field value in snapshot file", "Numerical result out of
|
||||
# range", or "Invalid argument" error upon reading this snapshot file.
|
||||
#
|
||||
# (Note that the "Unexpected field value in snapshot file" error message
|
||||
# was introduced along with the change to snapshot file format "2",
|
||||
# starting with tar v1.16 [or, more precisely, v1.15.91], while the
|
||||
# other two were introduced in v1.27.)
|
||||
#
|
||||
# The checks here are intended to match those found in the incremen.c
|
||||
# source file. See the choose_architecture() function (above) for more
|
||||
# information on how to configure the range of values considered valid
|
||||
# by this script.
|
||||
#
|
||||
# (Note: the checks here are taken from the code that processes
|
||||
# version 2 snapshot files, but to keep things simple we apply those
|
||||
# same checks to files having earlier versions -- but only for
|
||||
# the fields that actually exist in those input files.)
|
||||
|
||||
sub check_field_values ($) {
|
||||
my $info = shift;
|
||||
|
||||
my $msg;
|
||||
my $error_found = 0;
|
||||
|
||||
print " Checking field values in snapshot file...\n";
|
||||
|
||||
$snapver = $info->[0];
|
||||
|
||||
$msg = "";
|
||||
$msg .= validate_integer_field($info->[1], 'timestamp_sec');
|
||||
if ($snapver >= 1) {
|
||||
$msg .= validate_integer_field($info->[2], 'timestamp_nsec');
|
||||
}
|
||||
if ( $msg ne "" ) {
|
||||
$error_found = 1;
|
||||
print "\n snapshot file header:\n";
|
||||
print $msg;
|
||||
}
|
||||
|
||||
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
|
||||
$msg = "";
|
||||
|
||||
$msg .= validate_integer_field($dir->{'nfs'}, 'nfs');
|
||||
if ($snapver >= 1) {
|
||||
$msg .= validate_integer_field($dir->{'timestamp_sec'}, 'timestamp_sec');
|
||||
$msg .= validate_integer_field($dir->{'timestamp_nsec'}, 'timestamp_nsec');
|
||||
}
|
||||
$msg .= validate_integer_field($dir->{'dev'}, 'dev');
|
||||
$msg .= validate_integer_field($dir->{'ino'}, 'ino');
|
||||
|
||||
if ( $msg ne "" ) {
|
||||
$error_found = 1;
|
||||
print "\n directory: $dir->{'name'}\n";
|
||||
print $msg;
|
||||
}
|
||||
}
|
||||
|
||||
print "\n Snapshot field value check complete" ,
|
||||
$error_found ? "" : ", no errors found" ,
|
||||
".\n";
|
||||
}
|
||||
|
||||
## editing
|
||||
|
||||
sub replace_device_number ($@) {
|
||||
my $info = shift(@_);
|
||||
my @repl = @_;
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
foreach $x (@repl) {
|
||||
if (${%$dir}{'dev'} eq $$x[0]) {
|
||||
${%$dir}{'dev'} = $$x[1];
|
||||
last;
|
||||
}
|
||||
my $count = 0;
|
||||
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
foreach $x (@repl) {
|
||||
if ($dir->{'dev'} eq $$x[0]) {
|
||||
$dir->{'dev'} = $$x[1];
|
||||
$count++;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
print " Updated $count records.\n"
|
||||
}
|
||||
|
||||
## writing
|
||||
@@ -215,10 +486,13 @@ sub write_incr_db_0 ($$) {
|
||||
my $timestamp_sec = $info->[1];
|
||||
print $file "$timestamp_sec\n";
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
print $file "${%$dir}{'dev'} ";
|
||||
print $file "${%$dir}{'ino'} ";
|
||||
print $file "${%$dir}{'name'}\n";
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
if ($dir->{'nfs'}) {
|
||||
print $file '+'
|
||||
}
|
||||
print $file "$dir->{'dev'} ";
|
||||
print $file "$dir->{'ino'} ";
|
||||
print $file "$dir->{'name'}\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,18 +501,21 @@ sub write_incr_db_1 ($$) {
|
||||
my $info = shift;
|
||||
my $file = shift;
|
||||
|
||||
print $file "GNU tar-1.15-1\n";
|
||||
print $file $info->[4];
|
||||
|
||||
my $timestamp_sec = $info->[1];
|
||||
my $timestamp_nsec = $info->[2];
|
||||
print $file "$timestamp_sec $timestamp_nsec\n";
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
print $file "${%$dir}{'timestamp_sec'} ";
|
||||
print $file "${%$dir}{'timestamp_nsec'} ";
|
||||
print $file "${%$dir}{'dev'} ";
|
||||
print $file "${%$dir}{'ino'} ";
|
||||
print $file "${%$dir}{'name'}\n";
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
if ($dir->{'nfs'}) {
|
||||
print $file '+'
|
||||
}
|
||||
print $file "$dir->{'timestamp_sec'} ";
|
||||
print $file "$dir->{'timestamp_nsec'} ";
|
||||
print $file "$dir->{'dev'} ";
|
||||
print $file "$dir->{'ino'} ";
|
||||
print $file "$dir->{'name'}\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,21 +524,21 @@ sub write_incr_db_2 ($$) {
|
||||
my $info = shift;
|
||||
my $file = shift;
|
||||
|
||||
print $file "GNU tar-1.16-2\n";
|
||||
print $file $info->[4];
|
||||
|
||||
my $timestamp_sec = $info->[1];
|
||||
my $timestamp_nsec = $info->[2];
|
||||
print $file $timestamp_sec . "\0";
|
||||
print $file $timestamp_nsec . "\0";
|
||||
|
||||
foreach my $dir (@{${@$info}[3]}) {
|
||||
print $file ${%$dir}{'nfs'} . "\0";
|
||||
print $file ${%$dir}{'timestamp_sec'} . "\0";
|
||||
print $file ${%$dir}{'timestamp_nsec'} . "\0";
|
||||
print $file ${%$dir}{'dev'} . "\0";
|
||||
print $file ${%$dir}{'ino'} . "\0";
|
||||
print $file ${%$dir}{'name'} . "\0";
|
||||
foreach my $dirent (@{${%$dir}{'dirents'}}) {
|
||||
foreach my $dir (@{$info->[3]}) {
|
||||
print $file $dir->{'nfs'} . "\0";
|
||||
print $file $dir->{'timestamp_sec'} . "\0";
|
||||
print $file $dir->{'timestamp_nsec'} . "\0";
|
||||
print $file $dir->{'dev'} . "\0";
|
||||
print $file $dir->{'ino'} . "\0";
|
||||
print $file $dir->{'name'} . "\0";
|
||||
foreach my $dirent (@{$dir->{'dirents'}}) {
|
||||
print $file $dirent . "\0";
|
||||
}
|
||||
print $file "\0";
|
||||
@@ -271,9 +548,10 @@ sub write_incr_db_2 ($$) {
|
||||
## main
|
||||
|
||||
sub main {
|
||||
our ($opt_b, $opt_r, $opt_h);
|
||||
getopts('br:h');
|
||||
HELP_MESSAGE() if ($opt_h || $#ARGV == -1 || ($opt_b && !$opt_r));
|
||||
our ($opt_b, $opt_r, $opt_h, $opt_c, $opt_a);
|
||||
getopts('br:hca:');
|
||||
HELP_MESSAGE() if ($opt_h || $#ARGV == -1 || ($opt_b && !$opt_r) ||
|
||||
($opt_a && !$opt_c) || ($opt_r && $opt_c) );
|
||||
|
||||
my @repl;
|
||||
if ($opt_r) {
|
||||
@@ -283,31 +561,61 @@ sub main {
|
||||
}
|
||||
}
|
||||
|
||||
choose_architecture($opt_a) if ($opt_c);
|
||||
|
||||
foreach my $snapfile (@ARGV) {
|
||||
my $info = read_incr_db($snapfile);
|
||||
if ($opt_r ) {
|
||||
if ($opt_r) {
|
||||
if ($opt_b) {
|
||||
rename($snapfile, $snapfile . "~") || die "Could not rename '$snapfile' to backup";
|
||||
}
|
||||
|
||||
replace_device_number($info, @repl);
|
||||
write_incr_db($info, $snapfile);
|
||||
} elsif ($opt_c) {
|
||||
check_field_values($info);
|
||||
} else {
|
||||
show_device_counts($info, $snapfile);
|
||||
show_device_counts($info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub HELP_MESSAGE {
|
||||
print "Usage: tar-snapshot-edit.pl [-r 'DEV1-DEV2[,DEV3-DEV4...]' [-b]] SNAPFILE [SNAPFILE [..]]\n";
|
||||
print "\n";
|
||||
print " Without -r, summarize the 'device' values in each SNAPFILE.\n";
|
||||
print "\n";
|
||||
print " With -r, replace occurrences of DEV1 with DEV2 in each SNAPFILE.\n";
|
||||
print " DEV1 and DEV2 may be specified in hex (e.g., 0xfe01), decimal (e.g.,\n";
|
||||
print " 65025), or MAJ:MIN (e.g., 254:1). To replace multiple occurrences,\n";
|
||||
print " separate them with commas. If -b is also specified, backup\n";
|
||||
print " files (ending with '~') will be created.\n";
|
||||
print <<EOF;
|
||||
|
||||
Usage:
|
||||
tar-snapshot-edit SNAPFILE [SNAPFILE [...]]
|
||||
tar-snapshot-edit -r 'DEV1-DEV2[,DEV3-DEV4...]' [-b] SNAPFILE [SNAPFILE [...]]
|
||||
tar-snapshot-edit -c [-aARCH] SNAPFILE [SNAPFILE [...]]
|
||||
|
||||
With no options specified: print a summary of the 'device' values
|
||||
found in each SNAPFILE.
|
||||
|
||||
With -r: replace occurrences of DEV1 with DEV2 in each SNAPFILE.
|
||||
DEV1 and DEV2 may be specified in hex (e.g., 0xfe01), decimal (e.g.,
|
||||
65025), or MAJ:MIN (e.g., 254:1). To replace multiple occurrences,
|
||||
separate them with commas. If -b is also specified, backup files
|
||||
(ending with '~') will be created.
|
||||
|
||||
With -c: Check the field values in each SNAPFILE and print warning
|
||||
messages if any invalid values are found. (An invalid value is one
|
||||
that would cause \"tar\" to abort with an error message such as
|
||||
Unexpected field value in snapshot file
|
||||
Numerical result out of range
|
||||
or
|
||||
Invalid argument
|
||||
as it processed the snapshot file.)
|
||||
|
||||
Normally the program automatically chooses the valid ranges for
|
||||
the fields based on the current system's architecture, but the
|
||||
-a option can be used to override the selection, e.g. in order
|
||||
to validate a snapshot file generated on a some other system.
|
||||
(Currently only three architectures are supported, "iX86-linux",
|
||||
"x86_64-linux", and "IA64.ARCHREV_0" [HP/UX running on Itanium/ia64],
|
||||
and if the current system isn't recognized, then the iX86-linux
|
||||
values are used by default.)
|
||||
|
||||
EOF
|
||||
exit 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
# concatenates a GNU tar multi-volume archive into a single tar archive.
|
||||
# Author: Bruno Haible <bruno@clisp.org>, Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
# Copyright 2004-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# dump_type FILE [N]
|
||||
# Print type character from block N (default 0) of tar archive FILE
|
||||
dump_type() {
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
/* xsparse - expands compressed sparse file images extracted from GNU tar
|
||||
archives.
|
||||
|
||||
Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
|
||||
Copyright 2006-2025 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff
|
||||
This file is part of GNU tar.
|
||||
|
||||
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 3, or (at your option) any later
|
||||
version.
|
||||
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 3 of the License, 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.
|
||||
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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Sergey Poznyakoff */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Bound on length of the string representing an off_t.
|
||||
See INT_STRLEN_BOUND in intprops.h for explanation */
|
||||
@@ -43,10 +45,10 @@ struct sp_array
|
||||
off_t numbytes;
|
||||
};
|
||||
|
||||
char *progname;
|
||||
int verbose;
|
||||
static char *progname;
|
||||
static bool verbose;
|
||||
|
||||
void
|
||||
static void
|
||||
die (int code, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -59,58 +61,42 @@ die (int code, char *fmt, ...)
|
||||
exit (code);
|
||||
}
|
||||
|
||||
void *
|
||||
static void *
|
||||
emalloc (size_t size)
|
||||
{
|
||||
char *p = malloc (size);
|
||||
if (!p)
|
||||
if (!p && size)
|
||||
die (1, "not enough memory");
|
||||
return p;
|
||||
}
|
||||
|
||||
off_t
|
||||
static off_t
|
||||
string_to_off (char *p, char **endp)
|
||||
{
|
||||
off_t v = 0;
|
||||
|
||||
for (; *p; p++)
|
||||
{
|
||||
int digit = *p - '0';
|
||||
off_t x = v * 10;
|
||||
if (9 < (unsigned) digit)
|
||||
{
|
||||
if (endp)
|
||||
{
|
||||
*endp = p;
|
||||
break;
|
||||
}
|
||||
die (1, "number parse error near %s", p);
|
||||
}
|
||||
else if (x / 10 != v)
|
||||
die (1, "number out of allowed range, near %s", p);
|
||||
v = x + digit;
|
||||
if (v < 0)
|
||||
die (1, "negative number");
|
||||
}
|
||||
if (endp)
|
||||
*endp = p;
|
||||
errno = 0;
|
||||
intmax_t i = strtoimax (p, endp, 10);
|
||||
off_t v = i;
|
||||
if (i < 0 || v != i || errno == ERANGE)
|
||||
die (1, "number out of allowed range, near %s", p);
|
||||
if (errno || p == *endp)
|
||||
die (1, "number parse error near %s", p);
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t
|
||||
string_to_size (char *p, char **endp)
|
||||
static size_t
|
||||
string_to_size (char *p, char **endp, size_t maxsize)
|
||||
{
|
||||
off_t v = string_to_off (p, endp);
|
||||
size_t ret = v;
|
||||
if (ret != v)
|
||||
if (! (ret == v && ret <= maxsize))
|
||||
die (1, "number too big");
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t sparse_map_size;
|
||||
struct sp_array *sparse_map;
|
||||
static size_t sparse_map_size;
|
||||
static struct sp_array *sparse_map;
|
||||
|
||||
void
|
||||
static void
|
||||
get_line (char *s, int size, FILE *stream)
|
||||
{
|
||||
char *p = fgets (s, size, stream);
|
||||
@@ -120,11 +106,11 @@ get_line (char *s, int size, FILE *stream)
|
||||
die (1, "unexpected end of file");
|
||||
len = strlen (p);
|
||||
if (s[len - 1] != '\n')
|
||||
die (1, "buffer overflow");
|
||||
s[len - 1] = 0;
|
||||
die (1, "invalid or too-long data");
|
||||
s[len - 1] = '\0';
|
||||
}
|
||||
|
||||
int
|
||||
static bool
|
||||
get_var (FILE *fp, char **name, char **value)
|
||||
{
|
||||
static char *buffer;
|
||||
@@ -137,12 +123,12 @@ get_var (FILE *fp, char **name, char **value)
|
||||
size_t len, s;
|
||||
|
||||
if (!fgets (buffer, bufsize, fp))
|
||||
return 0;
|
||||
return false;
|
||||
len = strlen (buffer);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
s = string_to_size (buffer, &p);
|
||||
s = string_to_size (buffer, &p, SIZE_MAX - 1);
|
||||
if (*p != ' ')
|
||||
die (1, "malformed header: expected space but found %s", p);
|
||||
if (buffer[len-1] != '\n')
|
||||
@@ -159,30 +145,29 @@ get_var (FILE *fp, char **name, char **value)
|
||||
}
|
||||
p++;
|
||||
}
|
||||
while (memcmp (p, "GNU.sparse.", 11));
|
||||
while (strncmp (p, "GNU.sparse.", 11) != 0);
|
||||
|
||||
p += 11;
|
||||
q = strchr (p, '=');
|
||||
if (!q)
|
||||
die (1, "malformed header: expected `=' not found");
|
||||
die (1, "malformed header: expected '=' not found");
|
||||
*q++ = 0;
|
||||
q[strlen (q) - 1] = 0;
|
||||
*name = p;
|
||||
*value = q;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
char *outname;
|
||||
off_t outsize;
|
||||
unsigned version_major;
|
||||
unsigned version_minor;
|
||||
static char *outname;
|
||||
static off_t outsize;
|
||||
static off_t version_major;
|
||||
static off_t version_minor;
|
||||
|
||||
void
|
||||
static void
|
||||
read_xheader (char *name)
|
||||
{
|
||||
char *kw, *val;
|
||||
FILE *fp = fopen (name, "r");
|
||||
char *expect = NULL;
|
||||
size_t i = 0;
|
||||
|
||||
if (verbose)
|
||||
@@ -193,10 +178,6 @@ read_xheader (char *name)
|
||||
if (verbose)
|
||||
printf ("Found variable GNU.sparse.%s = %s\n", kw, val);
|
||||
|
||||
if (expect && strcmp (kw, expect))
|
||||
die (1, "bad keyword sequence: expected `%s' but found `%s'",
|
||||
expect, kw);
|
||||
expect = NULL;
|
||||
if (strcmp (kw, "name") == 0)
|
||||
{
|
||||
outname = emalloc (strlen (val) + 1);
|
||||
@@ -204,11 +185,11 @@ read_xheader (char *name)
|
||||
}
|
||||
else if (strcmp (kw, "major") == 0)
|
||||
{
|
||||
version_major = string_to_size (val, NULL);
|
||||
version_major = string_to_off (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "minor") == 0)
|
||||
{
|
||||
version_minor = string_to_size (val, NULL);
|
||||
version_minor = string_to_off (val, NULL);
|
||||
}
|
||||
else if (strcmp (kw, "realsize") == 0
|
||||
|| strcmp (kw, "size") == 0)
|
||||
@@ -217,17 +198,27 @@ read_xheader (char *name)
|
||||
}
|
||||
else if (strcmp (kw, "numblocks") == 0)
|
||||
{
|
||||
sparse_map_size = string_to_size (val, NULL);
|
||||
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
|
||||
sparse_map_size = string_to_size (val, NULL,
|
||||
SIZE_MAX / sizeof *sparse_map);
|
||||
if (sparse_map_size)
|
||||
{
|
||||
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
|
||||
sparse_map[0].offset = -1;
|
||||
}
|
||||
}
|
||||
else if (strcmp (kw, "offset") == 0)
|
||||
{
|
||||
if (sparse_map_size <= i)
|
||||
die (1, "bad GNU.sparse.map: spurious offset");
|
||||
sparse_map[i].offset = string_to_off (val, NULL);
|
||||
expect = "numbytes";
|
||||
}
|
||||
else if (strcmp (kw, "numbytes") == 0)
|
||||
{
|
||||
if (sparse_map_size <= i || sparse_map[i].offset < 0)
|
||||
die (1, "bad GNU.sparse.map: spurious numbytes");
|
||||
sparse_map[i++].numbytes = string_to_off (val, NULL);
|
||||
if (i < sparse_map_size)
|
||||
sparse_map[i].offset = -1;
|
||||
}
|
||||
else if (strcmp (kw, "map") == 0)
|
||||
{
|
||||
@@ -235,13 +226,13 @@ read_xheader (char *name)
|
||||
{
|
||||
sparse_map[i].offset = string_to_off (val, &val);
|
||||
if (*val != ',')
|
||||
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
|
||||
die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
|
||||
*val);
|
||||
sparse_map[i].numbytes = string_to_off (val+1, &val);
|
||||
if (*val != ',')
|
||||
{
|
||||
if (!(*val == 0 && i == sparse_map_size-1))
|
||||
die (1, "bad GNU.sparse.map: expected `,' but found `%c'",
|
||||
die (1, "bad GNU.sparse.map: expected ',' but found '%c'",
|
||||
*val);
|
||||
}
|
||||
else
|
||||
@@ -251,16 +242,15 @@ read_xheader (char *name)
|
||||
die (1, "bad GNU.sparse.map: garbage at the end");
|
||||
}
|
||||
}
|
||||
if (expect)
|
||||
die (1, "bad keyword sequence: expected `%s' not found", expect);
|
||||
if (version_major == 0 && sparse_map_size == 0)
|
||||
die (1, "size of the sparse map unknown");
|
||||
if (i != sparse_map_size)
|
||||
die (1, "not all sparse entries supplied");
|
||||
fclose (fp);
|
||||
if (ferror (fp) || fclose (fp) < 0)
|
||||
die (1, "read error: %s", name);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
read_map (FILE *ifp)
|
||||
{
|
||||
size_t i;
|
||||
@@ -270,7 +260,7 @@ read_map (FILE *ifp)
|
||||
printf ("Reading v.1.0 sparse map\n");
|
||||
|
||||
get_line (nbuf, sizeof nbuf, ifp);
|
||||
sparse_map_size = string_to_size (nbuf, NULL);
|
||||
sparse_map_size = string_to_size (nbuf, NULL, SIZE_MAX / sizeof *sparse_map);
|
||||
sparse_map = emalloc (sparse_map_size * sizeof *sparse_map);
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
@@ -281,52 +271,51 @@ read_map (FILE *ifp)
|
||||
sparse_map[i].numbytes = string_to_off (nbuf, NULL);
|
||||
}
|
||||
|
||||
fseeko (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE,
|
||||
SEEK_SET);
|
||||
off_t ifp_offset = ftello (ifp);
|
||||
if (ifp_offset < 0)
|
||||
die (1, "ftello");
|
||||
if (ifp_offset % BLOCKSIZE != 0
|
||||
&& fseeko (ifp, BLOCKSIZE - ifp_offset % BLOCKSIZE, SEEK_CUR) < 0)
|
||||
die (1, "fseeko");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
expand_sparse (FILE *sfp, int ofd)
|
||||
{
|
||||
size_t i;
|
||||
off_t max_numbytes = 0;
|
||||
size_t maxbytes;
|
||||
char *buffer;
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
if (max_numbytes < sparse_map[i].numbytes)
|
||||
max_numbytes = sparse_map[i].numbytes;
|
||||
|
||||
maxbytes = max_numbytes < SIZE_MAX ? max_numbytes : SIZE_MAX;
|
||||
|
||||
for (buffer = malloc (maxbytes); !buffer; maxbytes /= 2)
|
||||
if (maxbytes == 0)
|
||||
die (1, "not enough memory");
|
||||
|
||||
for (i = 0; i < sparse_map_size; i++)
|
||||
{
|
||||
off_t size = sparse_map[i].numbytes;
|
||||
|
||||
if (size == 0)
|
||||
ftruncate (ofd, sparse_map[i].offset);
|
||||
{
|
||||
if (0 <= ofd && ftruncate (ofd, sparse_map[i].offset) < 0)
|
||||
die (1, "ftruncate error (%d)", errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
lseek (ofd, sparse_map[i].offset, SEEK_SET);
|
||||
if (0 <= ofd && lseek (ofd, sparse_map[i].offset, SEEK_SET) < 0)
|
||||
die (1, "lseek error (%d)", errno);
|
||||
while (size)
|
||||
{
|
||||
size_t rdsize = (size < maxbytes) ? size : maxbytes;
|
||||
char buffer[BUFSIZ];
|
||||
size_t rdsize = size < BUFSIZ ? size : BUFSIZ;
|
||||
if (rdsize != fread (buffer, 1, rdsize, sfp))
|
||||
die (1, "read error (%d)", errno);
|
||||
if (rdsize != write (ofd, buffer, rdsize))
|
||||
die (1, "write error (%d)", errno);
|
||||
if (0 <= ofd)
|
||||
{
|
||||
ssize_t written = write (ofd, buffer, rdsize);
|
||||
if (written != rdsize)
|
||||
die (1, "write error (%d)", written < 0 ? errno : 0);
|
||||
}
|
||||
size -= rdsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
usage (int code)
|
||||
{
|
||||
printf ("Usage: %s [OPTIONS] infile [outfile]\n", progname);
|
||||
@@ -341,58 +330,26 @@ usage (int code)
|
||||
exit (code);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
guess_outname (char *name)
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
|
||||
if (name[0] == '.' && name[1] == '/')
|
||||
name += 2;
|
||||
|
||||
p = name + strlen (name) - 1;
|
||||
s = NULL;
|
||||
|
||||
for (; p > name && *p != '/'; p--)
|
||||
;
|
||||
if (*p == '/')
|
||||
s = p + 1;
|
||||
if (p != name)
|
||||
{
|
||||
for (p--; p > name && *p != '/'; p--)
|
||||
;
|
||||
}
|
||||
|
||||
if (*p != '/')
|
||||
{
|
||||
if (s)
|
||||
outname = s;
|
||||
else
|
||||
{
|
||||
outname = emalloc (4 + strlen (name));
|
||||
strcpy (outname, "../");
|
||||
strcpy (outname + 3, name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t len = p - name + 1;
|
||||
outname = emalloc (len + strlen (s) + 1);
|
||||
memcpy (outname, name, len);
|
||||
strcpy (outname + len, s);
|
||||
}
|
||||
char *base = strrchr (name, '/');
|
||||
base = base ? base + 1 : name;
|
||||
size_t dirlen = base - name, baselen = strlen (base);
|
||||
static char const parentdir[] = "../";
|
||||
int parentdirlen = sizeof parentdir - 1;
|
||||
outname = emalloc (dirlen + parentdirlen + baselen + 1);
|
||||
memcpy (outname, name, dirlen);
|
||||
memcpy (outname + dirlen, parentdir, parentdirlen);
|
||||
memcpy (outname + dirlen + parentdirlen, base, baselen + 1);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
int dry_run = 0;
|
||||
bool dry_run = false;
|
||||
char *xheader_file = NULL;
|
||||
char *inname;
|
||||
FILE *ifp;
|
||||
struct stat st;
|
||||
int ofd;
|
||||
|
||||
progname = argv[0];
|
||||
while ((c = getopt (argc, argv, "hnvx:")) != EOF)
|
||||
@@ -408,9 +365,9 @@ main (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
dry_run = 1;
|
||||
dry_run = true;
|
||||
case 'v':
|
||||
verbose++;
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -427,15 +384,16 @@ main (int argc, char **argv)
|
||||
if (xheader_file)
|
||||
read_xheader (xheader_file);
|
||||
|
||||
inname = argv[0];
|
||||
char *inname = argv[0];
|
||||
if (argv[1])
|
||||
outname = argv[1];
|
||||
|
||||
if (stat (inname, &st))
|
||||
struct stat st;
|
||||
if (stat (inname, &st) < 0)
|
||||
die (1, "cannot stat %s (%d)", inname, errno);
|
||||
|
||||
ifp = fopen (inname, "r");
|
||||
if (ifp == NULL)
|
||||
FILE *ifp = fopen (inname, "r");
|
||||
if (!ifp)
|
||||
die (1, "cannot open file %s (%d)", inname, errno);
|
||||
|
||||
if (!xheader_file || version_major == 1)
|
||||
@@ -444,12 +402,26 @@ main (int argc, char **argv)
|
||||
if (!outname)
|
||||
guess_outname (inname);
|
||||
|
||||
ofd = open (outname, O_RDWR|O_CREAT|O_TRUNC, st.st_mode);
|
||||
if (ofd == -1)
|
||||
die (1, "cannot open file %s (%d)", outname, errno);
|
||||
if (verbose)
|
||||
printf ("Expanding file '%s' to '%s'\n", inname, outname);
|
||||
|
||||
int ofd = -1;
|
||||
if (!dry_run)
|
||||
{
|
||||
ofd = open (outname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode);
|
||||
if (ofd < 0)
|
||||
die (1, "cannot open file %s (%d)", outname, errno);
|
||||
}
|
||||
|
||||
expand_sparse (ifp, ofd);
|
||||
|
||||
if (ferror (ifp) || fclose (ifp) < 0)
|
||||
die (1, "input error: %s", inname);
|
||||
if (close (ofd) < 0)
|
||||
die (1, "output error: %s", outname);
|
||||
|
||||
if (verbose)
|
||||
printf ("Expanding file `%s' to `%s'\n", inname, outname);
|
||||
printf ("Done\n");
|
||||
|
||||
if (dry_run)
|
||||
{
|
||||
@@ -457,17 +429,9 @@ main (int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
expand_sparse (ifp, ofd);
|
||||
|
||||
fclose (ifp);
|
||||
close (ofd);
|
||||
|
||||
if (verbose)
|
||||
printf ("Done\n");
|
||||
|
||||
if (outsize)
|
||||
{
|
||||
if (stat (outname, &st))
|
||||
if (stat (outname, &st) < 0)
|
||||
die (1, "cannot stat output file %s (%d)", outname, errno);
|
||||
if (st.st_size != outsize)
|
||||
die (1, "expanded file has wrong size");
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
# Makefile for GNU tar sources.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2006,
|
||||
# 2007, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 1994-2025 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 3, or (at your option)
|
||||
## any later version.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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.
|
||||
# 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 3 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
bin_PROGRAMS = tar
|
||||
|
||||
noinst_HEADERS = arith.h common.h tar.h
|
||||
noinst_HEADERS = arith.h common.h tar.h xattrs.h
|
||||
tar_SOURCES = \
|
||||
buffer.c\
|
||||
checkpoint.c\
|
||||
@@ -28,10 +27,12 @@ tar_SOURCES = \
|
||||
create.c\
|
||||
delete.c\
|
||||
exit.c\
|
||||
exclist.c\
|
||||
extract.c\
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
list.c\
|
||||
map.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
sparse.c\
|
||||
@@ -42,10 +43,14 @@ tar_SOURCES = \
|
||||
unlink.c\
|
||||
update.c\
|
||||
utf8.c\
|
||||
warning.c
|
||||
warning.c\
|
||||
xattrs.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
|
||||
AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
|
||||
LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
|
||||
|
||||
tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
|
||||
tar_LDADD = $(LIBS) ../lib/libtar.a ../gnu/libgnu.a\
|
||||
$(LIB_ACL) $(QCOPY_ACL_LIB) $(CLOCK_TIME_LIB) $(EUIDACCESS_LIBGEN)\
|
||||
$(GETRANDOM_LIB) $(HARD_LOCALE_LIB) $(FILE_HAS_ACL_LIB) $(MBRTOWC_LIB)\
|
||||
$(LIB_SELINUX) $(SETLOCALE_NULL_LIB) \
|
||||
$(LIBINTL) $(LIBICONV)
|
||||
|
||||
15
src/arith.h
15
src/arith.h
@@ -1,19 +1,20 @@
|
||||
/* Long integers, for GNU tar.
|
||||
Copyright 1999, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1999-2025 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 3, or (at your option)
|
||||
any later version.
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
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 this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Handle large integers for calculating big tape lengths and the
|
||||
like. In practice, double precision does for now. On the vast
|
||||
|
||||
1061
src/buffer.c
1061
src/buffer.c
File diff suppressed because it is too large
Load Diff
450
src/checkpoint.c
450
src/checkpoint.c
@@ -1,23 +1,34 @@
|
||||
/* Checkpoint management for tar.
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
Copyright 2007-2025 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 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
|
||||
#include <wordsplit.h>
|
||||
|
||||
#include <flexmember.h>
|
||||
#include <fprintftime.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
enum checkpoint_opcode
|
||||
{
|
||||
cop_dot,
|
||||
@@ -25,7 +36,9 @@ enum checkpoint_opcode
|
||||
cop_echo,
|
||||
cop_ttyout,
|
||||
cop_sleep,
|
||||
cop_exec
|
||||
cop_exec,
|
||||
cop_totals,
|
||||
cop_wait
|
||||
};
|
||||
|
||||
struct checkpoint_action
|
||||
@@ -36,158 +49,317 @@ struct checkpoint_action
|
||||
{
|
||||
time_t time;
|
||||
char *command;
|
||||
int signal;
|
||||
} v;
|
||||
char commandbuf[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
/* Checkpointing counter */
|
||||
static unsigned checkpoint;
|
||||
static intmax_t checkpoint;
|
||||
|
||||
/* List of checkpoint actions */
|
||||
static struct checkpoint_action *checkpoint_action, *checkpoint_action_tail;
|
||||
static struct checkpoint_action *checkpoint_action,
|
||||
**checkpoint_action_tail = &checkpoint_action;
|
||||
|
||||
/* State of the checkpoint system */
|
||||
static enum {
|
||||
CHKP_INIT, /* Needs initialization */
|
||||
CHKP_COMPILE, /* Actions are being compiled */
|
||||
CHKP_RUN /* Actions are being run */
|
||||
} checkpoint_state;
|
||||
/* Blocked signals */
|
||||
static sigset_t sigs;
|
||||
|
||||
static struct checkpoint_action *
|
||||
alloc_action (enum checkpoint_opcode opcode)
|
||||
alloc_action (enum checkpoint_opcode opcode, char const *quoted_string)
|
||||
{
|
||||
struct checkpoint_action *p = xzalloc (sizeof *p);
|
||||
if (checkpoint_action_tail)
|
||||
checkpoint_action_tail->next = p;
|
||||
else
|
||||
checkpoint_action = p;
|
||||
checkpoint_action_tail = p;
|
||||
idx_t quoted_size = quoted_string ? strlen (quoted_string) + 1 : 0;
|
||||
struct checkpoint_action *p = xmalloc (FLEXSIZEOF (struct checkpoint_action,
|
||||
commandbuf, quoted_size));
|
||||
*checkpoint_action_tail = p;
|
||||
checkpoint_action_tail = &p->next;
|
||||
p->next = NULL;
|
||||
p->opcode = opcode;
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *
|
||||
copy_string_unquote (const char *str)
|
||||
{
|
||||
char *output = xstrdup (str);
|
||||
size_t len = strlen (output);
|
||||
if ((*output == '"' || *output == '\'')
|
||||
&& output[len-1] == *output)
|
||||
if (quoted_string)
|
||||
{
|
||||
memmove (output, output+1, len-2);
|
||||
output[len-2] = 0;
|
||||
p->v.command = memcpy (p->commandbuf, quoted_string, quoted_size);
|
||||
unquote_string (p->v.command);
|
||||
}
|
||||
unquote_string (output);
|
||||
return output;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_compile_action (const char *str)
|
||||
{
|
||||
struct checkpoint_action *act;
|
||||
if (checkpoint_state == CHKP_INIT)
|
||||
{
|
||||
sigemptyset (&sigs);
|
||||
checkpoint_state = CHKP_COMPILE;
|
||||
}
|
||||
|
||||
if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
|
||||
alloc_action (cop_dot);
|
||||
alloc_action (cop_dot, NULL);
|
||||
else if (strcmp (str, "bell") == 0)
|
||||
alloc_action (cop_bell);
|
||||
alloc_action (cop_bell, NULL);
|
||||
else if (strcmp (str, "echo") == 0)
|
||||
alloc_action (cop_echo);
|
||||
alloc_action (cop_echo, NULL)->v.command = NULL;
|
||||
else if (strncmp (str, "echo=", 5) == 0)
|
||||
{
|
||||
act = alloc_action (cop_echo);
|
||||
act->v.command = copy_string_unquote (str + 5);
|
||||
}
|
||||
alloc_action (cop_echo, str + 5);
|
||||
else if (strncmp (str, "exec=", 5) == 0)
|
||||
{
|
||||
act = alloc_action (cop_exec);
|
||||
act->v.command = copy_string_unquote (str + 5);
|
||||
}
|
||||
alloc_action (cop_exec, str + 5);
|
||||
else if (strncmp (str, "ttyout=", 7) == 0)
|
||||
{
|
||||
act = alloc_action (cop_ttyout);
|
||||
act->v.command = copy_string_unquote (str + 7);
|
||||
}
|
||||
alloc_action (cop_ttyout, str + 7);
|
||||
else if (strncmp (str, "sleep=", 6) == 0)
|
||||
{
|
||||
char const *arg = str + 6;
|
||||
char *p;
|
||||
time_t n = strtoul (str+6, &p, 10);
|
||||
if (*p)
|
||||
FATAL_ERROR ((0, 0, _("%s: not a valid timeout"), str));
|
||||
act = alloc_action (cop_sleep);
|
||||
act->v.time = n;
|
||||
alloc_action (cop_sleep, NULL)->v.time
|
||||
= stoint (arg, &p, NULL, 0, TYPE_MAXIMUM (time_t));
|
||||
if ((p == arg) | *p)
|
||||
paxfatal (0, _("%s: not a valid timeout"), str);
|
||||
}
|
||||
else if (strcmp (str, "totals") == 0)
|
||||
alloc_action (cop_totals, NULL);
|
||||
else if (strncmp (str, "wait=", 5) == 0)
|
||||
{
|
||||
int sig = decode_signal (str + 5);
|
||||
alloc_action (cop_wait, NULL)->v.signal = sig;
|
||||
sigaddset (&sigs, sig);
|
||||
}
|
||||
else
|
||||
FATAL_ERROR ((0, 0, _("%s: unknown checkpoint action"), str));
|
||||
paxfatal (0, _("%s: unknown checkpoint action"), str);
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_finish_compile ()
|
||||
checkpoint_finish_compile (void)
|
||||
{
|
||||
if (checkpoint_option)
|
||||
if (checkpoint_state == CHKP_INIT
|
||||
&& checkpoint_option
|
||||
&& !checkpoint_action)
|
||||
{
|
||||
if (!checkpoint_action)
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
}
|
||||
else if (checkpoint_action)
|
||||
/* Otherwise, set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
|
||||
if (checkpoint_state == CHKP_COMPILE)
|
||||
{
|
||||
sigprocmask (SIG_BLOCK, &sigs, NULL);
|
||||
|
||||
if (!checkpoint_option)
|
||||
/* set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
|
||||
checkpoint_state = CHKP_RUN;
|
||||
}
|
||||
}
|
||||
|
||||
static intmax_t
|
||||
getwidth (FILE *fp)
|
||||
{
|
||||
char const *columns;
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize ws;
|
||||
if (ioctl (fileno (fp), TIOCGWINSZ, &ws) == 0 && 0 < ws.ws_col)
|
||||
return ws.ws_col;
|
||||
#endif
|
||||
|
||||
columns = getenv ("COLUMNS");
|
||||
if (columns)
|
||||
{
|
||||
char *end;
|
||||
intmax_t col = stoint (columns, &end, NULL, 0, INTMAX_MAX);
|
||||
if (! (*end | !col))
|
||||
return col;
|
||||
}
|
||||
|
||||
return 80;
|
||||
}
|
||||
|
||||
static char *
|
||||
expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
|
||||
getarg (char const *input, char const **endp, char **argbuf, idx_t *arglen)
|
||||
{
|
||||
const char *opstr = do_write ? gettext ("write") : gettext ("read");
|
||||
size_t opstrlen = strlen (opstr);
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
char *cps = STRINGIFY_BIGINT (cpn, uintbuf);
|
||||
size_t cpslen = strlen (cps);
|
||||
const char *ip;
|
||||
char *op;
|
||||
char *output;
|
||||
size_t outlen = strlen (input); /* Initial guess */
|
||||
|
||||
/* Fix the initial length guess */
|
||||
for (ip = input; (ip = strchr (ip, '%')) != NULL; )
|
||||
if (input[0] == '{')
|
||||
{
|
||||
switch (ip[1])
|
||||
char *p = strchr (input + 1, '}');
|
||||
if (p)
|
||||
{
|
||||
case 'u':
|
||||
outlen += cpslen - 2;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
outlen += opstrlen - 2;
|
||||
idx_t n = p - input;
|
||||
if (n > *arglen)
|
||||
*argbuf = xpalloc (*argbuf, arglen, n - *arglen, -1, 1);
|
||||
n--;
|
||||
*endp = p + 1;
|
||||
(*argbuf)[n] = 0;
|
||||
return memcpy (*argbuf, input + 1, n);
|
||||
}
|
||||
ip++;
|
||||
}
|
||||
|
||||
output = xmalloc (outlen + 1);
|
||||
for (ip = input, op = output; *ip; )
|
||||
*endp = input;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool tty_cleanup;
|
||||
|
||||
static const char *def_format =
|
||||
"%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r";
|
||||
|
||||
static intmax_t
|
||||
format_checkpoint_string (FILE *fp, intmax_t len,
|
||||
const char *input, bool do_write,
|
||||
intmax_t cpn)
|
||||
{
|
||||
const char *opstr = do_write ? gettext ("write") : gettext ("read");
|
||||
const char *ip;
|
||||
|
||||
static char *argbuf = NULL;
|
||||
static idx_t arglen = 0;
|
||||
char *arg = NULL;
|
||||
|
||||
if (!input)
|
||||
{
|
||||
if (do_write)
|
||||
/* TRANSLATORS: This is a "checkpoint of write operation",
|
||||
*not* "Writing a checkpoint". */
|
||||
input = gettext ("Write checkpoint %u");
|
||||
else
|
||||
/* TRANSLATORS: This is a "checkpoint of read operation",
|
||||
*not* "Reading a checkpoint". */
|
||||
input = gettext ("Read checkpoint %u");
|
||||
}
|
||||
|
||||
for (ip = input; *ip; ip++)
|
||||
{
|
||||
if (*ip == '%')
|
||||
{
|
||||
switch (*++ip)
|
||||
if (*++ip == '{')
|
||||
{
|
||||
arg = getarg (ip, &ip, &argbuf, &arglen);
|
||||
if (!arg)
|
||||
{
|
||||
fputc ('%', fp);
|
||||
fputc (*ip, fp);
|
||||
len = add_printf (len, 2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (*ip)
|
||||
{
|
||||
case 'c':
|
||||
len = add_printf (len,
|
||||
format_checkpoint_string (fp, len, def_format,
|
||||
do_write, cpn));
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
op = stpcpy (op, cps);
|
||||
len = add_printf (len, fprintf (fp, "%jd", cpn));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
op = stpcpy (op, opstr);
|
||||
fputs (opstr, fp);
|
||||
len = add_printf (len, strlen (opstr));
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
len = add_printf (len,
|
||||
fprintf (fp, "%.0f",
|
||||
compute_duration_ns () / BILLION));
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
{
|
||||
static char const *const checkpoint_total_format[]
|
||||
= { "R", "W", "D" };
|
||||
char const *const *fmt = checkpoint_total_format, *fmtbuf[3];
|
||||
struct wordsplit ws;
|
||||
compute_duration_ns ();
|
||||
|
||||
if (arg)
|
||||
{
|
||||
ws.ws_delim = ",";
|
||||
if (wordsplit (arg, &ws,
|
||||
(WRDSF_NOVAR | WRDSF_NOCMD
|
||||
| WRDSF_QUOTE | WRDSF_DELIM))
|
||||
!= WRDSE_OK)
|
||||
paxerror (0, _("cannot split string '%s': %s"),
|
||||
arg, wordsplit_strerror (&ws));
|
||||
else if (3 < ws.ws_wordc)
|
||||
paxerror (0, _("too many words in '%s'"), arg);
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ws.ws_wordc; i++)
|
||||
fmtbuf[i] = ws.ws_wordv[i];
|
||||
for (; i < 3; i++)
|
||||
fmtbuf[i] = NULL;
|
||||
fmt = fmtbuf;
|
||||
}
|
||||
}
|
||||
len = add_printf (len, format_total_stats (fp, fmt, ',', 0));
|
||||
if (arg)
|
||||
wordsplit_free (&ws);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
{
|
||||
struct timespec ts = current_timespec ();
|
||||
const char *fmt = arg ? arg : "%c";
|
||||
struct tm *tm = localtime (&ts.tv_sec);
|
||||
len = add_printf (len,
|
||||
(tm ? fprintftime (fp, fmt, tm, 0, ts.tv_nsec)
|
||||
: fprintf (fp, "????""-??""-?? ??:??:??")));
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (0 <= len)
|
||||
{
|
||||
intmax_t w;
|
||||
if (!arg)
|
||||
w = getwidth (fp);
|
||||
else
|
||||
{
|
||||
char *end;
|
||||
w = stoint (arg, &end, NULL, 0, INTMAX_MAX);
|
||||
if ((end == arg) | *end)
|
||||
w = 80;
|
||||
}
|
||||
for (; w > len; len++)
|
||||
fputc (' ', fp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*op++ = '%';
|
||||
*op++ = *ip;
|
||||
fputc ('%', fp);
|
||||
fputc (*ip, fp);
|
||||
len = add_printf (len, 2);
|
||||
break;
|
||||
}
|
||||
ip++;
|
||||
arg = NULL;
|
||||
}
|
||||
else
|
||||
*op++ = *ip++;
|
||||
{
|
||||
fputc (*ip, fp);
|
||||
if (*ip == '\r')
|
||||
{
|
||||
len = 0;
|
||||
tty_cleanup = true;
|
||||
}
|
||||
else
|
||||
len = add_printf (len, 1);
|
||||
}
|
||||
}
|
||||
*op = 0;
|
||||
return output;
|
||||
fflush (fp);
|
||||
return len;
|
||||
}
|
||||
|
||||
static FILE *tty = NULL;
|
||||
|
||||
static void
|
||||
run_checkpoint_actions (bool do_write)
|
||||
{
|
||||
struct checkpoint_action *p;
|
||||
FILE *tty = NULL;
|
||||
|
||||
for (p = checkpoint_action; p; p = p->next)
|
||||
{
|
||||
@@ -210,26 +382,10 @@ run_checkpoint_actions (bool do_write)
|
||||
|
||||
case cop_echo:
|
||||
{
|
||||
char *tmp;
|
||||
const char *str = p->v.command;
|
||||
if (!str)
|
||||
{
|
||||
if (do_write)
|
||||
/* TRANSLATORS: This is a ``checkpoint of write operation'',
|
||||
*not* ``Writing a checkpoint''.
|
||||
E.g. in Spanish ``Punto de comprobaci@'on de escritura'',
|
||||
*not* ``Escribiendo un punto de comprobaci@'on'' */
|
||||
str = gettext ("Write checkpoint %u");
|
||||
else
|
||||
/* TRANSLATORS: This is a ``checkpoint of read operation'',
|
||||
*not* ``Reading a checkpoint''.
|
||||
E.g. in Spanish ``Punto de comprobaci@'on de lectura'',
|
||||
*not* ``Leyendo un punto de comprobaci@'on'' */
|
||||
str = gettext ("Read checkpoint %u");
|
||||
}
|
||||
tmp = expand_checkpoint_string (str, do_write, checkpoint);
|
||||
WARN ((0, 0, "%s", tmp));
|
||||
free (tmp);
|
||||
int n = fprintf (stderr, "%s: ", program_name);
|
||||
format_checkpoint_string (stderr, n, p->v.command, do_write,
|
||||
checkpoint);
|
||||
fputc ('\n', stderr);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -237,13 +393,8 @@ run_checkpoint_actions (bool do_write)
|
||||
if (!tty)
|
||||
tty = fopen ("/dev/tty", "w");
|
||||
if (tty)
|
||||
{
|
||||
char *tmp = expand_checkpoint_string (p->v.command, do_write,
|
||||
checkpoint);
|
||||
fprintf (tty, "%s", tmp);
|
||||
fflush (tty);
|
||||
free (tmp);
|
||||
}
|
||||
format_checkpoint_string (tty, 0, p->v.command, do_write,
|
||||
checkpoint);
|
||||
break;
|
||||
|
||||
case cop_sleep:
|
||||
@@ -255,10 +406,44 @@ run_checkpoint_actions (bool do_write)
|
||||
archive_name_cursor[0],
|
||||
checkpoint);
|
||||
break;
|
||||
|
||||
case cop_totals:
|
||||
compute_duration_ns ();
|
||||
print_total_stats ();
|
||||
break;
|
||||
|
||||
case cop_wait:
|
||||
{
|
||||
int n;
|
||||
sigwait (&sigs, &n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_flush_actions (void)
|
||||
{
|
||||
struct checkpoint_action *p;
|
||||
|
||||
for (p = checkpoint_action; p; p = p->next)
|
||||
{
|
||||
switch (p->opcode)
|
||||
{
|
||||
case cop_ttyout:
|
||||
if (tty && tty_cleanup)
|
||||
{
|
||||
intmax_t w = getwidth (tty);
|
||||
while (w--)
|
||||
fputc (' ', tty);
|
||||
fputc ('\r', tty);
|
||||
fflush (tty);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* nothing */;
|
||||
}
|
||||
}
|
||||
if (tty)
|
||||
fclose (tty);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -267,3 +452,14 @@ checkpoint_run (bool do_write)
|
||||
if (checkpoint_option && !(++checkpoint % checkpoint_option))
|
||||
run_checkpoint_actions (do_write);
|
||||
}
|
||||
|
||||
void
|
||||
checkpoint_finish (void)
|
||||
{
|
||||
if (checkpoint_option)
|
||||
{
|
||||
checkpoint_flush_actions ();
|
||||
if (tty)
|
||||
fclose (tty);
|
||||
}
|
||||
}
|
||||
|
||||
825
src/common.h
825
src/common.h
File diff suppressed because it is too large
Load Diff
325
src/compare.c
325
src/compare.c
@@ -1,34 +1,40 @@
|
||||
/* Diff files from a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
|
||||
2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988-2025 Free Software Foundation, Inc.
|
||||
|
||||
Written by John Gilmore, on 1987-04-30.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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 3, or (at your option) any later
|
||||
version.
|
||||
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 3 of the License, 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.
|
||||
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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by John Gilmore, on 1987-04-30. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
|
||||
#if HAVE_LINUX_FD_H
|
||||
# include <linux/fd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_MTIO_H
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include <alignalloc.h>
|
||||
#include <quotearg.h>
|
||||
#include <rmt.h>
|
||||
#include <same-inode.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Nonzero if we are verifying at the moment. */
|
||||
@@ -44,12 +50,13 @@ static char *diff_buffer;
|
||||
void
|
||||
diff_init (void)
|
||||
{
|
||||
void *ptr;
|
||||
diff_buffer = page_aligned_alloc (&ptr, record_size);
|
||||
diff_buffer = xalignalloc (getpagesize (), record_size);
|
||||
if (listed_incremental_option)
|
||||
read_directory_file ();
|
||||
}
|
||||
|
||||
enum { QUOTE_ARG, QUOTE_NAME };
|
||||
|
||||
/* Sigh about something that differs by writing a MESSAGE to stdlis,
|
||||
given MESSAGE is nonzero. Also set the exit status if not already. */
|
||||
void
|
||||
@@ -59,7 +66,7 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf (stdlis, "%s: ", quotearg_colon (st->file_name));
|
||||
fprintf (stdlis, "%s: ", quote_n_colon (QUOTE_NAME, st->file_name));
|
||||
va_start (ap, fmt);
|
||||
vfprintf (stdlis, fmt, ap);
|
||||
va_end (ap);
|
||||
@@ -70,21 +77,20 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
|
||||
}
|
||||
|
||||
/* Take a buffer returned by read_and_process and do nothing with it. */
|
||||
static int
|
||||
process_noop (size_t size __attribute__ ((unused)),
|
||||
char *data __attribute__ ((unused)))
|
||||
static bool
|
||||
process_noop (MAYBE_UNUSED idx_t size, MAYBE_UNUSED char *data)
|
||||
{
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
process_rawdata (size_t bytes, char *buffer)
|
||||
static bool
|
||||
process_rawdata (idx_t bytes, char *buffer)
|
||||
{
|
||||
size_t status = safe_read (diff_handle, diff_buffer, bytes);
|
||||
idx_t status = blocking_read (diff_handle, diff_buffer, bytes);
|
||||
|
||||
if (status != bytes)
|
||||
if (status < bytes)
|
||||
{
|
||||
if (status == SAFE_READ_ERROR)
|
||||
if (errno)
|
||||
{
|
||||
read_error (current_stat_info.file_name);
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
@@ -92,53 +98,48 @@ process_rawdata (size_t bytes, char *buffer)
|
||||
else
|
||||
{
|
||||
report_difference (¤t_stat_info,
|
||||
ngettext ("Could only read %lu of %lu byte",
|
||||
"Could only read %lu of %lu bytes",
|
||||
ngettext ("Could read only %td of %td byte",
|
||||
"Could read only %td of %td bytes",
|
||||
bytes),
|
||||
(unsigned long) status, (unsigned long) bytes);
|
||||
status, bytes);
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp (buffer, diff_buffer, bytes))
|
||||
if (memcmp (buffer, diff_buffer, bytes) != 0)
|
||||
{
|
||||
report_difference (¤t_stat_info, _("Contents differ"));
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Some other routine wants SIZE bytes in the archive. For each chunk
|
||||
of the archive, call PROCESSOR with the size of the chunk, and the
|
||||
address of the chunk it can work with. The PROCESSOR should return
|
||||
nonzero for success. Once it returns error, continue skipping
|
||||
without calling PROCESSOR anymore. */
|
||||
/* Some other routine wants ST->stat.st_size bytes in the archive.
|
||||
For each chunk of the archive, call PROCESSOR with the size of the chunk,
|
||||
and the address of the chunk it can work with. PROCESSOR should return
|
||||
true for success. Once it fails, continue skipping without calling
|
||||
PROCESSOR anymore. */
|
||||
|
||||
static void
|
||||
read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
|
||||
read_and_process (struct tar_stat_info *st, bool (*processor) (idx_t, char *))
|
||||
{
|
||||
union block *data_block;
|
||||
size_t data_size;
|
||||
off_t size = st->stat.st_size;
|
||||
|
||||
mv_begin_read (st);
|
||||
while (size)
|
||||
for (off_t size = st->stat.st_size; size; )
|
||||
{
|
||||
data_block = find_next_block ();
|
||||
union block *data_block = find_next_block ();
|
||||
if (! data_block)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in archive")));
|
||||
paxerror (0, _("Unexpected EOF in archive"));
|
||||
return;
|
||||
}
|
||||
|
||||
data_size = available_space_after (data_block);
|
||||
idx_t data_size = available_space_after (data_block);
|
||||
if (data_size > size)
|
||||
data_size = size;
|
||||
if (!(*processor) (data_size, data_block->buffer))
|
||||
if (!processor (data_size, charptr (data_block)))
|
||||
processor = process_noop;
|
||||
set_next_block_after ((union block *)
|
||||
(data_block->buffer + data_size - 1));
|
||||
set_next_block_after (charptr (data_block) + data_size - 1);
|
||||
size -= data_size;
|
||||
mv_size_left (size);
|
||||
}
|
||||
@@ -147,23 +148,18 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
|
||||
|
||||
/* Call either stat or lstat over STAT_DATA, depending on
|
||||
--dereference (-h), for a file which should exist. Diagnose any
|
||||
problem. Return nonzero for success, zero otherwise. */
|
||||
static int
|
||||
problem. Return true for success, false otherwise. */
|
||||
static bool
|
||||
get_stat_data (char const *file_name, struct stat *stat_data)
|
||||
{
|
||||
int status = deref_stat (file_name, stat_data);
|
||||
|
||||
if (status != 0)
|
||||
if (deref_stat (file_name, stat_data) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
stat_warn (file_name);
|
||||
else
|
||||
stat_error (file_name);
|
||||
(errno == ENOENT ? stat_warn : stat_error) (file_name);
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,23 +223,21 @@ diff_file (void)
|
||||
}
|
||||
else
|
||||
{
|
||||
int status;
|
||||
|
||||
if (current_stat_info.is_sparse)
|
||||
sparse_diff_file (diff_handle, ¤t_stat_info);
|
||||
else
|
||||
read_and_process (¤t_stat_info, process_rawdata);
|
||||
|
||||
if (atime_preserve_option == replace_atime_preserve)
|
||||
if (atime_preserve_option == replace_atime_preserve
|
||||
&& stat_data.st_size != 0)
|
||||
{
|
||||
struct timespec atime = get_stat_atime (&stat_data);
|
||||
if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
|
||||
!= 0)
|
||||
< 0)
|
||||
utime_error (file_name);
|
||||
}
|
||||
|
||||
status = close (diff_handle);
|
||||
if (status != 0)
|
||||
if (close (diff_handle) < 0)
|
||||
close_error (file_name);
|
||||
}
|
||||
}
|
||||
@@ -258,21 +252,22 @@ diff_link (void)
|
||||
|
||||
if (get_stat_data (current_stat_info.file_name, &file_data)
|
||||
&& get_stat_data (current_stat_info.link_name, &link_data)
|
||||
&& !sys_compare_links (&file_data, &link_data))
|
||||
&& !psame_inode (&file_data, &link_data))
|
||||
report_difference (¤t_stat_info,
|
||||
_("Not linked to %s"),
|
||||
quote (current_stat_info.link_name));
|
||||
quote_n_colon (QUOTE_ARG,
|
||||
current_stat_info.link_name));
|
||||
}
|
||||
|
||||
#ifdef HAVE_READLINK
|
||||
static void
|
||||
diff_symlink (void)
|
||||
{
|
||||
size_t len = strlen (current_stat_info.link_name);
|
||||
char *linkbuf = alloca (len + 1);
|
||||
char buf[1024];
|
||||
idx_t len = strlen (current_stat_info.link_name);
|
||||
char *linkbuf = len < sizeof buf ? buf : xmalloc (len + 1);
|
||||
|
||||
int status = readlinkat (chdir_fd, current_stat_info.file_name,
|
||||
linkbuf, len + 1);
|
||||
ssize_t status = readlinkat (chdir_fd, current_stat_info.file_name,
|
||||
linkbuf, len + 1);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
@@ -283,10 +278,12 @@ diff_symlink (void)
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
}
|
||||
else if (status != len
|
||||
|| strncmp (current_stat_info.link_name, linkbuf, len) != 0)
|
||||
|| memcmp (current_stat_info.link_name, linkbuf, len) != 0)
|
||||
report_difference (¤t_stat_info, _("Symlink differs"));
|
||||
|
||||
if (linkbuf != buf)
|
||||
free (linkbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
diff_special (void)
|
||||
@@ -322,82 +319,91 @@ diff_special (void)
|
||||
report_difference (¤t_stat_info, _("Mode differs"));
|
||||
}
|
||||
|
||||
static int
|
||||
/* Return zero if and only if A and B should be considered equal.
|
||||
for the purposes of dump directory comparison. */
|
||||
static char
|
||||
dumpdir_cmp (const char *a, const char *b)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
while (*a)
|
||||
switch (*a)
|
||||
{
|
||||
case 'Y':
|
||||
case 'N':
|
||||
if (!strchr ("YN", *b))
|
||||
/* If the null-terminated strings A and B are equal, other
|
||||
than possibly A's first byte being 'Y' where B's is 'N' or
|
||||
vice versa, advance A and B past the strings.
|
||||
Otherwise, return 1. */
|
||||
if (! (*b == 'Y' || *b == 'N'))
|
||||
return 1;
|
||||
if (strcmp(a + 1, b + 1))
|
||||
return 1;
|
||||
len = strlen (a) + 1;
|
||||
a += len;
|
||||
b += len;
|
||||
break;
|
||||
|
||||
a++, b++;
|
||||
FALLTHROUGH;
|
||||
case 'D':
|
||||
if (strcmp(a, b))
|
||||
/* If the null-terminated strings A and B are equal, advance A
|
||||
and B past them. Otherwise, return 1. */
|
||||
while (*a)
|
||||
if (*a++ != *b++)
|
||||
return 1;
|
||||
if (*b)
|
||||
return 1;
|
||||
len = strlen (a) + 1;
|
||||
a += len;
|
||||
b += len;
|
||||
a++, b++;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
case 'T':
|
||||
case 'X':
|
||||
return *b;
|
||||
|
||||
default:
|
||||
unreachable ();
|
||||
}
|
||||
return *b;
|
||||
}
|
||||
|
||||
static void
|
||||
diff_dumpdir (void)
|
||||
diff_dumpdir (struct tar_stat_info *dir)
|
||||
{
|
||||
const char *dumpdir_buffer;
|
||||
dev_t dev = 0;
|
||||
struct stat stat_data;
|
||||
|
||||
if (deref_stat (current_stat_info.file_name, &stat_data) != 0)
|
||||
if (dir->fd == 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
stat_warn (current_stat_info.file_name);
|
||||
void (*diag) (char const *) = NULL;
|
||||
int fd = subfile_open (dir->parent, dir->orig_file_name, open_read_flags);
|
||||
if (fd < 0)
|
||||
diag = open_diag;
|
||||
else if (fstat (fd, &dir->stat) < 0)
|
||||
{
|
||||
diag = stat_diag;
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
stat_error (current_stat_info.file_name);
|
||||
dir->fd = fd;
|
||||
if (diag)
|
||||
{
|
||||
file_removed_diag (dir->orig_file_name, false, diag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
dev = stat_data.st_dev;
|
||||
|
||||
dumpdir_buffer = directory_contents (scan_directory (¤t_stat_info));
|
||||
dumpdir_buffer = directory_contents (scan_directory (dir));
|
||||
|
||||
if (dumpdir_buffer)
|
||||
{
|
||||
if (dumpdir_cmp (current_stat_info.dumpdir, dumpdir_buffer))
|
||||
report_difference (¤t_stat_info, _("Contents differ"));
|
||||
if (dumpdir_cmp (dir->dumpdir, dumpdir_buffer) != 0)
|
||||
report_difference (dir, _("Contents differ"));
|
||||
}
|
||||
else
|
||||
read_and_process (¤t_stat_info, process_noop);
|
||||
read_and_process (dir, process_noop);
|
||||
}
|
||||
|
||||
static void
|
||||
diff_multivol (void)
|
||||
{
|
||||
struct stat stat_data;
|
||||
int fd, status;
|
||||
off_t offset;
|
||||
|
||||
if (current_stat_info.had_trailing_slash)
|
||||
{
|
||||
diff_dir ();
|
||||
return;
|
||||
}
|
||||
|
||||
struct stat stat_data;
|
||||
if (!get_stat_data (current_stat_info.file_name, &stat_data))
|
||||
return;
|
||||
|
||||
@@ -408,8 +414,11 @@ diff_multivol (void)
|
||||
return;
|
||||
}
|
||||
|
||||
offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
|
||||
if (stat_data.st_size != current_stat_info.stat.st_size + offset)
|
||||
off_t offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
|
||||
off_t file_size;
|
||||
if (offset < 0
|
||||
|| ckd_add (&file_size, current_stat_info.stat.st_size, offset)
|
||||
|| stat_data.st_size != file_size)
|
||||
{
|
||||
report_difference (¤t_stat_info, _("Size differs"));
|
||||
skip_member ();
|
||||
@@ -417,7 +426,7 @@ diff_multivol (void)
|
||||
}
|
||||
|
||||
|
||||
fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
|
||||
int fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
@@ -431,13 +440,11 @@ diff_multivol (void)
|
||||
{
|
||||
seek_error_details (current_stat_info.file_name, offset);
|
||||
report_difference (¤t_stat_info, NULL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
read_and_process (¤t_stat_info, process_rawdata);
|
||||
|
||||
read_and_process (¤t_stat_info, process_rawdata);
|
||||
|
||||
status = close (fd);
|
||||
if (status != 0)
|
||||
if (close (fd) < 0)
|
||||
close_error (current_stat_info.file_name);
|
||||
}
|
||||
|
||||
@@ -460,11 +467,10 @@ diff_archive (void)
|
||||
switch (current_header->header.typeflag)
|
||||
{
|
||||
default:
|
||||
ERROR ((0, 0, _("%s: Unknown file type `%c', diffed as normal file"),
|
||||
quotearg_colon (current_stat_info.file_name),
|
||||
current_header->header.typeflag));
|
||||
/* Fall through. */
|
||||
|
||||
paxerror (0, _("%s: Unknown file type '%c', diffed as normal file"),
|
||||
quotearg_colon (current_stat_info.file_name),
|
||||
current_header->header.typeflag);
|
||||
FALLTHROUGH;
|
||||
case AREGTYPE:
|
||||
case REGTYPE:
|
||||
case GNUTYPE_SPARSE:
|
||||
@@ -482,11 +488,9 @@ diff_archive (void)
|
||||
diff_link ();
|
||||
break;
|
||||
|
||||
#ifdef HAVE_READLINK
|
||||
case SYMTYPE:
|
||||
diff_symlink ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case CHRTYPE:
|
||||
case BLKTYPE:
|
||||
@@ -497,7 +501,7 @@ diff_archive (void)
|
||||
case GNUTYPE_DUMPDIR:
|
||||
case DIRTYPE:
|
||||
if (is_dumpdir (¤t_stat_info))
|
||||
diff_dumpdir ();
|
||||
diff_dumpdir (¤t_stat_info);
|
||||
diff_dir ();
|
||||
break;
|
||||
|
||||
@@ -512,13 +516,22 @@ diff_archive (void)
|
||||
void
|
||||
verify_volume (void)
|
||||
{
|
||||
bool may_fail = false;
|
||||
if (removed_prefixes_p ())
|
||||
{
|
||||
WARN((0, 0,
|
||||
_("Archive contains file names with leading prefixes removed.")));
|
||||
WARN((0, 0,
|
||||
_("Verification may fail to locate original files.")));
|
||||
paxwarn (0,
|
||||
_("Archive contains file names with leading prefixes removed."));
|
||||
may_fail = true;
|
||||
}
|
||||
if (transform_program_p ())
|
||||
{
|
||||
paxwarn (0, _("Archive contains transformed file names."));
|
||||
may_fail = true;
|
||||
}
|
||||
if (may_fail)
|
||||
paxwarn (0, _("Verification may fail to locate original files."));
|
||||
|
||||
clear_directory_table ();
|
||||
|
||||
if (!diff_buffer)
|
||||
diff_init ();
|
||||
@@ -540,31 +553,12 @@ verify_volume (void)
|
||||
ioctl (archive, FDFLUSH);
|
||||
#endif
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop operation;
|
||||
int status;
|
||||
|
||||
operation.mt_op = MTBSF;
|
||||
operation.mt_count = 1;
|
||||
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation), status < 0)
|
||||
{
|
||||
if (errno != EIO
|
||||
|| (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
|
||||
status < 0))
|
||||
{
|
||||
#endif
|
||||
if (rmtlseek (archive, (off_t) 0, SEEK_SET) != 0)
|
||||
{
|
||||
/* Lseek failed. Try a different method. */
|
||||
seek_warn (archive_name_array[0]);
|
||||
return;
|
||||
}
|
||||
#ifdef MTIOCTOP
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!mtioseek (true, -1) && rmtlseek (archive, 0, SEEK_SET) < 0)
|
||||
{
|
||||
/* Lseek failed. Try a different method. */
|
||||
seek_warn (archive_name_array[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
access_mode = ACCESS_READ;
|
||||
now_verifying = 1;
|
||||
@@ -578,7 +572,7 @@ verify_volume (void)
|
||||
|
||||
if (status == HEADER_FAILURE)
|
||||
{
|
||||
int counter = 0;
|
||||
intmax_t counter = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -589,10 +583,11 @@ verify_volume (void)
|
||||
}
|
||||
while (status == HEADER_FAILURE);
|
||||
|
||||
ERROR ((0, 0,
|
||||
ngettext ("VERIFY FAILURE: %d invalid header detected",
|
||||
"VERIFY FAILURE: %d invalid headers detected",
|
||||
counter), counter));
|
||||
paxerror (0,
|
||||
ngettext ("VERIFY FAILURE: %jd invalid header detected",
|
||||
"VERIFY FAILURE: %jd invalid headers detected",
|
||||
counter),
|
||||
counter);
|
||||
}
|
||||
if (status == HEADER_END_OF_FILE)
|
||||
break;
|
||||
@@ -601,18 +596,18 @@ verify_volume (void)
|
||||
set_next_block_after (current_header);
|
||||
if (!ignore_zeros_option)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
if (status == HEADER_ZERO_BLOCK)
|
||||
break;
|
||||
WARNOPT (WARN_ALONE_ZERO_BLOCK,
|
||||
(0, 0, _("A lone zero block at %s"),
|
||||
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
|
||||
warnopt (WARN_ALONE_ZERO_BLOCK,
|
||||
0, _("A lone zero block at %jd"),
|
||||
intmax (current_block_ordinal ()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
decode_header (current_header, ¤t_stat_info, ¤t_format, true);
|
||||
diff_archive ();
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(tar.h)
|
||||
PROGS="tar"
|
||||
AC_SUBST(PROGS)dnl
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_GCC_TRADITIONAL
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_YACC
|
||||
AC_AIX
|
||||
AC_MINIX
|
||||
AC_ISC_POSIX
|
||||
AC_CONST
|
||||
AC_RETSIGTYPE
|
||||
AC_SIZE_T
|
||||
AC_MAJOR_HEADER
|
||||
AC_DIR_HEADER
|
||||
# The 3-argument open happens to go along with the O_* defines,
|
||||
# which are easier to check for.
|
||||
AC_HEADER_CHECK(fcntl.h, open_header=fcntl.h, open_header=sys/file.h)
|
||||
AC_COMPILE_CHECK(3-argument open,
|
||||
[#include <$open_header>], [int x = O_RDONLY;], , AC_DEFINE(EMUL_OPEN3))
|
||||
AC_REMOTE_TAPE
|
||||
AC_RSH
|
||||
AC_STDC_HEADERS
|
||||
AC_UNISTD_H
|
||||
echo checking for getgrgid declaration
|
||||
AC_HEADER_EGREP(getgrgid, grp.h, AC_DEFINE(HAVE_GETGRGID))
|
||||
echo checking for getpwuid declaration
|
||||
AC_HEADER_EGREP(getpwuid, pwd.h, AC_DEFINE(HAVE_GETPWUID))
|
||||
AC_HAVE_HEADERS(string.h limits.h)
|
||||
echo checking default archive
|
||||
# This might guess wrong, but it's not very important.
|
||||
for dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2
|
||||
do
|
||||
if test -n "`ls /dev/$dev 2>/dev/null`"; then
|
||||
DEF_AR_FILE=/dev/$dev
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$DEF_AR_FILE"; then
|
||||
DEF_AR_FILE=-
|
||||
fi
|
||||
|
||||
AC_SUBST(DEF_AR_FILE)dnl
|
||||
AC_HAVE_FUNCS(strstr valloc mkdir mknod rename ftruncate ftime getcwd)
|
||||
AC_VPRINTF
|
||||
AC_ALLOCA
|
||||
echo checking for BSD
|
||||
( test -f /vmunix || test -f /sdmach || test -f /../../mach ) && AC_DEFINE(BSD42)
|
||||
echo checking for HP-UX
|
||||
test "`(uname -s) 2> /dev/null`" = 'HP-UX' && MALLOC=malloc.o
|
||||
AC_SUBST(MALLOC)
|
||||
AC_XENIX_DIR
|
||||
AC_HAVE_LIBRARY(socket, [LIBS="$LIBS -lsocket"])
|
||||
AC_HAVE_LIBRARY(nsl, [LIBS="$LIBS -lnsl"])
|
||||
AC_OUTPUT(Makefile)
|
||||
874
src/create.c
874
src/create.c
File diff suppressed because it is too large
Load Diff
361
src/delete.c
361
src/delete.c
@@ -1,41 +1,31 @@
|
||||
/* Delete entries from a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001, 2003, 2004,
|
||||
2005, 2006, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988-2025 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 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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 3 of the License, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <system-ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
#include <rmt.h>
|
||||
|
||||
static union block *new_record;
|
||||
static int new_blocks;
|
||||
static idx_t new_blocks;
|
||||
static bool acting_as_filter;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* The number of records skipped at the start of the archive, when
|
||||
passing over members that are not deleted. */
|
||||
off_t records_skipped;
|
||||
@@ -50,47 +40,37 @@ move_archive (off_t count)
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
#ifdef MTIOCTOP
|
||||
{
|
||||
struct mtop operation;
|
||||
|
||||
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))
|
||||
{
|
||||
if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
|
||||
return;
|
||||
|
||||
if (errno == EIO
|
||||
&& 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* MTIOCTOP */
|
||||
|
||||
{
|
||||
off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
|
||||
off_t increment = record_size * (off_t) count;
|
||||
off_t position = position0 + increment;
|
||||
|
||||
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);
|
||||
|
||||
if (mtioseek (false, count))
|
||||
return;
|
||||
}
|
||||
|
||||
off_t position0 = rmtlseek (archive, 0, SEEK_CUR), position = 0;
|
||||
if (0 <= position0)
|
||||
{
|
||||
/* Pretend the starting position is at the first record
|
||||
boundary after POSITION0. This is useful at EOF after
|
||||
a short read. */
|
||||
idx_t short_size = position0 % record_size;
|
||||
idx_t start_offset = short_size ? record_size - short_size : 0;
|
||||
off_t increment, move_start;
|
||||
if (ckd_mul (&increment, record_size, count)
|
||||
|| ckd_add (&move_start, position0, start_offset)
|
||||
|| ckd_add (&position, move_start, increment)
|
||||
|| position < 0)
|
||||
{
|
||||
paxerror (EOVERFLOW, "lseek: %s", archive_name_array[0]);
|
||||
return;
|
||||
}
|
||||
else if (rmtlseek (archive, position, SEEK_SET) == position)
|
||||
return;
|
||||
}
|
||||
if (!_isrmt (archive))
|
||||
seek_error_details (archive_name_array[0], position);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
write_record (bool move_back_flag)
|
||||
{
|
||||
union block *save_record = record_start;
|
||||
record_start = new_record;
|
||||
@@ -121,22 +101,21 @@ write_record (int move_back_flag)
|
||||
}
|
||||
|
||||
static void
|
||||
write_recent_blocks (union block *h, size_t blocks)
|
||||
write_recent_blocks (union block *h, idx_t blocks)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < blocks; i++)
|
||||
for (idx_t i = 0; i < blocks; i++)
|
||||
{
|
||||
new_record[new_blocks++] = h[i];
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
write_record (true);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_recent_bytes (char *data, size_t bytes)
|
||||
write_recent_bytes (char *data, idx_t bytes)
|
||||
{
|
||||
size_t blocks = bytes / BLOCKSIZE;
|
||||
size_t rest = bytes - blocks * BLOCKSIZE;
|
||||
idx_t blocks = bytes >> LG_BLOCKSIZE;
|
||||
idx_t rest = bytes & (BLOCKSIZE - 1);
|
||||
|
||||
write_recent_blocks ((union block *)data, blocks);
|
||||
memcpy (new_record[new_blocks].buffer, data + blocks * BLOCKSIZE, rest);
|
||||
@@ -144,7 +123,25 @@ write_recent_bytes (char *data, size_t bytes)
|
||||
memset (new_record[new_blocks].buffer + rest, 0, BLOCKSIZE - rest);
|
||||
new_blocks++;
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
write_record (true);
|
||||
}
|
||||
|
||||
static void
|
||||
flush_file (void)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
off_t size = current_stat_info.stat.st_size;
|
||||
off_t blocks_to_skip = (size >> LG_BLOCKSIZE) + !!(size & (BLOCKSIZE - 1));
|
||||
|
||||
while (record_end - current_block <= blocks_to_skip)
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
flush_archive ();
|
||||
if (record_end == current_block)
|
||||
/* Hit EOF */
|
||||
return;
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -155,19 +152,19 @@ delete_archive_members (void)
|
||||
|
||||
/* FIXME: Should clean the routine before cleaning these variables :-( */
|
||||
struct name *name;
|
||||
off_t blocks_to_skip = 0;
|
||||
off_t blocks_to_keep = 0;
|
||||
int kept_blocks_in_record;
|
||||
ptrdiff_t kept_blocks_in_record;
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||
|
||||
/* Skip to the first member that matches the name list. */
|
||||
do
|
||||
{
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
read_header_x_raw);
|
||||
¤t_stat_info,
|
||||
read_header_x_raw);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
@@ -175,19 +172,18 @@ delete_archive_members (void)
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
if ((name = name_scan (current_stat_info.file_name)) == NULL)
|
||||
if ((name = name_scan (current_stat_info.file_name, false)) == NULL)
|
||||
{
|
||||
skip_member ();
|
||||
skim_member (acting_as_filter);
|
||||
break;
|
||||
}
|
||||
name->found_count++;
|
||||
if (!ISFOUND(name))
|
||||
if (!isfound (name))
|
||||
{
|
||||
skip_member ();
|
||||
skim_member (acting_as_filter);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
logical_status = status;
|
||||
break;
|
||||
@@ -198,7 +194,7 @@ delete_archive_members (void)
|
||||
set_next_block_after (current_header);
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
FALLTHROUGH;
|
||||
case HEADER_END_OF_FILE:
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
@@ -208,15 +204,13 @@ delete_archive_members (void)
|
||||
switch (previous_status)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
paxwarn (0, _("This does not look like a tar archive"));
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
|
||||
paxerror (0, _("Skipping to next header"));
|
||||
FALLTHROUGH;
|
||||
case HEADER_FAILURE:
|
||||
break;
|
||||
|
||||
@@ -246,15 +240,12 @@ delete_archive_members (void)
|
||||
|
||||
if (logical_status == HEADER_SUCCESS)
|
||||
{
|
||||
/* FIXME: Pheew! This is crufty code! */
|
||||
logical_status = HEADER_STILL_UNREAD;
|
||||
goto flush_file;
|
||||
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)
|
||||
/* Skip matching members and move the rest up the archive. */
|
||||
while (logical_status != HEADER_END_OF_FILE)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
@@ -262,105 +253,109 @@ delete_archive_members (void)
|
||||
|
||||
if (current_block == record_end)
|
||||
flush_archive ();
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
read_header_auto);
|
||||
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
|
||||
switch (status)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
|
||||
case HEADER_SUCCESS:
|
||||
/* Found another header. */
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
if ((name = name_scan (current_stat_info.file_name, false)) != NULL)
|
||||
{
|
||||
name->found_count++;
|
||||
if (isfound (name))
|
||||
{
|
||||
flush_file ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Copy header. */
|
||||
|
||||
if (current_stat_info.xhdr.size)
|
||||
{
|
||||
write_recent_bytes (current_stat_info.xhdr.buffer,
|
||||
current_stat_info.xhdr.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 >> LG_BLOCKSIZE)
|
||||
+ !!(current_stat_info.stat.st_size & (BLOCKSIZE - 1)));
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
|
||||
{
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (true);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
ptrdiff_t 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 (true);
|
||||
}
|
||||
break;
|
||||
|
||||
case HEADER_ZERO_BLOCK:
|
||||
if (ignore_zeros_option)
|
||||
set_next_block_after (current_header);
|
||||
else
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
|
||||
case HEADER_END_OF_FILE:
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == HEADER_FAILURE)
|
||||
{
|
||||
ERROR ((0, 0, _("Deleting non-header from archive")));
|
||||
case HEADER_FAILURE:
|
||||
paxerror (0, _("Deleting non-header from archive"));
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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 (current_stat_info.xhdr.size)
|
||||
{
|
||||
write_recent_bytes (current_stat_info.xhdr.buffer,
|
||||
current_stat_info.xhdr.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);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
tar_stat_destroy (¤t_stat_info);
|
||||
}
|
||||
|
||||
if (logical_status == HEADER_END_OF_FILE)
|
||||
@@ -368,11 +363,11 @@ delete_archive_members (void)
|
||||
/* 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;
|
||||
idx_t total_zero_blocks = 0;
|
||||
|
||||
do
|
||||
{
|
||||
int zero_blocks = blocking_factor - new_blocks;
|
||||
idx_t 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);
|
||||
@@ -382,7 +377,7 @@ delete_archive_members (void)
|
||||
|
||||
if (! acting_as_filter && ! _isrmt (archive))
|
||||
{
|
||||
if (sys_truncate (archive))
|
||||
if (sys_truncate (archive) < 0)
|
||||
truncate_warn (archive_name_array[0]);
|
||||
}
|
||||
}
|
||||
|
||||
327
src/exclist.c
Normal file
327
src/exclist.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/* Per-directory exclusion files for tar.
|
||||
|
||||
Copyright 2014-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <system.h>
|
||||
#include <c-ctype.h>
|
||||
#include <quotearg.h>
|
||||
#include <flexmember.h>
|
||||
#include <fnmatch.h>
|
||||
#include <wordsplit.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef void (*add_fn) (struct exclude *, char const *, int, void *);
|
||||
|
||||
struct vcs_ignore_file
|
||||
{
|
||||
char const *filename;
|
||||
int flags;
|
||||
add_fn addfn;
|
||||
void *(*initfn) (void *);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static struct vcs_ignore_file *get_vcs_ignore_file (const char *name);
|
||||
|
||||
struct excfile
|
||||
{
|
||||
struct excfile *next;
|
||||
int flags;
|
||||
char name[FLEXIBLE_ARRAY_MEMBER];
|
||||
};
|
||||
|
||||
static struct excfile *excfile_head, *excfile_tail;
|
||||
|
||||
void
|
||||
excfile_add (const char *name, int flags)
|
||||
{
|
||||
struct excfile *p = xmalloc (FLEXNSIZEOF (struct excfile, name,
|
||||
strlen (name) + 1));
|
||||
p->next = NULL;
|
||||
p->flags = flags;
|
||||
strcpy (p->name, name);
|
||||
if (excfile_tail)
|
||||
excfile_tail->next = p;
|
||||
else
|
||||
excfile_head = p;
|
||||
excfile_tail = p;
|
||||
}
|
||||
|
||||
struct exclist
|
||||
{
|
||||
struct exclist *next, *prev;
|
||||
int flags;
|
||||
struct exclude *excluded;
|
||||
};
|
||||
|
||||
void
|
||||
info_attach_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
struct exclist *head = NULL, *tail = NULL;
|
||||
if (dir->exclude_list)
|
||||
return;
|
||||
|
||||
for (struct excfile *file = excfile_head; file; file = file->next)
|
||||
{
|
||||
if (faccessat (dir->fd, file->name, F_OK, 0) == 0)
|
||||
{
|
||||
int fd = subfile_open (dir, file->name, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
open_error (file->name);
|
||||
continue;
|
||||
}
|
||||
FILE *fp = fdopen (fd, "r");
|
||||
if (!fp)
|
||||
{
|
||||
paxerror (errno, _("%s: fdopen failed"), file->name);
|
||||
close (fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct exclude *ex = new_exclude ();
|
||||
|
||||
struct vcs_ignore_file *vcsfile = get_vcs_ignore_file (file->name);
|
||||
|
||||
if (vcsfile->initfn)
|
||||
vcsfile->data = vcsfile->initfn (vcsfile->data);
|
||||
|
||||
if (add_exclude_fp (vcsfile->addfn, ex, fp,
|
||||
FNM_FILE_NAME|EXCLUDE_WILDCARDS|EXCLUDE_ANCHORED,
|
||||
'\n',
|
||||
vcsfile->data))
|
||||
paxfatal (errno, "%s", quotearg_colon (file->name));
|
||||
fclose (fp);
|
||||
|
||||
struct exclist *ent = xmalloc (sizeof *ent);
|
||||
ent->excluded = ex;
|
||||
ent->flags = file->flags;
|
||||
ent->prev = tail;
|
||||
ent->next = NULL;
|
||||
|
||||
if (tail)
|
||||
tail->next = ent;
|
||||
else
|
||||
head = ent;
|
||||
tail = ent;
|
||||
}
|
||||
}
|
||||
dir->exclude_list = head;
|
||||
}
|
||||
|
||||
void
|
||||
info_free_exclist (struct tar_stat_info *dir)
|
||||
{
|
||||
struct exclist *ep = dir->exclude_list;
|
||||
|
||||
while (ep)
|
||||
{
|
||||
struct exclist *next = ep->next;
|
||||
free_exclude (ep->excluded);
|
||||
free (ep);
|
||||
ep = next;
|
||||
}
|
||||
|
||||
dir->exclude_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return nonzero if file NAME is excluded. */
|
||||
bool
|
||||
excluded_name (char const *name, struct tar_stat_info *st)
|
||||
{
|
||||
struct exclist *ep;
|
||||
const char *rname = NULL;
|
||||
char *bname = NULL;
|
||||
bool result;
|
||||
int nr = 0;
|
||||
|
||||
name += FILE_SYSTEM_PREFIX_LEN (name);
|
||||
|
||||
/* Try global exclusion list first */
|
||||
if (excluded_file_name (excluded, name))
|
||||
return true;
|
||||
|
||||
if (!st)
|
||||
return false;
|
||||
|
||||
for (result = false; st && !result; st = st->parent, nr = EXCL_NON_RECURSIVE)
|
||||
{
|
||||
for (ep = st->exclude_list; ep; ep = ep->next)
|
||||
{
|
||||
if (ep->flags & nr)
|
||||
continue;
|
||||
if ((result = excluded_file_name (ep->excluded, name)))
|
||||
break;
|
||||
|
||||
if (!rname)
|
||||
{
|
||||
rname = name;
|
||||
/* Skip leading ./ */
|
||||
while (*rname == '.' && ISSLASH (rname[1]))
|
||||
rname += 2;
|
||||
}
|
||||
if ((result = excluded_file_name (ep->excluded, rname)))
|
||||
break;
|
||||
|
||||
if (!bname)
|
||||
bname = base_name (name);
|
||||
if ((result = excluded_file_name (ep->excluded, bname)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (bname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
cvs_addfn (struct exclude *ex, char const *pattern, int options,
|
||||
MAYBE_UNUSED void *data)
|
||||
{
|
||||
struct wordsplit ws;
|
||||
|
||||
options |= EXCLUDE_ALLOC;
|
||||
if (wordsplit (pattern, &ws,
|
||||
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS)
|
||||
!= WRDSE_OK)
|
||||
return;
|
||||
for (idx_t i = 0; i < ws.ws_wordc; i++)
|
||||
add_exclude (ex, ws.ws_wordv[i], options);
|
||||
wordsplit_free (&ws);
|
||||
}
|
||||
|
||||
static void
|
||||
git_addfn (struct exclude *ex, char const *pattern, int options,
|
||||
MAYBE_UNUSED void *data)
|
||||
{
|
||||
while (c_isspace (*pattern))
|
||||
++pattern;
|
||||
if (*pattern == 0 || *pattern == '#')
|
||||
return;
|
||||
if (*pattern == '\\' && pattern[1] == '#')
|
||||
++pattern;
|
||||
add_exclude (ex, pattern, options);
|
||||
}
|
||||
|
||||
static void
|
||||
bzr_addfn (struct exclude *ex, char const *pattern, int options,
|
||||
MAYBE_UNUSED void *data)
|
||||
{
|
||||
while (c_isspace (*pattern))
|
||||
++pattern;
|
||||
if (*pattern == 0 || *pattern == '#')
|
||||
return;
|
||||
if (*pattern == '!')
|
||||
{
|
||||
if (*++pattern == '!')
|
||||
++pattern;
|
||||
else
|
||||
options |= EXCLUDE_INCLUDE;
|
||||
}
|
||||
/* FIXME: According to the docs, globbing patterns are rsync-style,
|
||||
and regexps are perl-style. */
|
||||
if (strncmp (pattern, "RE:", 3) == 0)
|
||||
{
|
||||
pattern += 3;
|
||||
options &= ~EXCLUDE_WILDCARDS;
|
||||
options |= EXCLUDE_REGEX;
|
||||
}
|
||||
add_exclude (ex, pattern, options);
|
||||
}
|
||||
|
||||
static void *
|
||||
hg_initfn (void *data)
|
||||
{
|
||||
static int hg_options;
|
||||
int *hgopt = data ? data : &hg_options;
|
||||
*hgopt = EXCLUDE_REGEX;
|
||||
return hgopt;
|
||||
}
|
||||
|
||||
static void
|
||||
hg_addfn (struct exclude *ex, char const *pattern, int options, void *data)
|
||||
{
|
||||
int *hgopt = data;
|
||||
|
||||
while (c_isspace (*pattern))
|
||||
++pattern;
|
||||
if (*pattern == 0 || *pattern == '#')
|
||||
return;
|
||||
if (strncmp (pattern, "syntax:", 7) == 0)
|
||||
{
|
||||
for (pattern += 7; c_isspace (*pattern); ++pattern)
|
||||
;
|
||||
if (strcmp (pattern, "regexp") == 0)
|
||||
/* FIXME: Regexps must be perl-style */
|
||||
*hgopt = EXCLUDE_REGEX;
|
||||
else if (strcmp (pattern, "glob") == 0)
|
||||
*hgopt = EXCLUDE_WILDCARDS;
|
||||
/* Ignore unknown syntax */
|
||||
return;
|
||||
}
|
||||
|
||||
idx_t len = strlen (pattern);
|
||||
if (pattern[len-1] == '/')
|
||||
{
|
||||
char *p;
|
||||
|
||||
--len;
|
||||
p = xmalloc (len+1);
|
||||
memcpy (p, pattern, len);
|
||||
p[len] = 0;
|
||||
pattern = p;
|
||||
exclude_add_pattern_buffer (ex, p);
|
||||
options |= FNM_LEADING_DIR|EXCLUDE_ALLOC;
|
||||
}
|
||||
|
||||
add_exclude (ex, pattern,
|
||||
((*hgopt == EXCLUDE_REGEX)
|
||||
? (options & ~EXCLUDE_WILDCARDS)
|
||||
: (options & ~EXCLUDE_REGEX)) | *hgopt);
|
||||
}
|
||||
|
||||
static struct vcs_ignore_file vcs_ignore_files[] = {
|
||||
{ ".cvsignore", EXCL_NON_RECURSIVE, cvs_addfn, NULL, NULL },
|
||||
{ ".gitignore", 0, git_addfn, NULL, NULL },
|
||||
{ ".bzrignore", 0, bzr_addfn, NULL, NULL },
|
||||
{ ".hgignore", 0, hg_addfn, hg_initfn, NULL },
|
||||
{ NULL, 0, git_addfn, NULL, NULL }
|
||||
};
|
||||
|
||||
static struct vcs_ignore_file *
|
||||
get_vcs_ignore_file (const char *name)
|
||||
{
|
||||
struct vcs_ignore_file *p;
|
||||
|
||||
for (p = vcs_ignore_files; p->filename; p++)
|
||||
if (strcmp (p->filename, name) == 0)
|
||||
break;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
exclude_vcs_ignores (void)
|
||||
{
|
||||
struct vcs_ignore_file *p;
|
||||
|
||||
for (p = vcs_ignore_files; p->filename; p++)
|
||||
excfile_add (p->filename, p->flags);
|
||||
}
|
||||
28
src/exit.c
28
src/exit.c
@@ -1,19 +1,21 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
/* Exit from GNU tar.
|
||||
|
||||
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 3, or (at your option) any later
|
||||
version.
|
||||
Copyright 2009-2025 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 file is part of GNU tar.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
|
||||
1329
src/extract.c
1329
src/extract.c
File diff suppressed because it is too large
Load Diff
1119
src/incremen.c
1119
src/incremen.c
File diff suppressed because it is too large
Load Diff
933
src/list.c
933
src/list.c
File diff suppressed because it is too large
Load Diff
263
src/map.c
Normal file
263
src/map.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/* Owner/group mapping for tar
|
||||
|
||||
Copyright 2015-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
#include "wordsplit.h"
|
||||
#include <hash.h>
|
||||
#include <pwd.h>
|
||||
|
||||
struct mapentry
|
||||
{
|
||||
uintmax_t orig_id;
|
||||
uintmax_t new_id;
|
||||
char *new_name;
|
||||
};
|
||||
|
||||
static size_t
|
||||
map_hash (void const *entry, size_t nbuckets)
|
||||
{
|
||||
struct mapentry const *map = entry;
|
||||
return map->orig_id % nbuckets;
|
||||
}
|
||||
|
||||
static bool
|
||||
map_compare (void const *entry1, void const *entry2)
|
||||
{
|
||||
struct mapentry const *map1 = entry1;
|
||||
struct mapentry const *map2 = entry2;
|
||||
return map1->orig_id == map2->orig_id;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_id (uintmax_t *retval,
|
||||
char const *arg, char const *what, uintmax_t maxval,
|
||||
char const *file, intmax_t line)
|
||||
{
|
||||
char *p;
|
||||
bool overflow;
|
||||
*retval = stoint (arg, &p, &overflow, 0, maxval);
|
||||
|
||||
if ((p == arg) | *p)
|
||||
{
|
||||
error (0, 0, _("%s:%jd: invalid %s: %s"), file, line, what, arg);
|
||||
return false;
|
||||
}
|
||||
if (overflow)
|
||||
{
|
||||
error (0, 0, _("%s:%jd: %s out of range: %s"), file, line, what, arg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
map_read (Hash_table **ptab, char const *file,
|
||||
uintmax_t (*name_to_id) (char const *), char const *what,
|
||||
uintmax_t maxval)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = NULL;
|
||||
size_t bufsize = 0;
|
||||
ssize_t n;
|
||||
struct wordsplit ws;
|
||||
int wsopt;
|
||||
intmax_t line;
|
||||
bool err = false;
|
||||
|
||||
fp = fopen (file, "r");
|
||||
if (!fp)
|
||||
open_fatal (file);
|
||||
|
||||
ws.ws_comment = "#";
|
||||
wsopt = WRDSF_COMMENT | WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS
|
||||
| WRDSF_QUOTE;
|
||||
line = 0;
|
||||
while ((n = getline (&buf, &bufsize, fp)) > 0)
|
||||
{
|
||||
struct mapentry *ent;
|
||||
uintmax_t orig_id, new_id;
|
||||
char *name = NULL;
|
||||
char *colon;
|
||||
|
||||
++line;
|
||||
if (wordsplit (buf, &ws, wsopt) != WRDSE_OK)
|
||||
paxfatal (0, _("%s:%jd: cannot split line: %s"),
|
||||
file, line, wordsplit_strerror (&ws));
|
||||
wsopt |= WRDSF_REUSE;
|
||||
if (ws.ws_wordc == 0)
|
||||
continue;
|
||||
if (ws.ws_wordc != 2)
|
||||
{
|
||||
error (0, 0, _("%s:%jd: malformed line"), file, line);
|
||||
err = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ws.ws_wordv[0][0] == '+')
|
||||
{
|
||||
if (!parse_id (&orig_id, ws.ws_wordv[0]+1, what, maxval, file, line))
|
||||
{
|
||||
err = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (name_to_id)
|
||||
{
|
||||
orig_id = name_to_id (ws.ws_wordv[0]);
|
||||
if (orig_id == UINTMAX_MAX)
|
||||
{
|
||||
error (0, 0, _("%s:%jd: can't obtain %s of %s"),
|
||||
file, line, what, ws.ws_wordv[0]);
|
||||
err = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
colon = strchr (ws.ws_wordv[1], ':');
|
||||
if (colon)
|
||||
{
|
||||
if (colon > ws.ws_wordv[1])
|
||||
name = ws.ws_wordv[1];
|
||||
*colon++ = 0;
|
||||
if (!parse_id (&new_id, colon, what, maxval, file, line))
|
||||
{
|
||||
err = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (ws.ws_wordv[1][0] == '+')
|
||||
{
|
||||
if (!parse_id (&new_id, ws.ws_wordv[1], what, maxval, file, line))
|
||||
{
|
||||
err = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = ws.ws_wordv[1];
|
||||
new_id = name_to_id (ws.ws_wordv[1]);
|
||||
if (new_id == UINTMAX_MAX)
|
||||
{
|
||||
error (0, 0, _("%s:%jd: can't obtain %s of %s"),
|
||||
file, line, what, ws.ws_wordv[1]);
|
||||
err = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ent = xmalloc (sizeof (*ent));
|
||||
ent->orig_id = orig_id;
|
||||
ent->new_id = new_id;
|
||||
ent->new_name = name ? xstrdup (name) : NULL;
|
||||
|
||||
if (!((*ptab
|
||||
|| (*ptab = hash_initialize (0, 0, map_hash, map_compare, 0)))
|
||||
&& hash_insert (*ptab, ent)))
|
||||
xalloc_die ();
|
||||
}
|
||||
if (wsopt & WRDSF_REUSE)
|
||||
wordsplit_free (&ws);
|
||||
fclose (fp);
|
||||
if (err)
|
||||
paxfatal (0, _("errors reading map file"));
|
||||
}
|
||||
|
||||
/* UID translation */
|
||||
|
||||
static Hash_table *owner_map;
|
||||
|
||||
static uintmax_t
|
||||
name_to_uid (char const *name)
|
||||
{
|
||||
struct passwd *pw = getpwnam (name);
|
||||
return pw ? pw->pw_uid : UINTMAX_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
owner_map_read (char const *file)
|
||||
{
|
||||
map_read (&owner_map, file, name_to_uid, "UID", TYPE_MAXIMUM (uid_t));
|
||||
}
|
||||
|
||||
void
|
||||
owner_map_translate (uid_t uid, uid_t *new_uid, char const **new_name)
|
||||
{
|
||||
if (owner_map)
|
||||
{
|
||||
struct mapentry ent, *res;
|
||||
|
||||
ent.orig_id = uid;
|
||||
res = hash_lookup (owner_map, &ent);
|
||||
if (res)
|
||||
{
|
||||
*new_uid = res->new_id;
|
||||
*new_name = res->new_name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uid_t minus_1 = -1;
|
||||
if (owner_option != minus_1)
|
||||
*new_uid = owner_option;
|
||||
if (owner_name_option)
|
||||
*new_name = owner_name_option;
|
||||
}
|
||||
|
||||
/* GID translation */
|
||||
|
||||
static Hash_table *group_map;
|
||||
|
||||
static uintmax_t
|
||||
name_to_gid (char const *name)
|
||||
{
|
||||
struct group *gr = getgrnam (name);
|
||||
return gr ? gr->gr_gid : UINTMAX_MAX;
|
||||
}
|
||||
|
||||
void
|
||||
group_map_read (char const *file)
|
||||
{
|
||||
map_read (&group_map, file, name_to_gid, "GID", TYPE_MAXIMUM (gid_t));
|
||||
}
|
||||
|
||||
void
|
||||
group_map_translate (gid_t gid, gid_t *new_gid, char const **new_name)
|
||||
{
|
||||
if (group_map)
|
||||
{
|
||||
struct mapentry ent, *res;
|
||||
|
||||
ent.orig_id = gid;
|
||||
res = hash_lookup (group_map, &ent);
|
||||
if (res)
|
||||
{
|
||||
*new_gid = res->new_id;
|
||||
*new_name = res->new_name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gid_t minus_1 = -1;
|
||||
if (group_option != minus_1)
|
||||
*new_gid = group_option;
|
||||
if (group_name_option)
|
||||
*new_name = group_name_option;
|
||||
}
|
||||
696
src/misc.c
696
src/misc.c
File diff suppressed because it is too large
Load Diff
1421
src/names.c
1421
src/names.c
File diff suppressed because it is too large
Load Diff
703
src/sparse.c
703
src/sparse.c
File diff suppressed because it is too large
Load Diff
105
src/suffix.c
105
src/suffix.c
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2007, 2009 Free Software Foundation, Inc.
|
||||
Copyright 2007-2025 Free Software Foundation, Inc.
|
||||
|
||||
Written by Sergey Poznyakoff.
|
||||
|
||||
@@ -21,15 +21,19 @@
|
||||
|
||||
struct compression_suffix
|
||||
{
|
||||
const char *suffix;
|
||||
size_t length;
|
||||
const char *program;
|
||||
char suffix[sizeof "tbz2"]; /* "tbz2" is tied for longest. */
|
||||
char program[max (max (max (sizeof GZIP_PROGRAM, sizeof COMPRESS_PROGRAM),
|
||||
max (sizeof BZIP2_PROGRAM, sizeof LZIP_PROGRAM)),
|
||||
max (max (sizeof LZMA_PROGRAM, sizeof LZOP_PROGRAM),
|
||||
max (sizeof XZ_PROGRAM, sizeof ZSTD_PROGRAM)))];
|
||||
};
|
||||
|
||||
static struct compression_suffix compression_suffixes[] = {
|
||||
static struct compression_suffix const compression_suffixes[] = {
|
||||
#define __CAT2__(a,b) a ## b
|
||||
#define S(s,p) #s, sizeof (#s) - 1, __CAT2__(p,_PROGRAM)
|
||||
#define S(s, p) #s, __CAT2__(p,_PROGRAM)
|
||||
{ "tar", "" },
|
||||
{ S(gz, GZIP) },
|
||||
{ S(z, GZIP) },
|
||||
{ S(tgz, GZIP) },
|
||||
{ S(taz, GZIP) },
|
||||
{ S(Z, COMPRESS) },
|
||||
@@ -42,41 +46,86 @@ static struct compression_suffix compression_suffixes[] = {
|
||||
{ S(lzma, LZMA) },
|
||||
{ S(tlz, LZMA) },
|
||||
{ S(lzo, LZOP) },
|
||||
{ S(tzo, LZOP) },
|
||||
{ S(xz, XZ) },
|
||||
{ S(txz, XZ) }, /* Slackware */
|
||||
{ S(zst, ZSTD) },
|
||||
{ S(tzst, ZSTD) },
|
||||
#undef S
|
||||
#undef __CAT2__
|
||||
};
|
||||
|
||||
static int nsuffixes = sizeof (compression_suffixes) /
|
||||
sizeof (compression_suffixes[0]);
|
||||
|
||||
static const char *
|
||||
find_compression_program (const char *name, const char *defprog)
|
||||
/* Extract the suffix from archive file NAME, and return a pointer to
|
||||
compression_suffix associated with it or NULL if none is found.
|
||||
No matter what is the return value, if RET_LEN is not NULL, store
|
||||
there the length of NAME with that suffix stripped, or 0 if NAME has
|
||||
no suffix. */
|
||||
static struct compression_suffix const *
|
||||
find_compression_suffix (char const *name, idx_t *ret_len)
|
||||
{
|
||||
char *suf = strrchr (name, '.');
|
||||
char const *suf = strrchr (name, '.');
|
||||
|
||||
if (suf)
|
||||
if (suf && suf[1] != 0 && suf[1] != '/')
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
if (ret_len)
|
||||
*ret_len = suf - name;
|
||||
suf++;
|
||||
len = strlen (suf);
|
||||
|
||||
for (i = 0; i < nsuffixes; i++)
|
||||
{
|
||||
if (compression_suffixes[i].length == len
|
||||
&& memcmp (compression_suffixes[i].suffix, suf, len) == 0)
|
||||
return compression_suffixes[i].program;
|
||||
}
|
||||
for (struct compression_suffix const *p = compression_suffixes;
|
||||
p < (compression_suffixes
|
||||
+ sizeof compression_suffixes / sizeof *compression_suffixes);
|
||||
p++)
|
||||
if (strcmp (p->suffix, suf) == 0)
|
||||
return p;
|
||||
}
|
||||
return defprog;
|
||||
else if (ret_len)
|
||||
*ret_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Select compression program using the suffix of the archive file NAME.
|
||||
Use DEFPROG, if there is no suffix, or if no program is associated with
|
||||
the suffix. In the latter case, if VERBOSE is true, issue a warning.
|
||||
*/
|
||||
void
|
||||
set_compression_program_by_suffix (const char *name, const char *defprog)
|
||||
set_compression_program_by_suffix (const char *name, const char *defprog,
|
||||
bool verbose)
|
||||
{
|
||||
const char *program = find_compression_program (name, defprog);
|
||||
if (program)
|
||||
use_compress_program_option = program;
|
||||
idx_t len;
|
||||
struct compression_suffix const *p = find_compression_suffix (name, &len);
|
||||
if (p)
|
||||
use_compress_program_option = p->program[0] ? p->program : NULL;
|
||||
else
|
||||
{
|
||||
use_compress_program_option = defprog;
|
||||
if (len > 0 && verbose)
|
||||
paxwarn (0,
|
||||
_("no compression program is defined for suffix '%s';"
|
||||
" assuming %s"),
|
||||
name + len,
|
||||
defprog ? defprog : "uncompressed archive");
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
strip_compression_suffix (const char *name)
|
||||
{
|
||||
char *s = NULL;
|
||||
idx_t len;
|
||||
struct compression_suffix const *p = find_compression_suffix (name, &len);
|
||||
|
||||
if (p)
|
||||
{
|
||||
/* Strip an additional ".tar" suffix, but only if the just-stripped
|
||||
"outer" suffix did not begin with "t". */
|
||||
if (len > 4 && strncmp (name + len - 4, ".tar", 4) == 0
|
||||
&& p->suffix[0] != 't')
|
||||
len -= 4;
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
s = xmalloc (len + 1);
|
||||
memcpy (s, name, len);
|
||||
s[len] = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
616
src/system.c
616
src/system.c
@@ -1,7 +1,6 @@
|
||||
/* System-dependent calls for tar.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007,
|
||||
2008, 2010 Free Software Foundation, Inc.
|
||||
Copyright 2003-2025 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
|
||||
@@ -14,17 +13,70 @@
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
|
||||
#if HAVE_SYS_MTIO_H
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include <priv-set.h>
|
||||
#include <rmt.h>
|
||||
#include <same-inode.h>
|
||||
#include <signal.h>
|
||||
#include <wordsplit.h>
|
||||
#include <poll.h>
|
||||
#include <parse-datetime.h>
|
||||
|
||||
#if MSDOS
|
||||
bool dev_null_output;
|
||||
|
||||
static _Noreturn void
|
||||
xexec (const char *cmd)
|
||||
{
|
||||
char *argv[4];
|
||||
|
||||
argv[0] = (char *) "/bin/sh";
|
||||
argv[1] = (char *) "-c";
|
||||
argv[2] = (char *) cmd;
|
||||
argv[3] = NULL;
|
||||
|
||||
execv ("/bin/sh", argv);
|
||||
exec_fatal (cmd);
|
||||
}
|
||||
|
||||
/* True if the archive is seekable via ioctl and MTIOCTOP,
|
||||
or if it is not known whether it is seekable.
|
||||
False if it is known to be not seekable. */
|
||||
static bool mtioseekable_archive;
|
||||
|
||||
bool
|
||||
mtioseek (bool count_files, off_t count)
|
||||
{
|
||||
if (mtioseekable_archive)
|
||||
{
|
||||
#ifdef MTIOCTOP
|
||||
struct mtop operation;
|
||||
operation.mt_op = (count_files
|
||||
? (count < 0 ? MTBSF : MTFSF)
|
||||
: (count < 0 ? MTBSR : MTFSR));
|
||||
if (! (count < 0
|
||||
? ckd_sub (&operation.mt_count, 0, count)
|
||||
: ckd_add (&operation.mt_count, count, 0))
|
||||
&& (0 <= rmtioctl (archive, MTIOCTOP, &operation)
|
||||
|| (errno == EIO
|
||||
&& 0 <= rmtioctl (archive, MTIOCTOP, &operation))))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
mtioseekable_archive = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !HAVE_WAITPID /* MingW, MSVC 14. */
|
||||
|
||||
bool
|
||||
sys_get_archive_stat (void)
|
||||
@@ -38,11 +90,6 @@ 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)
|
||||
{
|
||||
@@ -79,82 +126,86 @@ 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);
|
||||
}
|
||||
|
||||
size_t
|
||||
idx_t
|
||||
sys_write_archive_buffer (void)
|
||||
{
|
||||
return full_write (archive, record_start->buffer, record_size);
|
||||
return full_write (archive, charptr (record_start), 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")));
|
||||
paxfatal (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")));
|
||||
paxfatal (0, _("Cannot use compressed or remote archives"));
|
||||
}
|
||||
|
||||
bool
|
||||
sys_exec_setmtime_script (const char *script_name,
|
||||
int dirfd,
|
||||
const char *file_name,
|
||||
const char *fmt,
|
||||
struct timespec *ts)
|
||||
{
|
||||
paxfatal (0, _("--set-mtime-command not implemented on this platform"));
|
||||
}
|
||||
#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 remote = _isrmt (archive);
|
||||
mtioseekable_archive = true;
|
||||
if (!remote && 0 <= archive && fstat (archive, &archive_stat) == 0)
|
||||
{
|
||||
if (!S_ISCHR (archive_stat.st_mode))
|
||||
mtioseekable_archive = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: This memset should not be needed. It is present only
|
||||
because other parts of tar may incorrectly access
|
||||
archive_stat even if it's not the archive status. */
|
||||
memset (&archive_stat, 0, sizeof archive_stat);
|
||||
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return (!dev_null_output && !_isrmt (archive)
|
||||
&& psame_inode (&p->stat, &archive_stat));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
static char const dev_null[] = "/dev/null";
|
||||
|
||||
/* 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;
|
||||
static 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));
|
||||
&& (dev_null_stat.st_ino != 0
|
||||
|| stat (dev_null, &dev_null_stat) == 0)
|
||||
&& psame_inode (&archive_stat, &dev_null_stat)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -164,7 +215,7 @@ sys_wait_for_child (pid_t child_pid, bool eof)
|
||||
{
|
||||
int wait_status;
|
||||
|
||||
while (waitpid (child_pid, &wait_status, 0) == -1)
|
||||
while (waitpid (child_pid, &wait_status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (use_compress_program_option);
|
||||
@@ -175,11 +226,11 @@ sys_wait_for_child (pid_t child_pid, bool eof)
|
||||
{
|
||||
int sig = WTERMSIG (wait_status);
|
||||
if (!(!eof && sig == SIGPIPE))
|
||||
FATAL_ERROR ((0, 0, _("Child died with signal %d"), sig));
|
||||
paxfatal (0, _("Child died with signal %d"), sig);
|
||||
}
|
||||
else if (WEXITSTATUS (wait_status) != 0)
|
||||
FATAL_ERROR ((0, 0, _("Child returned status %d"),
|
||||
WEXITSTATUS (wait_status)));
|
||||
paxfatal (0, _("Child returned status %d"),
|
||||
WEXITSTATUS (wait_status));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,13 +245,13 @@ sys_spawn_shell (void)
|
||||
if (child == 0)
|
||||
{
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (shell, "-sh", "-i", (char *) 0);
|
||||
execlp (shell, "-sh", "-i", NULL);
|
||||
exec_fatal (shell);
|
||||
}
|
||||
else
|
||||
{
|
||||
int wait_status;
|
||||
while (waitpid (child, &wait_status, 0) == -1)
|
||||
while (waitpid (child, &wait_status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (shell);
|
||||
@@ -221,41 +272,39 @@ 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);
|
||||
off_t pos = lseek (fd, 0, SEEK_CUR);
|
||||
return pos < 0 ? -1 : ftruncate (fd, pos);
|
||||
}
|
||||
|
||||
/* Return nonzero if NAME is the name of a regular file, or if the file
|
||||
/* Return true 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
|
||||
static bool
|
||||
is_regular_file (const char *name)
|
||||
{
|
||||
struct stat stbuf;
|
||||
|
||||
if (stat (name, &stbuf) == 0)
|
||||
return S_ISREG (stbuf.st_mode);
|
||||
return !!S_ISREG (stbuf.st_mode);
|
||||
else
|
||||
return errno == ENOENT;
|
||||
}
|
||||
|
||||
size_t
|
||||
idx_t
|
||||
sys_write_archive_buffer (void)
|
||||
{
|
||||
return rmtwrite (archive, record_start->buffer, record_size);
|
||||
return rmtwrite (archive, charptr (record_start), record_size);
|
||||
}
|
||||
|
||||
#define PREAD 0 /* read file descriptor from pipe() */
|
||||
#define PWRITE 1 /* write file descriptor from pipe() */
|
||||
/* Read and write file descriptors from a pipe(pipefd) call. */
|
||||
enum { PREAD, PWRITE };
|
||||
|
||||
/* Work around GCC bug 109839. */
|
||||
#if 13 <= __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wanalyzer-fd-leak"
|
||||
#endif
|
||||
|
||||
/* Duplicate file descriptor FROM into becoming INTO.
|
||||
INTO is closed first and has to be the next available slot. */
|
||||
@@ -264,37 +313,20 @@ 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 ();
|
||||
}
|
||||
if (dup2 (from, into) < 0)
|
||||
paxfatal (errno, _("Cannot dup2"));
|
||||
xclose (from);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
|
||||
|
||||
/* Propagate any failure of the grandchild back to the parent. */
|
||||
static void
|
||||
static _Noreturn void
|
||||
wait_for_grandchild (pid_t pid)
|
||||
{
|
||||
int wait_status;
|
||||
int exit_code = 0;
|
||||
|
||||
while (waitpid (pid, &wait_status, 0) == -1)
|
||||
while (waitpid (pid, &wait_status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (use_compress_program_option);
|
||||
@@ -318,6 +350,7 @@ sys_child_open_for_compress (void)
|
||||
pid_t grandchild_pid;
|
||||
pid_t child_pid;
|
||||
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
xpipe (parent_pipe);
|
||||
child_pid = xfork ();
|
||||
|
||||
@@ -365,8 +398,7 @@ sys_child_open_for_compress (void)
|
||||
xdup2 (archive, STDOUT_FILENO);
|
||||
}
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option, NULL);
|
||||
exec_fatal (use_compress_program_option);
|
||||
xexec (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -383,9 +415,7 @@ sys_child_open_for_compress (void)
|
||||
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
|
||||
xclose (child_pipe[PREAD]);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
(char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
xexec (use_compress_program_option);
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
@@ -408,20 +438,20 @@ sys_child_open_for_compress (void)
|
||||
|
||||
while (1)
|
||||
{
|
||||
size_t status = 0;
|
||||
ptrdiff_t status = 0;
|
||||
char *cursor;
|
||||
size_t length;
|
||||
idx_t length;
|
||||
|
||||
/* Assemble a record. */
|
||||
|
||||
for (length = 0, cursor = record_start->buffer;
|
||||
for (length = 0, cursor = charptr (record_start);
|
||||
length < record_size;
|
||||
length += status, cursor += status)
|
||||
{
|
||||
size_t size = record_size - length;
|
||||
idx_t size = record_size - length;
|
||||
|
||||
status = safe_read (STDIN_FILENO, cursor, size);
|
||||
if (status == SAFE_READ_ERROR)
|
||||
if (status < 0)
|
||||
read_fatal (use_compress_program_option);
|
||||
if (status == 0)
|
||||
break;
|
||||
@@ -437,7 +467,7 @@ sys_child_open_for_compress (void)
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
memset (record_start->buffer + length, 0, record_size - length);
|
||||
memset (charptr (record_start) + length, 0, record_size - length);
|
||||
status = sys_write_archive_buffer ();
|
||||
if (status != record_size)
|
||||
archive_write_error (status);
|
||||
@@ -455,6 +485,40 @@ sys_child_open_for_compress (void)
|
||||
wait_for_grandchild (grandchild_pid);
|
||||
}
|
||||
|
||||
static void
|
||||
run_decompress_program (void)
|
||||
{
|
||||
int i;
|
||||
const char *p, *prog = NULL;
|
||||
struct wordsplit ws;
|
||||
int wsflags = (WRDSF_DEFFLAGS | WRDSF_ENV | WRDSF_DOOFFS) & ~WRDSF_NOVAR;
|
||||
|
||||
ws.ws_env = (const char **) environ;
|
||||
ws.ws_offs = 1;
|
||||
|
||||
for (p = first_decompress_program (&i); p; p = next_decompress_program (&i))
|
||||
{
|
||||
if (prog)
|
||||
{
|
||||
warnopt (WARN_DECOMPRESS_PROGRAM, errno, _("cannot run %s"), prog);
|
||||
warnopt (WARN_DECOMPRESS_PROGRAM, 0, _("trying %s"), p);
|
||||
}
|
||||
if (wordsplit (p, &ws, wsflags) != WRDSE_OK)
|
||||
paxfatal (0, _("cannot split string '%s': %s"),
|
||||
p, wordsplit_strerror (&ws));
|
||||
wsflags |= WRDSF_REUSE;
|
||||
memmove (ws.ws_wordv, ws.ws_wordv + ws.ws_offs,
|
||||
ws.ws_wordc * sizeof *ws.ws_wordv);
|
||||
ws.ws_wordv[ws.ws_wordc] = (char *) "-d";
|
||||
prog = p;
|
||||
execvp (ws.ws_wordv[0], ws.ws_wordv);
|
||||
ws.ws_wordv[ws.ws_wordc] = NULL;
|
||||
}
|
||||
if (!prog)
|
||||
paxfatal (0, _("unable to run decompression program"));
|
||||
exec_fatal (prog);
|
||||
}
|
||||
|
||||
/* Set ARCHIVE for uncompressing, then reading an archive. */
|
||||
pid_t
|
||||
sys_child_open_for_uncompress (void)
|
||||
@@ -493,7 +557,7 @@ sys_child_open_for_uncompress (void)
|
||||
&& !_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
|
||||
/* We don't need a grandchild tar. Open the archive and launch the
|
||||
uncompressor. */
|
||||
|
||||
archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
|
||||
@@ -501,9 +565,7 @@ sys_child_open_for_uncompress (void)
|
||||
open_fatal (archive_name_array[0]);
|
||||
xdup2 (archive, STDIN_FILENO);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* We do need a grandchild tar. */
|
||||
@@ -520,9 +582,7 @@ sys_child_open_for_uncompress (void)
|
||||
xdup2 (child_pipe[PREAD], STDIN_FILENO);
|
||||
xclose (child_pipe[PWRITE]);
|
||||
priv_set_restore_linkdir ();
|
||||
execlp (use_compress_program_option, use_compress_program_option,
|
||||
"-d", (char *) 0);
|
||||
exec_fatal (use_compress_program_option);
|
||||
run_decompress_program ();
|
||||
}
|
||||
|
||||
/* The child tar is still here! */
|
||||
@@ -543,34 +603,26 @@ sys_child_open_for_uncompress (void)
|
||||
|
||||
/* Let's read the archive and pipe it into stdout. */
|
||||
|
||||
while (1)
|
||||
while (true)
|
||||
{
|
||||
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)
|
||||
ptrdiff_t n;
|
||||
while ((n = rmtread (archive, charptr (record_start), record_size)) < 0)
|
||||
archive_read_error ();
|
||||
if (n == 0)
|
||||
break;
|
||||
cursor = record_start->buffer;
|
||||
maximum = status;
|
||||
while (maximum)
|
||||
|
||||
char *cursor = charptr (record_start);
|
||||
do
|
||||
{
|
||||
count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
|
||||
idx_t count = min (n, BLOCKSIZE);
|
||||
if (full_write (STDOUT_FILENO, cursor, count) != count)
|
||||
write_error (use_compress_program_option);
|
||||
cursor += count;
|
||||
maximum -= count;
|
||||
n -= count;
|
||||
}
|
||||
while (n);
|
||||
}
|
||||
|
||||
xclose (STDOUT_FILENO);
|
||||
@@ -583,11 +635,8 @@ sys_child_open_for_uncompress (void)
|
||||
static void
|
||||
dec_to_env (char const *envar, uintmax_t num)
|
||||
{
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
char *numstr;
|
||||
|
||||
numstr = STRINGIFY_BIGINT (num, buf);
|
||||
if (setenv (envar, numstr, 1) != 0)
|
||||
char numstr[UINTMAX_STRSIZE_BOUND];
|
||||
if (setenv (envar, umaxtostr (num, numstr), 1) < 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
@@ -595,17 +644,19 @@ static void
|
||||
time_to_env (char const *envar, struct timespec t)
|
||||
{
|
||||
char buf[TIMESPEC_STRSIZE_BOUND];
|
||||
if (setenv (envar, code_timespec (t, buf), 1) != 0)
|
||||
if (setenv (envar, code_timespec (t, buf), 1) < 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
static void
|
||||
oct_to_env (char const *envar, unsigned long num)
|
||||
oct_to_env (char const *envar, mode_t m)
|
||||
{
|
||||
char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
|
||||
|
||||
snprintf (buf, sizeof buf, "0%lo", num);
|
||||
if (setenv (envar, buf, 1) != 0)
|
||||
char buf[sizeof "0" + (UINTMAX_WIDTH + 2) / 3];
|
||||
uintmax_t um = m;
|
||||
if (EXPR_SIGNED (m) && sizeof m < sizeof um)
|
||||
um &= ~ (UINTMAX_MAX << TYPE_WIDTH (m));
|
||||
sprintf (buf, "%#"PRIoMAX, um);
|
||||
if (setenv (envar, buf, 1) < 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
@@ -614,7 +665,7 @@ str_to_env (char const *envar, char const *str)
|
||||
{
|
||||
if (str)
|
||||
{
|
||||
if (setenv (envar, str, 1) != 0)
|
||||
if (setenv (envar, str, 1) < 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
else
|
||||
@@ -627,7 +678,7 @@ chr_to_env (char const *envar, char c)
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
if (setenv (envar, buf, 1) != 0)
|
||||
if (setenv (envar, buf, 1) < 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
@@ -679,13 +730,12 @@ stat_to_env (char *name, char type, struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
static pid_t global_pid;
|
||||
static RETSIGTYPE (*pipe_handler) (int sig);
|
||||
static void (*pipe_handler) (int sig);
|
||||
|
||||
int
|
||||
sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
|
||||
sys_exec_command (char *file_name, char typechar, struct tar_stat_info *st)
|
||||
{
|
||||
int p[2];
|
||||
char *argv[4];
|
||||
|
||||
xpipe (p);
|
||||
pipe_handler = signal (SIGPIPE, SIG_IGN);
|
||||
@@ -703,15 +753,8 @@ sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st)
|
||||
|
||||
stat_to_env (file_name, typechar, st);
|
||||
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = to_command_option;
|
||||
argv[3] = NULL;
|
||||
|
||||
priv_set_restore_linkdir ();
|
||||
execv ("/bin/sh", argv);
|
||||
|
||||
exec_fatal (file_name);
|
||||
xexec (to_command_option);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -723,7 +766,7 @@ sys_wait_command (void)
|
||||
return;
|
||||
|
||||
signal (SIGPIPE, pipe_handler);
|
||||
while (waitpid (global_pid, &status, 0) == -1)
|
||||
while (waitpid (global_pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
global_pid = -1;
|
||||
@@ -734,54 +777,65 @@ sys_wait_command (void)
|
||||
if (WIFEXITED (status))
|
||||
{
|
||||
if (!ignore_command_error_option && WEXITSTATUS (status))
|
||||
ERROR ((0, 0, _("%lu: Child returned status %d"),
|
||||
(unsigned long) global_pid, WEXITSTATUS (status)));
|
||||
paxerror (0, _("%jd: Child returned status %d"),
|
||||
intmax (global_pid), WEXITSTATUS (status));
|
||||
}
|
||||
else if (WIFSIGNALED (status))
|
||||
{
|
||||
WARN ((0, 0, _("%lu: Child terminated on signal %d"),
|
||||
(unsigned long) global_pid, WTERMSIG (status)));
|
||||
paxwarn (0, _("%jd: Child terminated on signal %d"),
|
||||
intmax (global_pid), WTERMSIG (status));
|
||||
}
|
||||
else
|
||||
ERROR ((0, 0, _("%lu: Child terminated on unknown reason"),
|
||||
(unsigned long) global_pid));
|
||||
paxerror (0, _("%jd: Child terminated on unknown reason"),
|
||||
intmax (global_pid));
|
||||
|
||||
global_pid = -1;
|
||||
}
|
||||
|
||||
int
|
||||
sys_exec_info_script (const char **archive_name, int volume_number)
|
||||
sys_exec_info_script (const char **archive_name, intmax_t volume_number)
|
||||
{
|
||||
pid_t pid;
|
||||
char *argv[4];
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
int p[2];
|
||||
static RETSIGTYPE (*saved_handler) (int sig);
|
||||
static void (*saved_handler) (int sig);
|
||||
|
||||
xpipe (p);
|
||||
saved_handler = signal (SIGPIPE, SIG_IGN);
|
||||
|
||||
pid = xfork ();
|
||||
pid_t pid = xfork ();
|
||||
|
||||
if (pid != 0)
|
||||
{
|
||||
/* Master */
|
||||
|
||||
int rc;
|
||||
int status;
|
||||
char *buf = NULL;
|
||||
size_t size = 0;
|
||||
FILE *fp;
|
||||
|
||||
xclose (p[PWRITE]);
|
||||
fp = fdopen (p[PREAD], "r");
|
||||
rc = getline (&buf, &size, fp);
|
||||
fclose (fp);
|
||||
FILE *fp = fdopen (p[PREAD], "r");
|
||||
if (!fp)
|
||||
{
|
||||
signal (SIGPIPE, saved_handler);
|
||||
call_arg_error ("fdopen", info_script_option);
|
||||
return -1;
|
||||
}
|
||||
ssize_t rc = getline (&buf, &size, fp);
|
||||
if (rc < 0)
|
||||
{
|
||||
signal (SIGPIPE, saved_handler);
|
||||
read_error (info_script_option);
|
||||
return -1;
|
||||
}
|
||||
*archive_name = buf;
|
||||
buf[rc - 1] = '\0';
|
||||
if (fclose (fp) < 0)
|
||||
{
|
||||
signal (SIGPIPE, saved_handler);
|
||||
close_error (info_script_option);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc > 0 && buf[rc-1] == '\n')
|
||||
buf[--rc] = 0;
|
||||
|
||||
while (waitpid (pid, &status, 0) == -1)
|
||||
while (waitpid (pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
signal (SIGPIPE, saved_handler);
|
||||
@@ -790,55 +844,32 @@ sys_exec_info_script (const char **archive_name, int volume_number)
|
||||
}
|
||||
|
||||
signal (SIGPIPE, saved_handler);
|
||||
|
||||
if (WIFEXITED (status))
|
||||
{
|
||||
if (WEXITSTATUS (status) == 0 && rc > 0)
|
||||
*archive_name = buf;
|
||||
else
|
||||
free (buf);
|
||||
return WEXITSTATUS (status);
|
||||
}
|
||||
|
||||
free (buf);
|
||||
return -1;
|
||||
return WIFEXITED (status) ? WEXITSTATUS (status) : -1;
|
||||
}
|
||||
|
||||
/* Child */
|
||||
setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
|
||||
setenv ("TAR_ARCHIVE", *archive_name, 1);
|
||||
setenv ("TAR_VOLUME", STRINGIFY_BIGINT (volume_number, uintbuf), 1);
|
||||
setenv ("TAR_BLOCKING_FACTOR",
|
||||
STRINGIFY_BIGINT (blocking_factor, uintbuf), 1);
|
||||
str_to_env ("TAR_VERSION", PACKAGE_VERSION);
|
||||
str_to_env ("TAR_ARCHIVE", *archive_name);
|
||||
dec_to_env ("TAR_VOLUME", volume_number);
|
||||
dec_to_env ("TAR_BLOCKING_FACTOR", blocking_factor);
|
||||
setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
|
||||
setenv ("TAR_FORMAT",
|
||||
archive_format_string (current_format == DEFAULT_FORMAT ?
|
||||
archive_format : current_format), 1);
|
||||
setenv ("TAR_FD", STRINGIFY_BIGINT (p[PWRITE], uintbuf), 1);
|
||||
dec_to_env ("TAR_FD", p[PWRITE]);
|
||||
|
||||
xclose (p[PREAD]);
|
||||
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = (char *) info_script_option;
|
||||
argv[3] = NULL;
|
||||
|
||||
priv_set_restore_linkdir ();
|
||||
execv (argv[0], argv);
|
||||
|
||||
exec_fatal (info_script_option);
|
||||
xexec (info_script_option);
|
||||
}
|
||||
|
||||
void
|
||||
sys_exec_checkpoint_script (const char *script_name,
|
||||
const char *archive_name,
|
||||
int checkpoint_number)
|
||||
intmax_t checkpoint_number)
|
||||
{
|
||||
pid_t pid;
|
||||
char *argv[4];
|
||||
char uintbuf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
pid = xfork ();
|
||||
pid_t pid = xfork ();
|
||||
|
||||
if (pid != 0)
|
||||
{
|
||||
@@ -846,7 +877,7 @@ sys_exec_checkpoint_script (const char *script_name,
|
||||
|
||||
int status;
|
||||
|
||||
while (waitpid (pid, &status, 0) == -1)
|
||||
while (waitpid (pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
waitpid_error (script_name);
|
||||
@@ -857,24 +888,175 @@ sys_exec_checkpoint_script (const char *script_name,
|
||||
}
|
||||
|
||||
/* Child */
|
||||
setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
|
||||
setenv ("TAR_ARCHIVE", archive_name, 1);
|
||||
setenv ("TAR_CHECKPOINT", STRINGIFY_BIGINT (checkpoint_number, uintbuf), 1);
|
||||
setenv ("TAR_BLOCKING_FACTOR",
|
||||
STRINGIFY_BIGINT (blocking_factor, uintbuf), 1);
|
||||
setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
|
||||
setenv ("TAR_FORMAT",
|
||||
archive_format_string (current_format == DEFAULT_FORMAT ?
|
||||
archive_format : current_format), 1);
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = (char *) script_name;
|
||||
argv[3] = NULL;
|
||||
|
||||
str_to_env ("TAR_VERSION", PACKAGE_VERSION);
|
||||
str_to_env ("TAR_ARCHIVE", archive_name);
|
||||
dec_to_env ("TAR_CHECKPOINT", checkpoint_number);
|
||||
dec_to_env ("TAR_BLOCKING_FACTOR", blocking_factor);
|
||||
str_to_env ("TAR_SUBCOMMAND", subcommand_string (subcommand_option));
|
||||
str_to_env ("TAR_FORMAT",
|
||||
archive_format_string (current_format == DEFAULT_FORMAT
|
||||
? archive_format : current_format));
|
||||
priv_set_restore_linkdir ();
|
||||
execv (argv[0], argv);
|
||||
xexec (script_name);
|
||||
}
|
||||
|
||||
exec_fatal (script_name);
|
||||
bool
|
||||
sys_exec_setmtime_script (const char *script_name,
|
||||
int dirfd,
|
||||
const char *file_name,
|
||||
const char *fmt,
|
||||
struct timespec *ts)
|
||||
{
|
||||
pid_t pid;
|
||||
int p[2];
|
||||
bool stop = false;
|
||||
struct pollfd pfd;
|
||||
|
||||
char *buffer = NULL;
|
||||
idx_t buflen = 0;
|
||||
idx_t bufsize = 0;
|
||||
char *cp;
|
||||
bool rc = true;
|
||||
|
||||
if (pipe (p) < 0)
|
||||
paxfatal (errno, _("pipe failed"));
|
||||
|
||||
if ((pid = xfork ()) == 0)
|
||||
{
|
||||
char *command = xmalloc (strlen (script_name) + strlen (file_name) + 2);
|
||||
|
||||
strcpy (command, script_name);
|
||||
strcat (command, " ");
|
||||
strcat (command, file_name);
|
||||
|
||||
if (dirfd != AT_FDCWD && fchdir (dirfd) < 0)
|
||||
paxfatal (errno, _("chdir failed"));
|
||||
|
||||
close (p[0]);
|
||||
if (dup2 (p[1], STDOUT_FILENO) < 0)
|
||||
paxfatal (errno, _("dup2 failed"));
|
||||
if (p[1] != STDOUT_FILENO)
|
||||
close (p[1]);
|
||||
|
||||
close (STDIN_FILENO);
|
||||
if (open (dev_null, O_RDONLY) != STDIN_FILENO)
|
||||
open_error (dev_null);
|
||||
|
||||
priv_set_restore_linkdir ();
|
||||
/* FIXME: This mishandles shell metacharacters in the file name.
|
||||
Come to think of it, isn't every use of xexec suspect? */
|
||||
xexec (command);
|
||||
}
|
||||
close (p[1]);
|
||||
|
||||
pfd.fd = p[0];
|
||||
pfd.events = POLLIN;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int n = poll (&pfd, 1, -1);
|
||||
if (n < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
paxerror (errno, _("poll failed"));
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
if (pfd.revents & POLLIN)
|
||||
{
|
||||
if (buflen == bufsize)
|
||||
buffer = xpalloc (buffer, &bufsize, 1, -1, 1);
|
||||
ssize_t nread = read (pfd.fd, buffer + buflen, bufsize - buflen);
|
||||
if (nread < 0)
|
||||
{
|
||||
paxerror (errno, _("error reading output of %s"), script_name);
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
if (nread == 0)
|
||||
break;
|
||||
buflen += n;
|
||||
}
|
||||
else if (pfd.revents & POLLHUP)
|
||||
break;
|
||||
}
|
||||
close (pfd.fd);
|
||||
|
||||
if (stop)
|
||||
kill (SIGKILL, pid);
|
||||
|
||||
sys_wait_for_child (pid, false);
|
||||
|
||||
if (stop)
|
||||
{
|
||||
free (buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buflen == 0)
|
||||
{
|
||||
paxerror (0, _("empty output from \"%s %s\""), script_name, file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
cp = memchr (buffer, '\n', buflen);
|
||||
if (cp)
|
||||
*cp = 0;
|
||||
else
|
||||
{
|
||||
if (buflen == bufsize)
|
||||
buffer = xirealloc (buffer, ++bufsize);
|
||||
buffer[buflen] = 0;
|
||||
}
|
||||
|
||||
if (fmt)
|
||||
{
|
||||
struct tm tm;
|
||||
time_t t;
|
||||
cp = strptime (buffer, fmt, &tm);
|
||||
if (cp == NULL)
|
||||
{
|
||||
paxerror (0, _("output from \"%s %s\" does not satisfy format string:"
|
||||
" %s"),
|
||||
script_name, file_name, buffer);
|
||||
rc = false;
|
||||
}
|
||||
else if (*cp != 0)
|
||||
{
|
||||
paxwarn (0, _("unconsumed output from \"%s %s\": %s"),
|
||||
script_name, file_name, cp);
|
||||
rc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.tm_wday = -1;
|
||||
t = mktime (&tm);
|
||||
if (tm.tm_wday < 0)
|
||||
{
|
||||
paxerror (errno, _("mktime failed"));
|
||||
rc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts->tv_sec = t;
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (! parse_datetime (ts, buffer, NULL))
|
||||
{
|
||||
paxerror (0, _("unparsable output from \"%s %s\": %s"),
|
||||
script_name, file_name, buffer);
|
||||
rc = false;
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* not MSDOS */
|
||||
|
||||
188
src/tar.h
188
src/tar.h
@@ -1,21 +1,21 @@
|
||||
/* GNU tar Archive Format description.
|
||||
|
||||
Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
||||
2000, 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 1988-2025 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 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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 3 of the License, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* tar Header Block, from POSIX 1003.1-1990. */
|
||||
|
||||
@@ -48,41 +48,48 @@ struct posix_header
|
||||
#define TVERSLEN 2
|
||||
|
||||
/* Values used in typeflag field. */
|
||||
#define REGTYPE '0' /* regular file */
|
||||
#define AREGTYPE '\0' /* regular file */
|
||||
#define LNKTYPE '1' /* link */
|
||||
#define SYMTYPE '2' /* reserved */
|
||||
#define CHRTYPE '3' /* character special */
|
||||
#define BLKTYPE '4' /* block special */
|
||||
#define DIRTYPE '5' /* directory */
|
||||
#define FIFOTYPE '6' /* FIFO special */
|
||||
#define CONTTYPE '7' /* reserved */
|
||||
enum
|
||||
{
|
||||
|
||||
#define XHDTYPE 'x' /* Extended header referring to the
|
||||
REGTYPE = '0', /* regular file */
|
||||
AREGTYPE = '\0', /* regular file */
|
||||
LNKTYPE = '1', /* link */
|
||||
SYMTYPE = '2', /* reserved */
|
||||
CHRTYPE = '3', /* character special */
|
||||
BLKTYPE = '4', /* block special */
|
||||
DIRTYPE = '5', /* directory */
|
||||
FIFOTYPE = '6', /* FIFO special */
|
||||
CONTTYPE = '7', /* reserved */
|
||||
|
||||
XHDTYPE = 'x', /* Extended header referring to the
|
||||
next file in the archive */
|
||||
#define XGLTYPE 'g' /* Global extended header */
|
||||
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 */
|
||||
#define TSVTX 01000 /* reserved */
|
||||
enum
|
||||
{
|
||||
TSUID = 04000, /* set UID on execution */
|
||||
TSGID = 02000, /* set GID on execution */
|
||||
TSVTX = 01000, /* reserved */
|
||||
/* file permissions */
|
||||
#define TUREAD 00400 /* read by owner */
|
||||
#define TUWRITE 00200 /* write by owner */
|
||||
#define TUEXEC 00100 /* execute/search by owner */
|
||||
#define TGREAD 00040 /* read by group */
|
||||
#define TGWRITE 00020 /* write by group */
|
||||
#define TGEXEC 00010 /* execute/search by group */
|
||||
#define TOREAD 00004 /* read by other */
|
||||
#define TOWRITE 00002 /* write by other */
|
||||
#define TOEXEC 00001 /* execute/search by other */
|
||||
TUREAD = 00400, /* read by owner */
|
||||
TUWRITE = 00200, /* write by owner */
|
||||
TUEXEC = 00100, /* execute/search by owner */
|
||||
TGREAD = 00040, /* read by group */
|
||||
TGWRITE = 00020, /* write by group */
|
||||
TGEXEC = 00010, /* execute/search by group */
|
||||
TOREAD = 00004, /* read by other */
|
||||
TOWRITE = 00002, /* write by other */
|
||||
TOEXEC = 00001 /* execute/search by other */
|
||||
};
|
||||
|
||||
/* tar Header Block, GNU extensions. */
|
||||
|
||||
/* In GNU tar, SYMTYPE is for to symbolic links, and CONTTYPE is for
|
||||
contiguous files, so maybe disobeying the `reserved' comment in POSIX
|
||||
contiguous files, so maybe disobeying the "reserved" comment in POSIX
|
||||
header description. I suspect these were meant to be used this way, and
|
||||
should not have really been `reserved' in the published standards. */
|
||||
should not have really been "reserved" in the published standards. */
|
||||
|
||||
/* *BEWARE* *BEWARE* *BEWARE* that the following information is still
|
||||
boiling, and may change. Even if the OLDGNU format description should be
|
||||
@@ -111,9 +118,12 @@ struct sparse
|
||||
necessary. The following constants tell how many sparse descriptors fit
|
||||
in each kind of header able to hold them. */
|
||||
|
||||
#define SPARSES_IN_EXTRA_HEADER 16
|
||||
#define SPARSES_IN_OLDGNU_HEADER 4
|
||||
#define SPARSES_IN_SPARSE_HEADER 21
|
||||
enum
|
||||
{
|
||||
SPARSES_IN_EXTRA_HEADER = 16,
|
||||
SPARSES_IN_OLDGNU_HEADER = 4,
|
||||
SPARSES_IN_SPARSE_HEADER = 21
|
||||
};
|
||||
|
||||
/* Extension header for sparse files, used immediately after the GNU extra
|
||||
header, and used only if all sparse information cannot fit into that
|
||||
@@ -168,29 +178,32 @@ struct oldgnu_header
|
||||
'N' Obsolete GNU tar, for file names that do not fit into the main header.
|
||||
'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. */
|
||||
#define GNUTYPE_DUMPDIR 'D'
|
||||
enum
|
||||
{
|
||||
/* This is a dir entry that contains the names of files that were in the
|
||||
dir at the time the dump was made. */
|
||||
GNUTYPE_DUMPDIR = 'D',
|
||||
|
||||
/* Identifies the *next* file on the tape as having a long linkname. */
|
||||
#define GNUTYPE_LONGLINK 'K'
|
||||
/* Identifies the *next* file on the tape as having a long linkname. */
|
||||
GNUTYPE_LONGLINK = 'K',
|
||||
|
||||
/* Identifies the *next* file on the tape as having a long name. */
|
||||
#define GNUTYPE_LONGNAME 'L'
|
||||
/* Identifies the *next* file on the tape as having a long name. */
|
||||
GNUTYPE_LONGNAME = 'L',
|
||||
|
||||
/* This is the continuation of a file that began on another volume. */
|
||||
#define GNUTYPE_MULTIVOL 'M'
|
||||
/* This is the continuation of a file that began on another volume. */
|
||||
GNUTYPE_MULTIVOL = 'M',
|
||||
|
||||
/* This is for sparse files. */
|
||||
#define GNUTYPE_SPARSE 'S'
|
||||
/* This is for sparse files. */
|
||||
GNUTYPE_SPARSE = 'S',
|
||||
|
||||
/* This file is a tape/volume header. Ignore it on extraction. */
|
||||
#define GNUTYPE_VOLHDR 'V'
|
||||
/* This file is a tape/volume header. Ignore it on extraction. */
|
||||
GNUTYPE_VOLHDR = 'V',
|
||||
|
||||
/* Solaris extended header */
|
||||
#define SOLARIS_XHDTYPE 'X'
|
||||
/* Solaris extended header. */
|
||||
SOLARIS_XHDTYPE = 'X'
|
||||
};
|
||||
|
||||
/* J@"org Schilling star header */
|
||||
/* Jörg Schilling star header. */
|
||||
|
||||
struct star_header
|
||||
{ /* byte offset */
|
||||
@@ -215,8 +228,11 @@ struct star_header
|
||||
/* 500 */
|
||||
};
|
||||
|
||||
#define SPARSES_IN_STAR_HEADER 4
|
||||
#define SPARSES_IN_STAR_EXT_HEADER 21
|
||||
enum
|
||||
{
|
||||
SPARSES_IN_STAR_HEADER = 4,
|
||||
SPARSES_IN_STAR_EXT_HEADER = 21
|
||||
};
|
||||
|
||||
struct star_in_header
|
||||
{
|
||||
@@ -245,8 +261,9 @@ struct star_ext_header
|
||||
|
||||
/* tar Header Block, overall structure. */
|
||||
|
||||
/* tar files are made in basic blocks of this size. */
|
||||
#define BLOCKSIZE 512
|
||||
/* tar files are made in basic blocks of size BLOCKSIZE.
|
||||
LG_BLOCKSIZE is the log base 2 of BLOCKSIZE. */
|
||||
enum { LG_BLOCKSIZE = 9, BLOCKSIZE = 1 << LG_BLOCKSIZE };
|
||||
|
||||
enum archive_format
|
||||
{
|
||||
@@ -271,9 +288,24 @@ struct sp_array
|
||||
struct xheader
|
||||
{
|
||||
struct obstack *stk;
|
||||
size_t size;
|
||||
idx_t size;
|
||||
char *buffer;
|
||||
uintmax_t string_length;
|
||||
idx_t string_length;
|
||||
};
|
||||
|
||||
/* Information about xattrs for a file. */
|
||||
struct xattr_array
|
||||
{
|
||||
char *xkey;
|
||||
char *xval_ptr;
|
||||
idx_t xval_len;
|
||||
};
|
||||
|
||||
struct xattr_map
|
||||
{
|
||||
struct xattr_array *xm_map;
|
||||
idx_t xm_size; /* Size of the xattr map */
|
||||
idx_t xm_max; /* Max. number of entries in xattr_map */
|
||||
};
|
||||
|
||||
struct tar_stat_info
|
||||
@@ -287,6 +319,15 @@ struct tar_stat_info
|
||||
|
||||
char *uname; /* user name of owner */
|
||||
char *gname; /* group name of owner */
|
||||
|
||||
char *cntx_name; /* SELinux context for the current archive entry. */
|
||||
|
||||
char *acls_a_ptr; /* Access ACLs for the current archive entry. */
|
||||
idx_t acls_a_len; /* Access ACLs for the current archive entry. */
|
||||
|
||||
char *acls_d_ptr; /* Default ACLs for the current archive entry. */
|
||||
idx_t acls_d_len; /* Default ACLs for the current archive entry. */
|
||||
|
||||
struct stat stat; /* regular filesystem stat */
|
||||
|
||||
/* STAT doesn't always have access, data modification, and status
|
||||
@@ -301,14 +342,24 @@ struct tar_stat_info
|
||||
bool is_sparse; /* Is the file sparse */
|
||||
|
||||
/* For sparse files: */
|
||||
unsigned sparse_major;
|
||||
unsigned sparse_minor;
|
||||
size_t sparse_map_avail; /* Index to the first unused element in
|
||||
intmax_t sparse_major;
|
||||
intmax_t sparse_minor;
|
||||
idx_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 */
|
||||
idx_t sparse_map_size; /* Size of the sparse map */
|
||||
struct sp_array *sparse_map;
|
||||
|
||||
off_t real_size; /* The real size of sparse file */
|
||||
bool real_size_set; /* True when GNU.sparse.realsize is set in
|
||||
archived file */
|
||||
|
||||
bool sparse_name_done; /* Set to true if 'GNU.sparse.name' header was
|
||||
processed pax header parsing. Following 'path'
|
||||
header (lower priority) will be ignored. */
|
||||
|
||||
struct xattr_map xattr_map;
|
||||
|
||||
/* Extended headers */
|
||||
struct xheader xhdr;
|
||||
|
||||
@@ -337,6 +388,9 @@ struct tar_stat_info
|
||||
It is negative if it could not be reopened after it was closed.
|
||||
Negate it to find out what errno was when the reopen failed. */
|
||||
int fd;
|
||||
|
||||
/* Exclusion list */
|
||||
struct exclist *exclude_list;
|
||||
};
|
||||
|
||||
union block
|
||||
|
||||
306
src/transform.c
306
src/transform.c
@@ -1,5 +1,5 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
Copyright 2006-2025 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
|
||||
@@ -12,11 +12,12 @@
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <regex.h>
|
||||
#include <mcel.h>
|
||||
#include <quotearg.h>
|
||||
#include "common.h"
|
||||
|
||||
enum transform_type
|
||||
@@ -50,9 +51,9 @@ struct replace_segm
|
||||
struct
|
||||
{
|
||||
char *ptr;
|
||||
size_t size;
|
||||
idx_t size;
|
||||
} literal; /* type == segm_literal */
|
||||
size_t ref; /* type == segm_backref */
|
||||
idx_t ref; /* type == segm_backref */
|
||||
enum case_ctl_type ctl; /* type == segm_case_ctl */
|
||||
} v;
|
||||
};
|
||||
@@ -62,16 +63,16 @@ struct transform
|
||||
struct transform *next;
|
||||
enum transform_type transform_type;
|
||||
int flags;
|
||||
unsigned match_number;
|
||||
idx_t match_number;
|
||||
regex_t regex;
|
||||
/* Compiled replacement expression */
|
||||
struct replace_segm *repl_head, *repl_tail;
|
||||
size_t segm_count; /* Number of elements in the above list */
|
||||
idx_t segm_count; /* Number of elements in the above list */
|
||||
};
|
||||
|
||||
|
||||
|
||||
int transform_flags = XFORM_ALL;
|
||||
static int transform_flags = XFORM_ALL;
|
||||
static struct transform *transform_head, *transform_tail;
|
||||
|
||||
static struct transform *
|
||||
@@ -101,9 +102,9 @@ add_segment (struct transform *tf)
|
||||
}
|
||||
|
||||
static void
|
||||
add_literal_segment (struct transform *tf, char *str, char *end)
|
||||
add_literal_segment (struct transform *tf, const char *str, const char *end)
|
||||
{
|
||||
size_t len = end - str;
|
||||
idx_t len = end - str;
|
||||
if (len)
|
||||
{
|
||||
struct replace_segm *segm = add_segment (tf);
|
||||
@@ -116,7 +117,7 @@ add_literal_segment (struct transform *tf, char *str, char *end)
|
||||
}
|
||||
|
||||
static void
|
||||
add_char_segment (struct transform *tf, int chr)
|
||||
add_char_segment (struct transform *tf, char chr)
|
||||
{
|
||||
struct replace_segm *segm = add_segment (tf);
|
||||
segm->type = segm_literal;
|
||||
@@ -127,15 +128,15 @@ add_char_segment (struct transform *tf, int chr)
|
||||
}
|
||||
|
||||
static void
|
||||
add_backref_segment (struct transform *tf, size_t ref)
|
||||
add_backref_segment (struct transform *tf, idx_t ref)
|
||||
{
|
||||
struct replace_segm *segm = add_segment (tf);
|
||||
segm->type = segm_backref;
|
||||
segm->v.ref = ref;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_xform_flags (int *pflags, int c)
|
||||
static bool
|
||||
parse_xform_flags (int *pflags, char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -164,9 +165,9 @@ parse_xform_flags (int *pflags, int c)
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -180,8 +181,7 @@ add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl)
|
||||
static const char *
|
||||
parse_transform_expr (const char *expr)
|
||||
{
|
||||
int delim;
|
||||
int i, j, rc;
|
||||
idx_t i, j;
|
||||
char *str, *beg, *cur;
|
||||
const char *p;
|
||||
int cflags = 0;
|
||||
@@ -199,16 +199,17 @@ parse_transform_expr (const char *expr)
|
||||
expr++;
|
||||
break;
|
||||
}
|
||||
if (parse_xform_flags (&transform_flags, *expr))
|
||||
USAGE_ERROR ((0, 0, _("Unknown transform flag: %c"),
|
||||
*expr));
|
||||
if (!parse_xform_flags (&transform_flags, *expr))
|
||||
paxusage (_("Unknown transform flag: %c"), *expr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
paxusage (_("Invalid transform expression"));
|
||||
}
|
||||
|
||||
delim = expr[1];
|
||||
char delim = expr[1];
|
||||
if (!delim)
|
||||
paxusage (_("Invalid transform expression"));
|
||||
|
||||
/* Scan regular expression */
|
||||
for (i = 2; expr[i] && expr[i] != delim; i++)
|
||||
@@ -216,7 +217,7 @@ parse_transform_expr (const char *expr)
|
||||
i++;
|
||||
|
||||
if (expr[i] != delim)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
paxusage (_("Invalid transform expression"));
|
||||
|
||||
/* Scan replacement expression */
|
||||
for (j = i + 1; expr[j] && expr[j] != delim; j++)
|
||||
@@ -224,7 +225,7 @@ parse_transform_expr (const char *expr)
|
||||
j++;
|
||||
|
||||
if (expr[j] != delim)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression")));
|
||||
paxusage (_("Invalid transform expression"));
|
||||
|
||||
/* Check flags */
|
||||
tf->transform_type = transform_first;
|
||||
@@ -246,14 +247,16 @@ parse_transform_expr (const char *expr)
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
tf->match_number = strtoul (p, (char**) &p, 0);
|
||||
p--;
|
||||
{
|
||||
char *endp;
|
||||
tf->match_number = stoint (p, &endp, NULL, 0, IDX_MAX);
|
||||
p = endp - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (parse_xform_flags (&tf->flags, *p))
|
||||
USAGE_ERROR ((0, 0, _("Unknown flag in transform expression: %c"),
|
||||
*p));
|
||||
if (!parse_xform_flags (&tf->flags, *p))
|
||||
paxusage (_("Unknown flag in transform expression: %c"), *p);
|
||||
}
|
||||
|
||||
if (*p == ';')
|
||||
@@ -264,16 +267,16 @@ parse_transform_expr (const char *expr)
|
||||
memcpy (str, expr + 2, i - 2);
|
||||
str[i - 2] = 0;
|
||||
|
||||
rc = regcomp (&tf->regex, str, cflags);
|
||||
int rc = regcomp (&tf->regex, str, cflags);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
char errbuf[512];
|
||||
regerror (rc, &tf->regex, errbuf, sizeof (errbuf));
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
|
||||
paxusage (_("Invalid transform expression: %s"), errbuf);
|
||||
}
|
||||
|
||||
if (str[0] == '^' || str[strlen (str) - 1] == '$')
|
||||
if (str[0] == '^' || (i > 2 && str[i - 3] == '$'))
|
||||
tf->transform_type = transform_first;
|
||||
|
||||
free (str);
|
||||
@@ -288,17 +291,18 @@ parse_transform_expr (const char *expr)
|
||||
{
|
||||
if (*cur == '\\')
|
||||
{
|
||||
size_t n;
|
||||
|
||||
add_literal_segment (tf, beg, cur);
|
||||
switch (*++cur)
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
n = strtoul (cur, &cur, 10);
|
||||
if (n > tf->regex.re_nsub)
|
||||
USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
|
||||
add_backref_segment (tf, n);
|
||||
{
|
||||
idx_t n = stoint (cur, &cur, NULL, 0, IDX_MAX);
|
||||
if (tf->regex.re_nsub < n)
|
||||
paxusage (_("Invalid transform replacement:"
|
||||
" back reference out of range"));
|
||||
add_backref_segment (tf, n);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
@@ -347,7 +351,7 @@ parse_transform_expr (const char *expr)
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
/* Turn the replacement to lowercase until a `\U' or `\E'
|
||||
/* Turn the replacement to lowercase until a '\U' or '\E'
|
||||
is found, */
|
||||
add_case_ctl_segment (tf, ctl_locase);
|
||||
cur++;
|
||||
@@ -360,7 +364,7 @@ parse_transform_expr (const char *expr)
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
/* Turn the replacement to uppercase until a `\L' or `\E'
|
||||
/* Turn the replacement to uppercase until a '\L' or '\E'
|
||||
is found, */
|
||||
add_case_ctl_segment (tf, ctl_upcase);
|
||||
cur++;
|
||||
@@ -373,19 +377,21 @@ parse_transform_expr (const char *expr)
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
/* Stop case conversion started by `\L' or `\U'. */
|
||||
/* Stop case conversion started by '\L' or '\U'. */
|
||||
add_case_ctl_segment (tf, ctl_stop);
|
||||
cur++;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Try to be nice */
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = '\\';
|
||||
buf[1] = *cur;
|
||||
add_literal_segment (tf, buf, buf + 2);
|
||||
}
|
||||
if (*cur == delim)
|
||||
add_char_segment (tf, delim);
|
||||
else
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = '\\';
|
||||
buf[1] = *cur;
|
||||
add_literal_segment (tf, buf, buf + 2);
|
||||
}
|
||||
cur++;
|
||||
break;
|
||||
}
|
||||
@@ -401,6 +407,7 @@ parse_transform_expr (const char *expr)
|
||||
cur++;
|
||||
}
|
||||
add_literal_segment (tf, beg, cur);
|
||||
free(str);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -412,74 +419,56 @@ set_transform_expr (const char *expr)
|
||||
expr = parse_transform_expr (expr);
|
||||
}
|
||||
|
||||
/* Run case conversion specified by CASE_CTL on array PTR of SIZE
|
||||
characters. Returns pointer to statically allocated storage. */
|
||||
static char *
|
||||
run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
|
||||
{
|
||||
static char *case_ctl_buffer;
|
||||
static size_t case_ctl_bufsize;
|
||||
char *p;
|
||||
|
||||
if (case_ctl_bufsize < size)
|
||||
{
|
||||
case_ctl_bufsize = size;
|
||||
case_ctl_buffer = xrealloc (case_ctl_buffer, case_ctl_bufsize);
|
||||
}
|
||||
memcpy (case_ctl_buffer, ptr, size);
|
||||
switch (case_ctl)
|
||||
{
|
||||
case ctl_upcase_next:
|
||||
case_ctl_buffer[0] = toupper ((unsigned char) case_ctl_buffer[0]);
|
||||
break;
|
||||
|
||||
case ctl_locase_next:
|
||||
case_ctl_buffer[0] = tolower ((unsigned char) case_ctl_buffer[0]);
|
||||
break;
|
||||
|
||||
case ctl_upcase:
|
||||
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
|
||||
*p = toupper ((unsigned char) *p);
|
||||
break;
|
||||
|
||||
case ctl_locase:
|
||||
for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
|
||||
*p = tolower ((unsigned char) *p);
|
||||
break;
|
||||
|
||||
case ctl_stop:
|
||||
break;
|
||||
}
|
||||
return case_ctl_buffer;
|
||||
}
|
||||
|
||||
|
||||
static struct obstack stk;
|
||||
static bool stk_init;
|
||||
|
||||
/* Run case conversion specified by CASE_CTL on array PTR of SIZE
|
||||
characters. Append the result to STK. */
|
||||
static void
|
||||
run_case_conv (enum case_ctl_type case_ctl, char *ptr, idx_t size)
|
||||
{
|
||||
char const *p = ptr, *plim = ptr + size;
|
||||
mbstate_t mbs; mbszero (&mbs);
|
||||
while (p < plim)
|
||||
{
|
||||
mcel_t g = mcel_scan (p, plim);
|
||||
char32_t ch;
|
||||
switch (case_ctl)
|
||||
{
|
||||
case ctl_upcase: case ctl_upcase_next: ch = c32toupper (g.ch); break;
|
||||
case ctl_locase: case ctl_locase_next: ch = c32tolower (g.ch); break;
|
||||
default: ch = g.ch; break;
|
||||
}
|
||||
if (ch == g.ch)
|
||||
obstack_grow (&stk, p, g.len);
|
||||
else
|
||||
{
|
||||
obstack_make_room (&stk, MB_LEN_MAX);
|
||||
mbstate_t ombs; mbszero (&ombs);
|
||||
idx_t outbytes = c32rtomb (obstack_next_free (&stk), ch, &ombs);
|
||||
obstack_blank_fast (&stk, outbytes);
|
||||
}
|
||||
p += g.len;
|
||||
if (case_ctl != ctl_upcase && case_ctl != ctl_locase)
|
||||
break;
|
||||
}
|
||||
|
||||
obstack_grow (&stk, p, plim - p);
|
||||
}
|
||||
|
||||
static void
|
||||
_single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
{
|
||||
regmatch_t *rmp;
|
||||
int rc;
|
||||
size_t nmatches = 0;
|
||||
idx_t nmatches = 0;
|
||||
enum case_ctl_type case_ctl = ctl_stop, /* Current case conversion op */
|
||||
save_ctl = ctl_stop; /* Saved case_ctl for \u and \l */
|
||||
|
||||
/* Reset case conversion after a single-char operation */
|
||||
#define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \
|
||||
|| case_ctl == ctl_locase_next) \
|
||||
{ \
|
||||
case_ctl = save_ctl; \
|
||||
save_ctl = ctl_stop; \
|
||||
}
|
||||
|
||||
rmp = xmalloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
|
||||
regmatch_t *rmp = xinmalloc (tf->regex.re_nsub + 1, sizeof *rmp);
|
||||
|
||||
while (*input)
|
||||
{
|
||||
size_t disp;
|
||||
char *ptr;
|
||||
idx_t disp;
|
||||
|
||||
rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0);
|
||||
|
||||
@@ -489,9 +478,6 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
|
||||
disp = rmp[0].rm_eo;
|
||||
|
||||
if (rmp[0].rm_so)
|
||||
obstack_grow (&stk, input, rmp[0].rm_so);
|
||||
|
||||
nmatches++;
|
||||
if (tf->match_number && nmatches < tf->match_number)
|
||||
{
|
||||
@@ -500,37 +486,36 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rmp[0].rm_so)
|
||||
obstack_grow (&stk, input, rmp[0].rm_so);
|
||||
|
||||
for (segm = tf->repl_head; segm; segm = segm->next)
|
||||
{
|
||||
switch (segm->type)
|
||||
{
|
||||
case segm_literal: /* Literal segment */
|
||||
if (case_ctl == ctl_stop)
|
||||
ptr = segm->v.literal.ptr;
|
||||
else
|
||||
run_case_conv (case_ctl,
|
||||
segm->v.literal.ptr,
|
||||
segm->v.literal.size);
|
||||
case_ctl_reset:
|
||||
/* Reset case conversion after a single-char operation. */
|
||||
if (case_ctl == ctl_upcase_next
|
||||
|| case_ctl == ctl_locase_next)
|
||||
{
|
||||
ptr = run_case_conv (case_ctl,
|
||||
segm->v.literal.ptr,
|
||||
segm->v.literal.size);
|
||||
CASE_CTL_RESET();
|
||||
case_ctl = save_ctl;
|
||||
save_ctl = ctl_stop;
|
||||
}
|
||||
obstack_grow (&stk, ptr, segm->v.literal.size);
|
||||
break;
|
||||
|
||||
case segm_backref: /* Back-reference segment */
|
||||
if (rmp[segm->v.ref].rm_so != -1
|
||||
&& rmp[segm->v.ref].rm_eo != -1)
|
||||
if (0 <= rmp[segm->v.ref].rm_so
|
||||
&& 0 <= rmp[segm->v.ref].rm_eo)
|
||||
{
|
||||
size_t size = rmp[segm->v.ref].rm_eo
|
||||
- rmp[segm->v.ref].rm_so;
|
||||
ptr = input + rmp[segm->v.ref].rm_so;
|
||||
if (case_ctl != ctl_stop)
|
||||
{
|
||||
ptr = run_case_conv (case_ctl, ptr, size);
|
||||
CASE_CTL_RESET();
|
||||
}
|
||||
|
||||
obstack_grow (&stk, ptr, size);
|
||||
idx_t size = (rmp[segm->v.ref].rm_eo
|
||||
- rmp[segm->v.ref].rm_so);
|
||||
run_case_conv (case_ctl,
|
||||
input + rmp[segm->v.ref].rm_so, size);
|
||||
goto case_ctl_reset;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -548,7 +533,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*FALL THROUGH*/
|
||||
FALLTHROUGH;
|
||||
|
||||
case ctl_upcase:
|
||||
case ctl_locase:
|
||||
@@ -577,11 +562,11 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
|
||||
free (rmp);
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
_transform_name_to_obstack (int flags, char *input, char **output)
|
||||
{
|
||||
struct transform *tf;
|
||||
bool alloced = false;
|
||||
bool ok = false;
|
||||
|
||||
if (!stk_init)
|
||||
{
|
||||
@@ -595,36 +580,57 @@ _transform_name_to_obstack (int flags, char *input, char **output)
|
||||
{
|
||||
_single_transform_name_to_obstack (tf, input);
|
||||
input = obstack_finish (&stk);
|
||||
alloced = true;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
obstack_grow0 (&stk, input, strlen (input));
|
||||
input = obstack_finish (&stk);
|
||||
}
|
||||
*output = input;
|
||||
return alloced;
|
||||
}
|
||||
|
||||
/* Transform name *PINPUT of a file or archive member of type TYPE
|
||||
(a single XFORM_* bit). If FUN is not NULL, call this function
|
||||
to further transform the result. Arguments to FUN are the transformed
|
||||
name and type, it's return value is the new transformed name.
|
||||
|
||||
If transformation results in a non-empty string, store the result in
|
||||
*PINPUT and return true. Otherwise, if it results in an empty string,
|
||||
issue a warning, return false and don't modify PINPUT.
|
||||
*/
|
||||
bool
|
||||
transform_name_fp (char **pinput, int flags,
|
||||
char *(*fun)(char *, void *), void *dat)
|
||||
transform_name_fp (char **pinput, int type,
|
||||
char const *(*fun) (char const *, int))
|
||||
{
|
||||
char *str;
|
||||
bool ret = _transform_name_to_obstack (flags, *pinput, &str);
|
||||
if (ret)
|
||||
{
|
||||
assign_string (pinput, fun ? fun (str, dat) : str);
|
||||
obstack_free (&stk, str);
|
||||
}
|
||||
else if (fun)
|
||||
{
|
||||
*pinput = NULL;
|
||||
assign_string (pinput, fun (str, dat));
|
||||
free (str);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
char *str;
|
||||
char const *result;
|
||||
|
||||
_transform_name_to_obstack (type, *pinput, &str);
|
||||
result = (str[0] != 0 && fun) ? fun (str, type) : str;
|
||||
|
||||
if (result[0] == 0)
|
||||
{
|
||||
warnopt (WARN_EMPTY_TRANSFORM, 0,
|
||||
_("%s: transforms to empty name"), quotearg_colon (*pinput));
|
||||
obstack_free (&stk, str);
|
||||
return false;
|
||||
}
|
||||
|
||||
assign_string (pinput, result);
|
||||
obstack_free (&stk, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
transform_name (char **pinput, int type)
|
||||
{
|
||||
return transform_name_fp (pinput, type, NULL, NULL);
|
||||
return transform_name_fp (pinput, type, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
transform_program_p (void)
|
||||
{
|
||||
return transform_head != NULL;
|
||||
}
|
||||
|
||||
168
src/unlink.c
168
src/unlink.c
@@ -1,19 +1,21 @@
|
||||
/* This file is part of GNU tar.
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
/* Unlink files.
|
||||
|
||||
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 3, or (at your option) any later
|
||||
version.
|
||||
Copyright 2009-2025 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 file is part of GNU tar.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
@@ -22,38 +24,51 @@
|
||||
struct deferred_unlink
|
||||
{
|
||||
struct deferred_unlink *next; /* Next unlink in the queue */
|
||||
char *file_name; /* Absolute name of the file to unlink */
|
||||
idx_t dir_idx; /* Directory index in wd */
|
||||
char *file_name; /* Name of the file to unlink, relative
|
||||
to dir_idx */
|
||||
bool is_dir; /* True if file_name is a directory */
|
||||
off_t records_written; /* Number of records written when this
|
||||
entry got added to the queue */
|
||||
};
|
||||
|
||||
static bool
|
||||
is_cwd (struct deferred_unlink const *p)
|
||||
{
|
||||
return p->is_dir && !p->file_name[p->file_name[0] == '.'];
|
||||
}
|
||||
|
||||
/* The unlink queue */
|
||||
static struct deferred_unlink *dunlink_head, *dunlink_tail;
|
||||
|
||||
/* Number of entries in the queue */
|
||||
static size_t dunlink_count;
|
||||
|
||||
/* List of entries available for allocation */
|
||||
static struct deferred_unlink *dunlink_avail;
|
||||
|
||||
/* Delay (number of records written) between adding entry to the
|
||||
list and its actual removal. */
|
||||
size_t deferred_unlink_delay = 0;
|
||||
|
||||
static struct deferred_unlink *
|
||||
dunlink_alloc (void)
|
||||
{
|
||||
struct deferred_unlink *p;
|
||||
if (dunlink_avail)
|
||||
struct deferred_unlink *p = dunlink_avail;
|
||||
if (!p)
|
||||
return xmalloc (sizeof *p);
|
||||
dunlink_avail = p->next;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
dunlink_insert (struct deferred_unlink *anchor, struct deferred_unlink *p)
|
||||
{
|
||||
if (anchor)
|
||||
{
|
||||
p = dunlink_avail;
|
||||
dunlink_avail = p->next;
|
||||
p->next = NULL;
|
||||
p->next = anchor->next;
|
||||
anchor->next = p;
|
||||
}
|
||||
else
|
||||
p = xmalloc (sizeof (*p));
|
||||
return p;
|
||||
{
|
||||
p->next = dunlink_head;
|
||||
dunlink_head = p;
|
||||
}
|
||||
if (!p->next)
|
||||
dunlink_tail = p;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -68,44 +83,59 @@ static void
|
||||
flush_deferred_unlinks (bool force)
|
||||
{
|
||||
struct deferred_unlink *p, *prev = NULL;
|
||||
idx_t saved_chdir = chdir_current;
|
||||
|
||||
for (p = dunlink_head; p; )
|
||||
{
|
||||
struct deferred_unlink *next = p->next;
|
||||
|
||||
if (force
|
||||
|| records_written > p->records_written + deferred_unlink_delay)
|
||||
|| p->records_written < records_written)
|
||||
{
|
||||
chdir_do (p->dir_idx);
|
||||
if (p->is_dir)
|
||||
{
|
||||
if (unlinkat (chdir_fd, p->file_name, AT_REMOVEDIR) != 0)
|
||||
const char *fname;
|
||||
|
||||
if (p->dir_idx && is_cwd (p))
|
||||
{
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
fname = p->file_name;
|
||||
|
||||
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
/* nothing to worry about */
|
||||
break;
|
||||
case EEXIST:
|
||||
/* OpenSolaris >=10 sets EEXIST instead of ENOTEMPTY
|
||||
if trying to remove a non-empty directory */
|
||||
#if defined ENOTEMPTY && ENOTEMPTY != EEXIST
|
||||
case ENOTEMPTY:
|
||||
if (!force)
|
||||
{
|
||||
/* Keep the record in list, in the hope we'll
|
||||
be able to remove it later */
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
}
|
||||
/* fall through */
|
||||
#endif
|
||||
/* Keep the record in list, in the hope we'll
|
||||
be able to remove it later */
|
||||
prev = p;
|
||||
p = next;
|
||||
continue;
|
||||
|
||||
default:
|
||||
rmdir_error (p->file_name);
|
||||
rmdir_error (fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlinkat (chdir_fd, p->file_name, 0) != 0 && errno != ENOENT)
|
||||
if (unlinkat (chdir_fd, p->file_name, 0) < 0 && errno != ENOENT)
|
||||
unlink_error (p->file_name);
|
||||
}
|
||||
dunlink_reclaim (p);
|
||||
dunlink_count--;
|
||||
p = next;
|
||||
if (prev)
|
||||
prev->next = p;
|
||||
@@ -120,12 +150,41 @@ flush_deferred_unlinks (bool force)
|
||||
}
|
||||
if (!dunlink_head)
|
||||
dunlink_tail = NULL;
|
||||
else if (force)
|
||||
{
|
||||
for (p = dunlink_head; p; )
|
||||
{
|
||||
struct deferred_unlink *next = p->next;
|
||||
const char *fname;
|
||||
|
||||
chdir_do (p->dir_idx);
|
||||
if (p->dir_idx && is_cwd (p))
|
||||
{
|
||||
fname = tar_dirname ();
|
||||
chdir_do (p->dir_idx - 1);
|
||||
}
|
||||
else
|
||||
fname = p->file_name;
|
||||
|
||||
if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
rmdir_error (fname);
|
||||
}
|
||||
dunlink_reclaim (p);
|
||||
p = next;
|
||||
}
|
||||
dunlink_head = dunlink_tail = NULL;
|
||||
}
|
||||
|
||||
chdir_do (saved_chdir);
|
||||
}
|
||||
|
||||
void
|
||||
finish_deferred_unlinks ()
|
||||
finish_deferred_unlinks (void)
|
||||
{
|
||||
flush_deferred_unlinks (true);
|
||||
|
||||
while (dunlink_avail)
|
||||
{
|
||||
struct deferred_unlink *next = dunlink_avail->next;
|
||||
@@ -140,19 +199,28 @@ queue_deferred_unlink (const char *name, bool is_dir)
|
||||
struct deferred_unlink *p;
|
||||
|
||||
if (dunlink_head
|
||||
&& records_written > dunlink_head->records_written + deferred_unlink_delay)
|
||||
&& records_written > dunlink_head->records_written)
|
||||
flush_deferred_unlinks (false);
|
||||
|
||||
p = dunlink_alloc ();
|
||||
p->next = NULL;
|
||||
p->file_name = normalize_filename (name);
|
||||
p->dir_idx = chdir_current;
|
||||
p->file_name = xstrdup (name);
|
||||
normalize_filename_x (p->file_name);
|
||||
p->is_dir = is_dir;
|
||||
p->records_written = records_written;
|
||||
|
||||
if (dunlink_tail)
|
||||
dunlink_tail->next = p;
|
||||
if (is_cwd (p))
|
||||
{
|
||||
struct deferred_unlink *q, *prev;
|
||||
for (q = dunlink_head, prev = NULL; q; prev = q, q = q->next)
|
||||
if (is_cwd (q) && q->dir_idx < p->dir_idx)
|
||||
break;
|
||||
if (q)
|
||||
dunlink_insert (prev, p);
|
||||
else
|
||||
dunlink_insert (dunlink_tail, p);
|
||||
}
|
||||
else
|
||||
dunlink_head = p;
|
||||
dunlink_tail = p;
|
||||
dunlink_count++;
|
||||
dunlink_insert (dunlink_tail, p);
|
||||
}
|
||||
|
||||
159
src/update.c
159
src/update.c
@@ -1,21 +1,21 @@
|
||||
/* Update a tar archive.
|
||||
|
||||
Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003,
|
||||
2004, 2005, 2007, 2010 Free Software Foundation, Inc.
|
||||
Copyright 1988-2025 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 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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 3 of the License, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Implement the 'r', 'u' and 'A' options for tar. 'A' means that the
|
||||
file names are tar files, and they should simply be appended to the end
|
||||
@@ -26,10 +26,6 @@
|
||||
#include <quotearg.h>
|
||||
#include "common.h"
|
||||
|
||||
/* FIXME: This module should not directly handle the following variable,
|
||||
instead, this should be done in buffer.c only. */
|
||||
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).
|
||||
@@ -42,13 +38,14 @@ bool time_to_start_writing;
|
||||
first part of the record. */
|
||||
char *output_start;
|
||||
|
||||
static bool acting_as_filter;
|
||||
|
||||
/* Catenate file FILE_NAME to the archive without creating a header for it.
|
||||
It had better be a tar file or the archive is screwed. */
|
||||
static void
|
||||
append_file (char *file_name)
|
||||
{
|
||||
int handle = openat (chdir_fd, file_name, O_RDONLY | O_BINARY);
|
||||
struct stat stat_data;
|
||||
|
||||
if (handle < 0)
|
||||
{
|
||||
@@ -56,49 +53,44 @@ append_file (char *file_name)
|
||||
return;
|
||||
}
|
||||
|
||||
if (fstat (handle, &stat_data) != 0)
|
||||
stat_error (file_name);
|
||||
else
|
||||
while (true)
|
||||
{
|
||||
off_t bytes_left = stat_data.st_size;
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
union block *start = find_next_block ();
|
||||
size_t buffer_size = available_space_after (start);
|
||||
size_t status;
|
||||
char buf[UINTMAX_STRSIZE_BOUND];
|
||||
|
||||
if (bytes_left < buffer_size)
|
||||
{
|
||||
buffer_size = bytes_left;
|
||||
status = buffer_size % BLOCKSIZE;
|
||||
if (status)
|
||||
memset (start->buffer + bytes_left, 0, BLOCKSIZE - status);
|
||||
}
|
||||
|
||||
status = safe_read (handle, start->buffer, buffer_size);
|
||||
if (status == SAFE_READ_ERROR)
|
||||
read_fatal_details (file_name, stat_data.st_size - bytes_left,
|
||||
buffer_size);
|
||||
if (status == 0)
|
||||
FATAL_ERROR ((0, 0,
|
||||
ngettext ("%s: File shrank by %s byte",
|
||||
"%s: File shrank by %s bytes",
|
||||
bytes_left),
|
||||
quotearg_colon (file_name),
|
||||
STRINGIFY_BIGINT (bytes_left, buf)));
|
||||
|
||||
bytes_left -= status;
|
||||
|
||||
set_next_block_after (start + (status - 1) / BLOCKSIZE);
|
||||
}
|
||||
union block *start = find_next_block ();
|
||||
idx_t bufsize = available_space_after (start);
|
||||
idx_t status = full_read (handle, charptr (start), bufsize);
|
||||
if (status < bufsize && errno)
|
||||
read_fatal (file_name);
|
||||
if (status == 0)
|
||||
break;
|
||||
idx_t rem = status % BLOCKSIZE;
|
||||
if (rem)
|
||||
memset (charptr (start) + (status - rem), 0, BLOCKSIZE - rem);
|
||||
set_next_block_after (charptr (start) + status - 1);
|
||||
}
|
||||
|
||||
if (close (handle) != 0)
|
||||
if (close (handle) < 0)
|
||||
close_error (file_name);
|
||||
}
|
||||
|
||||
/* If NAME is not a pattern, remove it from the namelist. Otherwise,
|
||||
remove the FILE_NAME that matched it. Take care to look for exact
|
||||
match when removing it. */
|
||||
static void
|
||||
remove_exact_name (struct name *name, char const *file_name)
|
||||
{
|
||||
if (name->is_wildcard)
|
||||
{
|
||||
struct name *match = name_scan (file_name, true);
|
||||
name->found_count++;
|
||||
if (match)
|
||||
name = match;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
remname (name);
|
||||
}
|
||||
|
||||
/* Implement the 'r' (add files to end of archive), and 'u' (add files
|
||||
to end of archive if they aren't there, or are more up to date than
|
||||
the version in the archive) commands. */
|
||||
@@ -110,7 +102,8 @@ update_archive (void)
|
||||
|
||||
name_gather ();
|
||||
open_archive (ACCESS_UPDATE);
|
||||
buffer_write_global_xheader ();
|
||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||
xheader_forbid_global ();
|
||||
|
||||
while (!found_end)
|
||||
{
|
||||
@@ -129,11 +122,13 @@ update_archive (void)
|
||||
struct name *name;
|
||||
|
||||
decode_header (current_header, ¤t_stat_info,
|
||||
¤t_format, 0);
|
||||
¤t_format, false);
|
||||
transform_stat_info (current_header->header.typeflag,
|
||||
¤t_stat_info);
|
||||
archive_format = current_format;
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
&& (name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
&& (name = name_scan (current_stat_info.file_name, false)) != NULL)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
@@ -142,42 +137,36 @@ update_archive (void)
|
||||
{
|
||||
if (S_ISDIR (s.st_mode))
|
||||
{
|
||||
char *p, *dirp;
|
||||
DIR *stream;
|
||||
int fd = openat (chdir_fd, name->name,
|
||||
open_read_flags | O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
open_error (name->name);
|
||||
else if (! ((stream = fdopendir (fd))
|
||||
&& (dirp = streamsavedir (stream))))
|
||||
savedir_error (name->name);
|
||||
else
|
||||
char *p;
|
||||
char *dirp = tar_savedir (current_stat_info.file_name,
|
||||
true);
|
||||
if (dirp)
|
||||
{
|
||||
namebuf_t nbuf = namebuf_create (name->name);
|
||||
namebuf_t nbuf = namebuf_create (current_stat_info.file_name);
|
||||
|
||||
for (p = dirp; *p; p += strlen (p) + 1)
|
||||
addname (namebuf_name (nbuf, p),
|
||||
0, false, NULL);
|
||||
name->change_dir, false, NULL);
|
||||
|
||||
namebuf_free (nbuf);
|
||||
free (dirp);
|
||||
|
||||
remname (name);
|
||||
remove_exact_name (name, current_stat_info.file_name);
|
||||
}
|
||||
|
||||
if (stream
|
||||
? closedir (stream) != 0
|
||||
: 0 <= fd && close (fd) != 0)
|
||||
savedir_error (name->name);
|
||||
}
|
||||
else if (tar_timespec_cmp (get_stat_mtime (&s),
|
||||
current_stat_info.mtime)
|
||||
<= 0)
|
||||
remname (name);
|
||||
{
|
||||
remove_exact_name (name, current_stat_info.file_name);
|
||||
}
|
||||
else if (name->is_wildcard)
|
||||
addname (current_stat_info.file_name,
|
||||
name->change_dir, false, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
skip_member ();
|
||||
skim_member (acting_as_filter);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -195,14 +184,12 @@ update_archive (void)
|
||||
switch (previous_status)
|
||||
{
|
||||
case HEADER_STILL_UNREAD:
|
||||
WARN ((0, 0, _("This does not look like a tar archive")));
|
||||
/* Fall through. */
|
||||
|
||||
paxwarn (0, _("This does not look like a tar archive"));
|
||||
FALLTHROUGH;
|
||||
case HEADER_SUCCESS:
|
||||
case HEADER_ZERO_BLOCK:
|
||||
ERROR ((0, 0, _("Skipping to next header")));
|
||||
/* Fall through. */
|
||||
|
||||
paxerror (0, _("Skipping to next header"));
|
||||
FALLTHROUGH;
|
||||
case HEADER_FAILURE:
|
||||
break;
|
||||
|
||||
@@ -219,14 +206,14 @@ update_archive (void)
|
||||
|
||||
reset_eof ();
|
||||
time_to_start_writing = true;
|
||||
output_start = current_block->buffer;
|
||||
output_start = charptr (current_block);
|
||||
|
||||
{
|
||||
struct name const *p;
|
||||
while ((p = name_from_list ()) != NULL)
|
||||
{
|
||||
char *file_name = p->name;
|
||||
if (excluded_name (file_name))
|
||||
if (excluded_name (file_name, NULL))
|
||||
continue;
|
||||
if (interactive_option && !confirm ("add", file_name))
|
||||
continue;
|
||||
|
||||
71
src/utf8.c
71
src/utf8.c
@@ -1,20 +1,21 @@
|
||||
/* Charset handling for GNU tar.
|
||||
|
||||
Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
|
||||
Copyright 2004-2025 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 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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 3 of the License, 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <quotearg.h>
|
||||
@@ -34,11 +35,15 @@
|
||||
# define iconv_open(tocode, fromcode) ((iconv_t) -1)
|
||||
|
||||
# undef iconv
|
||||
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) ((size_t) 0)
|
||||
# define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) \
|
||||
(errno = ENOSYS, SIZE_MAX)
|
||||
|
||||
# undef iconv_close
|
||||
# define iconv_close(cd) 0
|
||||
|
||||
# undef iconv_t
|
||||
# define iconv_t int
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -49,24 +54,23 @@ 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 (conv_desc[to_utf] == (iconv_t) -1)
|
||||
{
|
||||
if (to_utf)
|
||||
conv_desc[(int) to_utf] = iconv_open ("UTF-8", locale_charset ());
|
||||
conv_desc[to_utf] = iconv_open ("UTF-8", locale_charset ());
|
||||
else
|
||||
conv_desc[(int) to_utf] = iconv_open (locale_charset (), "UTF-8");
|
||||
conv_desc[to_utf] = iconv_open (locale_charset (), "UTF-8");
|
||||
}
|
||||
return conv_desc[(int) to_utf];
|
||||
return conv_desc[to_utf];
|
||||
}
|
||||
|
||||
bool
|
||||
utf8_convert (bool to_utf, char const *input, char **output)
|
||||
{
|
||||
char ICONV_CONST *ib;
|
||||
char *ob;
|
||||
char *ob, *ret;
|
||||
size_t inlen;
|
||||
size_t outlen;
|
||||
size_t rc;
|
||||
iconv_t cd = utf8_init (to_utf);
|
||||
|
||||
if (cd == 0)
|
||||
@@ -74,16 +78,35 @@ utf8_convert (bool to_utf, char const *input, char **output)
|
||||
*output = xstrdup (input);
|
||||
return true;
|
||||
}
|
||||
else if (cd == (iconv_t)-1)
|
||||
else if (cd == (iconv_t) -1)
|
||||
return false;
|
||||
|
||||
inlen = strlen (input) + 1;
|
||||
outlen = inlen * MB_LEN_MAX + 1;
|
||||
ob = *output = xmalloc (outlen);
|
||||
bool overflow = ckd_mul (&outlen, inlen, MB_LEN_MAX);
|
||||
overflow |= ckd_add (&outlen, outlen, 1);
|
||||
if (overflow)
|
||||
xalloc_die ();
|
||||
ob = ret = xmalloc (outlen);
|
||||
ib = (char ICONV_CONST *) input;
|
||||
rc = iconv (cd, &ib, &inlen, &ob, &outlen);
|
||||
/* According to POSIX, "if iconv() encounters a character in the input
|
||||
buffer that is valid, but for which an identical character does not
|
||||
exist in the target codeset, iconv() shall perform an
|
||||
implementation-defined conversion on this character." It will "update
|
||||
the variables pointed to by the arguments to reflect the extent of the
|
||||
conversion and return the number of non-identical conversions performed".
|
||||
On error, it returns SIZE_MAX.
|
||||
In other words, non-zero return always indicates failure, either because
|
||||
the input was not fully converted, or because it was converted in a
|
||||
non-reversible way.
|
||||
*/
|
||||
if (iconv (cd, &ib, &inlen, &ob, &outlen) != 0)
|
||||
{
|
||||
free (ret);
|
||||
return false;
|
||||
}
|
||||
*ob = 0;
|
||||
return rc != -1;
|
||||
*output = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
/* This file is part of GNU tar.
|
||||
/* Warnings for GNU tar.
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
Copyright 2009-2025 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 3, or (at your option) any later
|
||||
version.
|
||||
This file is part of GNU tar.
|
||||
|
||||
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.
|
||||
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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
|
||||
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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <system.h>
|
||||
#include <argmatch.h>
|
||||
@@ -41,6 +43,14 @@ static char const *const warning_args[] = {
|
||||
"unknown-cast",
|
||||
"unknown-keyword",
|
||||
"xdev",
|
||||
"decompress-program",
|
||||
"existing-file",
|
||||
"xattr-write",
|
||||
"record-size",
|
||||
"failed-read",
|
||||
"missing-zero-blocks",
|
||||
"verbose",
|
||||
"empty-transform",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -64,17 +74,25 @@ static int warning_types[] = {
|
||||
WARN_TIMESTAMP,
|
||||
WARN_UNKNOWN_CAST,
|
||||
WARN_UNKNOWN_KEYWORD,
|
||||
WARN_XDEV
|
||||
WARN_XDEV,
|
||||
WARN_DECOMPRESS_PROGRAM,
|
||||
WARN_EXISTING_FILE,
|
||||
WARN_XATTR_WRITE,
|
||||
WARN_RECORD_SIZE,
|
||||
WARN_FAILED_READ,
|
||||
WARN_MISSING_ZERO_BLOCKS,
|
||||
WARN_VERBOSE_WARNINGS,
|
||||
WARN_EMPTY_TRANSFORM
|
||||
};
|
||||
|
||||
ARGMATCH_VERIFY (warning_args, warning_types);
|
||||
|
||||
int warning_option = WARN_ALL;
|
||||
int warning_option = WARN_ALL & ~(WARN_VERBOSE_WARNINGS|WARN_MISSING_ZERO_BLOCKS);
|
||||
|
||||
void
|
||||
set_warning_option (const char *arg)
|
||||
{
|
||||
int negate = 0;
|
||||
bool negate = false;
|
||||
int option;
|
||||
|
||||
if (strcmp (arg, "none") == 0)
|
||||
@@ -84,7 +102,7 @@ set_warning_option (const char *arg)
|
||||
}
|
||||
if (strlen (arg) > 2 && memcmp (arg, "no-", 3) == 0)
|
||||
{
|
||||
negate = 1;
|
||||
negate = true;
|
||||
arg += 3;
|
||||
}
|
||||
|
||||
@@ -95,3 +113,17 @@ set_warning_option (const char *arg)
|
||||
else
|
||||
warning_option |= option;
|
||||
}
|
||||
|
||||
void
|
||||
warnopt (int opt, int errnum, char const *format, ...)
|
||||
{
|
||||
if (warning_enabled (opt))
|
||||
{
|
||||
if (error_hook)
|
||||
error_hook ();
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
verror (0, errnum, format, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
}
|
||||
|
||||
833
src/xattrs.c
Normal file
833
src/xattrs.c
Normal file
@@ -0,0 +1,833 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by James Antill, on 2006-07-27. */
|
||||
|
||||
#include <config.h>
|
||||
#include <system.h>
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "xattr-at.h"
|
||||
#include "selinux-at.h"
|
||||
|
||||
static char const XATTRS_PREFIX[] = "SCHILY.xattr.";
|
||||
enum { XATTRS_PREFIX_LEN = sizeof XATTRS_PREFIX - 1 };
|
||||
|
||||
void
|
||||
xheader_xattr_init (struct tar_stat_info *st)
|
||||
{
|
||||
xattr_map_init (&st->xattr_map);
|
||||
|
||||
st->acls_a_ptr = NULL;
|
||||
st->acls_a_len = 0;
|
||||
st->acls_d_ptr = NULL;
|
||||
st->acls_d_len = 0;
|
||||
st->cntx_name = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_init (struct xattr_map *map)
|
||||
{
|
||||
memset (map, 0, sizeof *map);
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_free (struct xattr_map *xattr_map)
|
||||
{
|
||||
for (idx_t i = 0; i < xattr_map->xm_size; i++)
|
||||
{
|
||||
free (xattr_map->xm_map[i].xkey);
|
||||
free (xattr_map->xm_map[i].xval_ptr);
|
||||
}
|
||||
free (xattr_map->xm_map);
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_add (struct xattr_map *map,
|
||||
const char *key, const char *val, idx_t len)
|
||||
{
|
||||
if (map->xm_size == map->xm_max)
|
||||
map->xm_map = xpalloc (map->xm_map, &map->xm_max, 1, -1,
|
||||
sizeof *map->xm_map);
|
||||
struct xattr_array *p = &map->xm_map[map->xm_size];
|
||||
p->xkey = xstrdup (key);
|
||||
p->xval_ptr = ximemdup (val, len + 1);
|
||||
p->xval_len = len;
|
||||
map->xm_size++;
|
||||
}
|
||||
|
||||
static void
|
||||
xheader_xattr_add (struct tar_stat_info *st,
|
||||
const char *key, const char *val, idx_t len)
|
||||
{
|
||||
idx_t klen = strlen (key);
|
||||
char *xkey = xmalloc (XATTRS_PREFIX_LEN + klen + 1);
|
||||
char *tmp = xkey;
|
||||
|
||||
tmp = stpcpy (tmp, XATTRS_PREFIX);
|
||||
stpcpy (tmp, key);
|
||||
|
||||
xattr_map_add (&st->xattr_map, xkey, val, len);
|
||||
|
||||
free (xkey);
|
||||
}
|
||||
|
||||
void
|
||||
xattr_map_copy (struct xattr_map *dst, const struct xattr_map *src)
|
||||
{
|
||||
for (idx_t i = 0; i < src->xm_size; i++)
|
||||
xattr_map_add (dst, src->xm_map[i].xkey,
|
||||
src->xm_map[i].xval_ptr,
|
||||
src->xm_map[i].xval_len);
|
||||
}
|
||||
|
||||
struct xattrs_mask_map
|
||||
{
|
||||
const char **masks;
|
||||
idx_t size;
|
||||
idx_t used;
|
||||
};
|
||||
|
||||
/* list of fnmatch patterns */
|
||||
static struct
|
||||
{
|
||||
/* lists of fnmatch patterns */
|
||||
struct xattrs_mask_map incl;
|
||||
struct xattrs_mask_map excl;
|
||||
} xattrs_setup;
|
||||
|
||||
/* disable posix acls when problem found in gnulib script m4/acl.m4 */
|
||||
#if ! USE_ACL
|
||||
# undef HAVE_POSIX_ACLS
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACLS
|
||||
# include "acl.h"
|
||||
# include <sys/acl.h>
|
||||
# ifdef HAVE_ACL_LIBACL_H
|
||||
# /* needed for numeric-owner support */
|
||||
# include <acl/libacl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_ACLS
|
||||
|
||||
/* acl-at wrappers, TODO: move to gnulib in future? */
|
||||
static acl_t acl_get_file_at (int, const char *, acl_type_t);
|
||||
static int acl_set_file_at (int, const char *, acl_type_t, acl_t);
|
||||
static int file_has_acl_at (int, char const *, struct stat const *);
|
||||
static int acl_delete_def_file_at (int, char const *);
|
||||
|
||||
/* acl_get_file_at */
|
||||
#define AT_FUNC_NAME acl_get_file_at
|
||||
#define AT_FUNC_RESULT acl_t
|
||||
#define AT_FUNC_FAIL (acl_t)NULL
|
||||
#define AT_FUNC_F1 acl_get_file
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type
|
||||
#define AT_FUNC_POST_FILE_ARGS , type
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_RESULT
|
||||
#undef AT_FUNC_FAIL
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* acl_set_file_at */
|
||||
#define AT_FUNC_NAME acl_set_file_at
|
||||
#define AT_FUNC_F1 acl_set_file
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type, acl_t acl
|
||||
#define AT_FUNC_POST_FILE_ARGS , type, acl
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* acl_delete_def_file_at */
|
||||
#define AT_FUNC_NAME acl_delete_def_file_at
|
||||
#define AT_FUNC_F1 acl_delete_def_file
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#define AT_FUNC_POST_FILE_ARGS
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* gnulib file_has_acl_at */
|
||||
#define AT_FUNC_NAME file_has_acl_at
|
||||
#define AT_FUNC_F1 file_has_acl
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat const *st
|
||||
#define AT_FUNC_POST_FILE_ARGS , st
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
/* convert unix permissions into an ACL ... needed due to "default" ACLs */
|
||||
static acl_t
|
||||
perms2acl (int perms)
|
||||
{
|
||||
char val[] = "user::---,group::---,other::---";
|
||||
/* 0123456789 123456789 123456789 123456789 */
|
||||
|
||||
/* user */
|
||||
if (perms & 0400)
|
||||
val[6] = 'r';
|
||||
if (perms & 0200)
|
||||
val[7] = 'w';
|
||||
if (perms & 0100)
|
||||
val[8] = 'x';
|
||||
|
||||
/* group */
|
||||
if (perms & 0040)
|
||||
val[17] = 'r';
|
||||
if (perms & 0020)
|
||||
val[18] = 'w';
|
||||
if (perms & 0010)
|
||||
val[19] = 'x';
|
||||
|
||||
/* other */
|
||||
if (perms & 0004)
|
||||
val[28] = 'r';
|
||||
if (perms & 0002)
|
||||
val[29] = 'w';
|
||||
if (perms & 0001)
|
||||
val[30] = 'x';
|
||||
|
||||
return acl_from_text (val);
|
||||
}
|
||||
|
||||
static char *
|
||||
skip_to_ext_fields (char *ptr)
|
||||
{
|
||||
/* skip tag name (user/group/default/mask) */
|
||||
ptr += strcspn (ptr, ":,\n");
|
||||
|
||||
if (*ptr != ':')
|
||||
return ptr;
|
||||
++ptr;
|
||||
|
||||
ptr += strcspn (ptr, ":,\n"); /* skip user/group name */
|
||||
|
||||
if (*ptr != ':')
|
||||
return ptr;
|
||||
++ptr;
|
||||
|
||||
ptr += strcspn (ptr, ":,\n"); /* skip perms */
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* The POSIX draft allows extra fields after the three main ones. Star
|
||||
uses this to add a fourth field for user/group which is the numeric ID.
|
||||
This function removes such extra fields by overwriting them with the
|
||||
characters that follow. */
|
||||
static char *
|
||||
fixup_extra_acl_fields (char *ptr)
|
||||
{
|
||||
char *src = ptr;
|
||||
char *dst = ptr;
|
||||
|
||||
while (*src)
|
||||
{
|
||||
const char *old = src;
|
||||
idx_t len = 0;
|
||||
|
||||
src = skip_to_ext_fields (src);
|
||||
len = src - old;
|
||||
if (old != dst)
|
||||
memmove (dst, old, len);
|
||||
dst += len;
|
||||
|
||||
if (*src == ':') /* We have extra fields, skip them all */
|
||||
src += strcspn (src, "\n,");
|
||||
|
||||
if ((*src == '\n') || (*src == ','))
|
||||
*dst++ = *src++; /* also done when dst == src, but that's ok */
|
||||
}
|
||||
if (src != dst)
|
||||
*dst = 0;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Set the "system.posix_acl_access/system.posix_acl_default" extended
|
||||
attribute. Called only when acls_option > 0. */
|
||||
static void
|
||||
xattrs__acls_set (struct tar_stat_info const *st,
|
||||
char const *file_name, acl_type_t type,
|
||||
char *ptr, bool def)
|
||||
{
|
||||
acl_t acl;
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
ptr = fixup_extra_acl_fields (ptr);
|
||||
acl = acl_from_text (ptr);
|
||||
}
|
||||
else if (def)
|
||||
{
|
||||
/* No "default" IEEE 1003.1e ACL set for directory. At this moment,
|
||||
FILE_NAME may already have inherited default acls from parent
|
||||
directory; clean them up. */
|
||||
if (acl_delete_def_file_at (chdir_fd, file_name) < 0)
|
||||
warnopt (WARN_XATTR_WRITE, errno,
|
||||
_("acl_delete_def_file_at: Cannot drop default POSIX ACLs "
|
||||
"for file '%s'"),
|
||||
file_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
acl = perms2acl (st->stat.st_mode);
|
||||
|
||||
if (!acl)
|
||||
{
|
||||
call_arg_warn ("acl_from_text", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (acl_set_file_at (chdir_fd, file_name, type, acl) < 0)
|
||||
/* warn even if filesystem does not support acls */
|
||||
warnopt (WARN_XATTR_WRITE, errno,
|
||||
_ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"),
|
||||
file_name);
|
||||
|
||||
acl_free (acl);
|
||||
}
|
||||
|
||||
/* Cleanup textual representation of the ACL in VAL by eliminating tab
|
||||
characters and comments */
|
||||
static void
|
||||
xattrs_acls_cleanup (char *val, idx_t *plen)
|
||||
{
|
||||
char *p, *q;
|
||||
|
||||
p = q = val + strcspn (val, "#\t");
|
||||
while (*q)
|
||||
{
|
||||
if (*q == '\t')
|
||||
q++;
|
||||
else if (*q == '#')
|
||||
{
|
||||
while (*q != '\n')
|
||||
q++;
|
||||
}
|
||||
else
|
||||
*p++ = *q++;
|
||||
}
|
||||
*plen = p - val;
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
acls_get_text (int parentfd, const char *file_name, acl_type_t type,
|
||||
char **ret_ptr, idx_t *ret_len)
|
||||
{
|
||||
char *val = NULL;
|
||||
acl_t acl;
|
||||
|
||||
if (!(acl = acl_get_file_at (parentfd, file_name, type)))
|
||||
{
|
||||
if (errno != ENOTSUP)
|
||||
call_arg_warn ("acl_get_file_at", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numeric_owner_option)
|
||||
{
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
val = acl_to_any_text (acl, NULL, '\n',
|
||||
TEXT_SOME_EFFECTIVE | TEXT_NUMERIC_IDS);
|
||||
#else
|
||||
static bool warned;
|
||||
if (!warned)
|
||||
{
|
||||
warned = true;
|
||||
paxwarn (0, _("--numeric-owner is ignored for ACLs:"
|
||||
" libacl is not available"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
val = acl_to_text (acl, NULL);
|
||||
acl_free (acl);
|
||||
|
||||
if (!val)
|
||||
{
|
||||
call_arg_warn ("acl_to_text", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
*ret_ptr = xstrdup (val);
|
||||
xattrs_acls_cleanup (*ret_ptr, ret_len);
|
||||
acl_free (val);
|
||||
}
|
||||
|
||||
static void
|
||||
xattrs__acls_get_a (int parentfd, const char *file_name,
|
||||
char **ret_ptr, idx_t *ret_len)
|
||||
{
|
||||
acls_get_text (parentfd, file_name, ACL_TYPE_ACCESS, ret_ptr, ret_len);
|
||||
}
|
||||
|
||||
/* "system.posix_acl_default" */
|
||||
static void
|
||||
xattrs__acls_get_d (int parentfd, char const *file_name,
|
||||
char **ret_ptr, idx_t *ret_len)
|
||||
{
|
||||
acls_get_text (parentfd, file_name, ACL_TYPE_DEFAULT, ret_ptr, ret_len);
|
||||
}
|
||||
#endif /* HAVE_POSIX_ACLS */
|
||||
|
||||
static void
|
||||
acls_one_line (const char *prefix, char delim,
|
||||
const char *aclstring, idx_t len)
|
||||
{
|
||||
/* support both long and short text representation of posix acls */
|
||||
struct obstack stk;
|
||||
idx_t pref_len = strlen (prefix);
|
||||
const char *oldstring = aclstring;
|
||||
idx_t pos = 0;
|
||||
|
||||
if (!aclstring || !len)
|
||||
return;
|
||||
|
||||
obstack_init (&stk);
|
||||
while (pos <= len)
|
||||
{
|
||||
idx_t move = strcspn (aclstring, ",\n");
|
||||
if (!move)
|
||||
break;
|
||||
|
||||
if (oldstring != aclstring)
|
||||
obstack_1grow (&stk, delim);
|
||||
|
||||
obstack_grow (&stk, prefix, pref_len);
|
||||
obstack_grow (&stk, aclstring, move);
|
||||
|
||||
pos += move + 1;
|
||||
aclstring += move + 1;
|
||||
}
|
||||
|
||||
obstack_1grow (&stk, '\0');
|
||||
|
||||
fputs (obstack_finish (&stk), stdlis);
|
||||
|
||||
obstack_free (&stk, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_acls_get (MAYBE_UNUSED int parentfd, MAYBE_UNUSED char const *file_name,
|
||||
MAYBE_UNUSED struct tar_stat_info *st,
|
||||
MAYBE_UNUSED bool xisfile)
|
||||
{
|
||||
if (acls_option > 0)
|
||||
{
|
||||
#ifndef HAVE_POSIX_ACLS
|
||||
static bool done;
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
paxwarn (0, _("POSIX ACL support is not available"));
|
||||
}
|
||||
#else
|
||||
int err = file_has_acl_at (parentfd, file_name, &st->stat);
|
||||
if (err == 0)
|
||||
return;
|
||||
if (err < 0)
|
||||
{
|
||||
call_arg_warn ("file_has_acl_at", file_name);
|
||||
return;
|
||||
}
|
||||
|
||||
xattrs__acls_get_a (parentfd, file_name,
|
||||
&st->acls_a_ptr, &st->acls_a_len);
|
||||
if (!xisfile)
|
||||
xattrs__acls_get_d (parentfd, file_name,
|
||||
&st->acls_d_ptr, &st->acls_d_len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_acls_set (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
MAYBE_UNUSED char const *file_name, char typeflag)
|
||||
{
|
||||
if (acls_option > 0 && typeflag != SYMTYPE)
|
||||
{
|
||||
#ifndef HAVE_POSIX_ACLS
|
||||
static bool done;
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
paxwarn (0, _("POSIX ACL support is not available"));
|
||||
}
|
||||
#else
|
||||
xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
|
||||
st->acls_a_ptr, false);
|
||||
if (typeflag == DIRTYPE || typeflag == GNUTYPE_DUMPDIR)
|
||||
xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
|
||||
st->acls_d_ptr, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mask_map_realloc (struct xattrs_mask_map *map)
|
||||
{
|
||||
if (map->used == map->size)
|
||||
map->masks = xpalloc (map->masks, &map->size, 1, -1, sizeof *map->masks);
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_mask_add (const char *mask, bool incl)
|
||||
{
|
||||
struct xattrs_mask_map *mask_map =
|
||||
incl ? &xattrs_setup.incl : &xattrs_setup.excl;
|
||||
/* ensure there is enough space */
|
||||
mask_map_realloc (mask_map);
|
||||
/* just assign pointers -- we silently expect that pointer "mask" is valid
|
||||
through the whole program (pointer to argv array) */
|
||||
mask_map->masks[mask_map->used++] = mask;
|
||||
}
|
||||
|
||||
static bool xattrs_masked_out (const char *kw, bool archiving);
|
||||
|
||||
/* get xattrs from file given by FILE_NAME or FD (when non-zero)
|
||||
xattrs are checked against the user supplied include/exclude mask
|
||||
if no mask is given this includes all the user.*, security.*, system.*,
|
||||
etc. available domains */
|
||||
void
|
||||
xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd)
|
||||
{
|
||||
if (xattrs_option)
|
||||
{
|
||||
#ifndef HAVE_XATTRS
|
||||
static bool done;
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
paxwarn (0, _("XATTR support is not available"));
|
||||
}
|
||||
#else
|
||||
static idx_t xsz = 1024 / 2 * 3;
|
||||
static char *xatrs = NULL;
|
||||
ssize_t xret;
|
||||
|
||||
while (!xatrs
|
||||
|| (((xret = (fd == 0
|
||||
? listxattrat (parentfd, file_name, xatrs, xsz)
|
||||
: flistxattr (fd, xatrs, xsz)))
|
||||
< 0)
|
||||
&& errno == ERANGE))
|
||||
{
|
||||
xatrs = xpalloc (xatrs, &xsz, 1, -1, sizeof *xatrs);
|
||||
}
|
||||
|
||||
if (xret < 0)
|
||||
call_arg_warn ((fd == 0) ? "llistxattrat" : "flistxattr", file_name);
|
||||
else
|
||||
{
|
||||
const char *attr = xatrs;
|
||||
static idx_t asz = 1024 / 2 * 3;
|
||||
static char *val = NULL;
|
||||
|
||||
while (xret > 0)
|
||||
{
|
||||
idx_t len = strlen (attr);
|
||||
ssize_t aret = 0;
|
||||
|
||||
while (!val
|
||||
|| (((aret = (fd == 0
|
||||
? lgetxattrat (parentfd, file_name, attr,
|
||||
val, asz)
|
||||
: fgetxattr (fd, attr, val, asz)))
|
||||
< 0)
|
||||
&& errno == ERANGE))
|
||||
{
|
||||
val = xpalloc (val, &asz, 1, -1, sizeof *val);
|
||||
}
|
||||
|
||||
if (0 <= aret)
|
||||
{
|
||||
if (!xattrs_masked_out (attr, true))
|
||||
xheader_xattr_add (st, attr, val, aret);
|
||||
}
|
||||
else if (errno != ENOATTR)
|
||||
call_arg_warn ((fd == 0) ? "lgetxattrat"
|
||||
: "fgetxattr", file_name);
|
||||
|
||||
attr += len + 1;
|
||||
xret -= len + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_XATTRS
|
||||
static void
|
||||
xattrs__fd_set (char const *file_name, char typeflag,
|
||||
const char *attr, const char *ptr, idx_t len)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
const char *sysname = "setxattrat";
|
||||
int ret;
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
ret = setxattrat (chdir_fd, file_name, attr, ptr, len, 0);
|
||||
else
|
||||
{
|
||||
sysname = "lsetxattr";
|
||||
ret = lsetxattrat (chdir_fd, file_name, attr, ptr, len, 0);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
warnopt (WARN_XATTR_WRITE, errno,
|
||||
_("%s: Cannot set '%s' extended attribute for file '%s'"),
|
||||
sysname, attr, file_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* lgetfileconat is called against FILE_NAME iff the FD parameter is set to
|
||||
zero, otherwise the fgetfileconat is used against correct file descriptor */
|
||||
void
|
||||
xattrs_selinux_get (MAYBE_UNUSED int parentfd, MAYBE_UNUSED char const *file_name,
|
||||
MAYBE_UNUSED struct tar_stat_info *st, MAYBE_UNUSED int fd)
|
||||
{
|
||||
if (selinux_context_option > 0)
|
||||
{
|
||||
#if HAVE_SELINUX_SELINUX_H != 1
|
||||
static bool done;
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
paxwarn (0, _("SELinux support is not available"));
|
||||
}
|
||||
#else
|
||||
int result = (fd
|
||||
? fgetfilecon (fd, &st->cntx_name)
|
||||
: lgetfileconat (parentfd, file_name, &st->cntx_name));
|
||||
|
||||
if (result < 0 && errno != ENODATA && errno != ENOTSUP)
|
||||
call_arg_warn (fd ? "fgetfilecon" : "lgetfileconat", file_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_selinux_set (MAYBE_UNUSED struct tar_stat_info const *st,
|
||||
MAYBE_UNUSED char const *file_name, MAYBE_UNUSED char typeflag)
|
||||
{
|
||||
if (selinux_context_option > 0)
|
||||
{
|
||||
#if HAVE_SELINUX_SELINUX_H != 1
|
||||
static bool done;
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
paxwarn (0, _("SELinux support is not available"));
|
||||
}
|
||||
#else
|
||||
const char *sysname = "setfilecon";
|
||||
int ret;
|
||||
|
||||
if (!st->cntx_name)
|
||||
return;
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
{
|
||||
ret = setfileconat (chdir_fd, file_name, st->cntx_name);
|
||||
sysname = "setfileconat";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = lsetfileconat (chdir_fd, file_name, st->cntx_name);
|
||||
sysname = "lsetfileconat";
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
warnopt (WARN_XATTR_WRITE, errno,
|
||||
_("%s: Cannot set SELinux context for file '%s'"),
|
||||
sysname, file_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm)
|
||||
{
|
||||
if (!mm->size)
|
||||
return false;
|
||||
|
||||
for (idx_t i = 0; i < mm->used; i++)
|
||||
if (fnmatch (mm->masks[i], kw, 0) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
xattrs_kw_included (const char *kw, bool archiving)
|
||||
{
|
||||
static char const USER_DOT_PFX[] = "user.";
|
||||
if (xattrs_setup.incl.size)
|
||||
return xattrs_matches_mask (kw, &xattrs_setup.incl);
|
||||
else if (archiving)
|
||||
return true;
|
||||
else
|
||||
return strncmp (kw, USER_DOT_PFX, sizeof (USER_DOT_PFX) - 1) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
xattrs_kw_excluded (const char *kw)
|
||||
{
|
||||
return xattrs_setup.excl.size ?
|
||||
xattrs_matches_mask (kw, &xattrs_setup.excl) : false;
|
||||
}
|
||||
|
||||
/* Check whether the xattr with keyword KW should be discarded from list of
|
||||
attributes that are going to be archived/excluded (set ARCHIVING=true for
|
||||
archiving, false for excluding) */
|
||||
static bool
|
||||
xattrs_masked_out (const char *kw, bool archiving)
|
||||
{
|
||||
return xattrs_kw_included (kw, archiving) ? xattrs_kw_excluded (kw) : true;
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_xattrs_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag, bool later_run)
|
||||
{
|
||||
if (xattrs_option)
|
||||
{
|
||||
#ifndef HAVE_XATTRS
|
||||
static bool done;
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
paxwarn (0, _("XATTR support is not available"));
|
||||
}
|
||||
#else
|
||||
if (!st->xattr_map.xm_size)
|
||||
return;
|
||||
|
||||
for (idx_t i = 0; i < st->xattr_map.xm_size; i++)
|
||||
{
|
||||
char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
|
||||
|
||||
/* TODO: this 'later_run' workaround is temporary solution -> once
|
||||
capabilities should become fully supported by it's API and there
|
||||
should exist something like xattrs_capabilities_set() call.
|
||||
For a regular files: all extended attributes are restored during
|
||||
the first run except 'security.capability' which is restored in
|
||||
'later_run == 1'. */
|
||||
if (typeflag == REGTYPE
|
||||
&& later_run == (strcmp (keyword, "security.capability") != 0))
|
||||
continue;
|
||||
|
||||
if (xattrs_masked_out (keyword, false /* extracting */ ))
|
||||
/* we don't want to restore this keyword */
|
||||
continue;
|
||||
|
||||
xattrs__fd_set (file_name, typeflag, keyword,
|
||||
st->xattr_map.xm_map[i].xval_ptr,
|
||||
st->xattr_map.xm_map[i].xval_len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_print_char (struct tar_stat_info const *st, char *output)
|
||||
{
|
||||
if (verbose_option < 2)
|
||||
{
|
||||
*output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (xattrs_option || selinux_context_option > 0 || acls_option > 0)
|
||||
{
|
||||
/* placeholders */
|
||||
*output = ' ';
|
||||
output[1] = 0;
|
||||
}
|
||||
|
||||
if (xattrs_option && st->xattr_map.xm_size)
|
||||
for (idx_t i = 0; i < st->xattr_map.xm_size; i++)
|
||||
{
|
||||
char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
|
||||
if (!xattrs_masked_out (keyword, false /* like extracting */ ))
|
||||
{
|
||||
*output = '*';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selinux_context_option > 0 && st->cntx_name)
|
||||
*output = '.';
|
||||
|
||||
if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
|
||||
*output = '+';
|
||||
}
|
||||
|
||||
void
|
||||
xattrs_print (struct tar_stat_info const *st)
|
||||
{
|
||||
if (verbose_option < 3)
|
||||
return;
|
||||
|
||||
/* selinux */
|
||||
if (selinux_context_option > 0 && st->cntx_name)
|
||||
fprintf (stdlis, " s: %s\n", st->cntx_name);
|
||||
|
||||
/* acls */
|
||||
if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
|
||||
{
|
||||
fprintf (stdlis, " a: ");
|
||||
acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len);
|
||||
if (st->acls_a_len && st->acls_d_len)
|
||||
fprintf (stdlis, ",");
|
||||
acls_one_line ("default:", ',', st->acls_d_ptr, st->acls_d_len);
|
||||
fprintf (stdlis, "\n");
|
||||
}
|
||||
|
||||
/* xattrs */
|
||||
if (xattrs_option && st->xattr_map.xm_size)
|
||||
{
|
||||
for (idx_t i = 0; i < st->xattr_map.xm_size; i++)
|
||||
{
|
||||
char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
|
||||
if (!xattrs_masked_out (keyword, false /* like extracting */ ))
|
||||
fprintf (stdlis, " x: %td %s\n",
|
||||
st->xattr_map.xm_map[i].xval_len, keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/xattrs.h
Normal file
47
src/xattrs.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* Support for extended attributes.
|
||||
|
||||
Copyright (C) 2006-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by James Antill, on 2006-07-27. */
|
||||
|
||||
#ifndef GUARD_XATTTRS_H
|
||||
#define GUARD_XATTTRS_H
|
||||
|
||||
/* Add include/exclude fnmatch pattern for xattr key domain. Set INCL parameter
|
||||
to true/false if you want to add include/exclude pattern */
|
||||
extern void xattrs_mask_add (const char *mask, bool incl);
|
||||
|
||||
extern void xattrs_acls_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, bool xisfile);
|
||||
extern void xattrs_selinux_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd);
|
||||
extern void xattrs_xattrs_get (int parentfd, char const *file_name,
|
||||
struct tar_stat_info *st, int fd);
|
||||
|
||||
extern void xattrs_acls_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag);
|
||||
extern void xattrs_selinux_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag);
|
||||
extern void xattrs_xattrs_set (struct tar_stat_info const *st,
|
||||
char const *file_name, char typeflag,
|
||||
bool later_run);
|
||||
|
||||
extern void xattrs_print_char (struct tar_stat_info const *st, char *output);
|
||||
extern void xattrs_print (struct tar_stat_info const *st);
|
||||
|
||||
#endif /* GUARD_XATTTRS_H */
|
||||
997
src/xheader.c
997
src/xheader.c
File diff suppressed because it is too large
Load Diff
5
tests/.gitignore
vendored
5
tests/.gitignore
vendored
@@ -8,3 +8,8 @@ argcv.c
|
||||
argcv.h
|
||||
genfile.c
|
||||
genfile
|
||||
download
|
||||
ttyemu
|
||||
checkseekhole
|
||||
ckmtime
|
||||
/compress-*.at
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
# Makefile for GNU tar regression tests.
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
|
||||
# 2006, 2007, 2009 Free Software Foundation, Inc.
|
||||
# Copyright 1996-2025 Free Software Foundation, Inc.
|
||||
|
||||
# François Pinard <pinard@iro.umontreal.ca>, 1988.
|
||||
# Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004.
|
||||
# This file is part of GNU tar.
|
||||
|
||||
## 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 3, or (at your option)
|
||||
## any later version.
|
||||
# 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 3 of the License, 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.
|
||||
# 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 this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
EXTRA_DIST = $(TESTSUITE_AT) \
|
||||
testsuite package.m4 star/README star/quicktest.sh \
|
||||
compress.m4
|
||||
|
||||
EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 star/README star/quicktest.sh
|
||||
DISTCLEANFILES = atconfig $(check_SCRIPTS)
|
||||
MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
|
||||
CLEANFILES =
|
||||
|
||||
## ------------ ##
|
||||
## package.m4. ##
|
||||
@@ -45,21 +45,50 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
## Test suite. ##
|
||||
## ------------ ##
|
||||
|
||||
# You can generate the body of this macro with the following shell command:
|
||||
# LC_ALL=C ls *.at */*.at | sed -e 's/^/ /' -e '$!s/$/\\/'
|
||||
TESTSUITE_AT = \
|
||||
T-cd.at\
|
||||
T-dir00.at\
|
||||
T-dir01.at\
|
||||
T-empty.at\
|
||||
T-mult.at\
|
||||
T-nest.at\
|
||||
T-nonl.at\
|
||||
T-null.at\
|
||||
testsuite.at\
|
||||
T-null2.at\
|
||||
T-rec.at\
|
||||
T-recurse.at\
|
||||
T-zfile.at\
|
||||
acls01.at\
|
||||
acls02.at\
|
||||
acls03.at\
|
||||
add-file.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
append02.at\
|
||||
append03.at\
|
||||
append04.at\
|
||||
append05.at\
|
||||
backup01.at\
|
||||
capabs_raw01.at\
|
||||
checkpoint/defaults.at\
|
||||
checkpoint/dot-compat.at\
|
||||
checkpoint/dot-int.at\
|
||||
checkpoint/dot.at\
|
||||
checkpoint/interval.at\
|
||||
chtype.at\
|
||||
comperr.at\
|
||||
comprec.at\
|
||||
delete01.at\
|
||||
delete02.at\
|
||||
delete03.at\
|
||||
delete04.at\
|
||||
delete05.at\
|
||||
delete06.at\
|
||||
difflink.at\
|
||||
dirrem01.at\
|
||||
dirrem02.at\
|
||||
exclude.at\
|
||||
exclude01.at\
|
||||
exclude02.at\
|
||||
@@ -67,6 +96,20 @@ TESTSUITE_AT = \
|
||||
exclude04.at\
|
||||
exclude05.at\
|
||||
exclude06.at\
|
||||
exclude07.at\
|
||||
exclude08.at\
|
||||
exclude09.at\
|
||||
exclude10.at\
|
||||
exclude11.at\
|
||||
exclude12.at\
|
||||
exclude13.at\
|
||||
exclude14.at\
|
||||
exclude15.at\
|
||||
exclude16.at\
|
||||
exclude17.at\
|
||||
exclude18.at\
|
||||
exclude19.at\
|
||||
exclude20.at\
|
||||
extrac01.at\
|
||||
extrac02.at\
|
||||
extrac03.at\
|
||||
@@ -82,19 +125,39 @@ TESTSUITE_AT = \
|
||||
extrac13.at\
|
||||
extrac14.at\
|
||||
extrac15.at\
|
||||
extrac16.at\
|
||||
extrac17.at\
|
||||
extrac18.at\
|
||||
extrac19.at\
|
||||
extrac20.at\
|
||||
extrac21.at\
|
||||
extrac22.at\
|
||||
extrac23.at\
|
||||
extrac24.at\
|
||||
extrac25.at\
|
||||
extrac26.at\
|
||||
extrac27.at\
|
||||
extrac28.at\
|
||||
extrac29.at\
|
||||
extrac30.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
gzip.at\
|
||||
grow.at\
|
||||
incremental.at\
|
||||
gzip.at\
|
||||
ignfail.at\
|
||||
incr01.at\
|
||||
incr02.at\
|
||||
incr03.at\
|
||||
incr04.at\
|
||||
incr05.at\
|
||||
incr06.at\
|
||||
incr07.at\
|
||||
incr08.at\
|
||||
incr09.at\
|
||||
incr10.at\
|
||||
incr11.at\
|
||||
incremental.at\
|
||||
indexfile.at\
|
||||
ignfail.at\
|
||||
label01.at\
|
||||
label02.at\
|
||||
label03.at\
|
||||
@@ -107,11 +170,14 @@ TESTSUITE_AT = \
|
||||
listed01.at\
|
||||
listed02.at\
|
||||
listed03.at\
|
||||
listed04.at\
|
||||
listed05.at\
|
||||
long01.at\
|
||||
longv7.at\
|
||||
lustar01.at\
|
||||
lustar02.at\
|
||||
lustar03.at\
|
||||
map.at\
|
||||
multiv01.at\
|
||||
multiv02.at\
|
||||
multiv03.at\
|
||||
@@ -120,54 +186,124 @@ TESTSUITE_AT = \
|
||||
multiv06.at\
|
||||
multiv07.at\
|
||||
multiv08.at\
|
||||
multiv09.at\
|
||||
multiv10.at\
|
||||
numeric.at\
|
||||
old.at\
|
||||
onetop01.at\
|
||||
onetop02.at\
|
||||
onetop03.at\
|
||||
onetop04.at\
|
||||
onetop05.at\
|
||||
opcomp01.at\
|
||||
opcomp02.at\
|
||||
opcomp03.at\
|
||||
opcomp04.at\
|
||||
opcomp05.at\
|
||||
opcomp06.at\
|
||||
options.at\
|
||||
options02.at\
|
||||
options03.at\
|
||||
owner.at\
|
||||
pipe.at\
|
||||
positional01.at\
|
||||
positional02.at\
|
||||
positional03.at\
|
||||
recurs02.at\
|
||||
recurse.at\
|
||||
remfiles01.at\
|
||||
remfiles02.at\
|
||||
remfiles03.at\
|
||||
remfiles04a.at\
|
||||
remfiles04b.at\
|
||||
remfiles04c.at\
|
||||
remfiles05a.at\
|
||||
remfiles05b.at\
|
||||
remfiles05c.at\
|
||||
remfiles06a.at\
|
||||
remfiles06b.at\
|
||||
remfiles06c.at\
|
||||
remfiles07a.at\
|
||||
remfiles07b.at\
|
||||
remfiles07c.at\
|
||||
remfiles08a.at\
|
||||
remfiles08b.at\
|
||||
remfiles08c.at\
|
||||
remfiles09a.at\
|
||||
remfiles09b.at\
|
||||
remfiles09c.at\
|
||||
remfiles10.at\
|
||||
rename01.at\
|
||||
rename02.at\
|
||||
rename03.at\
|
||||
rename04.at\
|
||||
rename05.at\
|
||||
remfiles01.at\
|
||||
remfiles02.at\
|
||||
remfiles03.at\
|
||||
rename06.at\
|
||||
same-order01.at\
|
||||
same-order02.at\
|
||||
selacl01.at\
|
||||
selnx01.at\
|
||||
shortfile.at\
|
||||
shortupd.at\
|
||||
shortrec.at\
|
||||
shortupd.at\
|
||||
sigpipe.at\
|
||||
skipdir.at\
|
||||
sparse01.at\
|
||||
sparse02.at\
|
||||
sparse03.at\
|
||||
sparse04.at\
|
||||
sparse05.at\
|
||||
sparse06.at\
|
||||
sparse07.at\
|
||||
sparsemv.at\
|
||||
sparsemvp.at\
|
||||
spmvp00.at\
|
||||
spmvp01.at\
|
||||
spmvp10.at\
|
||||
sptrcreat.at\
|
||||
sptrdiff00.at\
|
||||
sptrdiff01.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
star/multi-fail.at\
|
||||
star/pax-big-10g.at\
|
||||
star/ustar-big-2g.at\
|
||||
star/ustar-big-8g.at\
|
||||
testsuite.at\
|
||||
time01.at\
|
||||
time02.at\
|
||||
truncate.at\
|
||||
update.at\
|
||||
update01.at\
|
||||
update02.at\
|
||||
update03.at\
|
||||
update04.at\
|
||||
verbose.at\
|
||||
verify.at\
|
||||
version.at\
|
||||
volsize.at\
|
||||
volume.at\
|
||||
verbose.at\
|
||||
version.at\
|
||||
xattr01.at\
|
||||
xattr02.at\
|
||||
xattr03.at\
|
||||
xattr04.at\
|
||||
xattr05.at\
|
||||
xattr06.at\
|
||||
xattr07.at\
|
||||
xattr08.at\
|
||||
xform-h.at\
|
||||
xform01.at\
|
||||
star/gtarfail.at\
|
||||
star/gtarfail2.at\
|
||||
star/multi-fail.at\
|
||||
star/ustar-big-2g.at\
|
||||
star/ustar-big-8g.at\
|
||||
star/pax-big-10g.at
|
||||
xform02.at\
|
||||
xform03.at\
|
||||
xform04.at
|
||||
|
||||
distclean-local:
|
||||
-rm -rf download
|
||||
|
||||
TESTSUITE = $(srcdir)/testsuite
|
||||
|
||||
AUTOTEST = $(AUTOM4TE) --language=autotest
|
||||
$(TESTSUITE): package.m4 $(TESTSUITE_AT)
|
||||
$(TESTSUITE): compress.m4 package.m4 $(TESTSUITE_AT)
|
||||
$(AUTOTEST) -I $(srcdir) testsuite.at -o $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
@@ -186,7 +322,7 @@ check-full:
|
||||
#check_SCRIPTS = tar
|
||||
|
||||
# Run the test suite on the *installed* tree.
|
||||
installcheck-local:
|
||||
installcheck-local: $(check_PROGRAMS)
|
||||
$(SHELL) $(TESTSUITE) $(TESTSUITEFLAGS) AUTOTEST_PATH=$(exec_prefix)/bin
|
||||
|
||||
|
||||
@@ -194,11 +330,21 @@ installcheck-local:
|
||||
## genfile ##
|
||||
## ------------ ##
|
||||
|
||||
check_PROGRAMS = genfile
|
||||
check_PROGRAMS = genfile checkseekhole ckmtime
|
||||
|
||||
genfile_SOURCES = genfile.c argcv.c argcv.h
|
||||
checkseekhole_SOURCES = checkseekhole.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I$(top_srcdir)/gnu -I../gnu -I$(top_srcdir)/gnu -I$(top_srcdir)/lib
|
||||
AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\"
|
||||
LDADD = ../gnu/libgnu.a $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/gnu\
|
||||
-I../gnu\
|
||||
-I$(top_srcdir)/gnu\
|
||||
-I$(top_srcdir)/lib\
|
||||
-DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
LDADD = ../gnu/libgnu.a\
|
||||
$(LIB_ACL) $(QCOPY_ACL_LIB) $(CLOCK_TIME_LIB) $(EUIDACCESS_LIBGEN)\
|
||||
$(GETRANDOM_LIB) $(HARD_LOCALE_LIB) $(FILE_HAS_ACL_LIB) $(MBRTOWC_LIB)\
|
||||
$(LIB_SELINUX) $(SETLOCALE_NULL_LIB) \
|
||||
$(LIBINTL) $(LIBICONV)
|
||||
|
||||
44
tests/T-cd.at
Normal file
44
tests/T-cd.at
Normal file
@@ -0,0 +1,44 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([-C in file lists])
|
||||
AT_KEYWORDS([files-from T-cd chdir])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
>file1
|
||||
mkdir dir
|
||||
>dir/file2
|
||||
>dir/file3
|
||||
AT_DATA([F1],[file1
|
||||
-C dir
|
||||
.
|
||||
])
|
||||
tar cf archive -T F1
|
||||
tar tf archive | sort
|
||||
],
|
||||
[0],
|
||||
[./
|
||||
./file2
|
||||
./file3
|
||||
file1
|
||||
],[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
46
tests/T-dir00.at
Normal file
46
tests/T-dir00.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2014-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Tar 1.27 and 1.28 did not extract files under directory members listed
|
||||
# in the file read by --file-from.
|
||||
#
|
||||
# Reported-by: Jean-Louis Martineau <martineau@zmanda.com>
|
||||
# References: <541AE02C.2050008@zmanda.com>,
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2014-09/msg00006.html
|
||||
|
||||
AT_SETUP([recursive extraction from --files-from])
|
||||
AT_KEYWORDS([files-from extract T-dir T-dir00])
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir dir
|
||||
genfile -f dir/file1
|
||||
genfile -f dir/file2
|
||||
tar cf archive dir
|
||||
rm -rf dir
|
||||
echo dir > list
|
||||
tar xfTv archive list | sort
|
||||
],
|
||||
[0],
|
||||
[dir/
|
||||
dir/file1
|
||||
dir/file2
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
46
tests/T-dir01.at
Normal file
46
tests/T-dir01.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2014-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Tar 1.27 and 1.28 did not remove trailing slashes from file names
|
||||
# obtained with the --file-from option.
|
||||
#
|
||||
# Reported-by: Jean-Louis Martineau <martineau@zmanda.com>
|
||||
# References: <541AE02C.2050008@zmanda.com>,
|
||||
# http://lists.gnu.org/archive/html/bug-tar/2014-09/msg00006.html
|
||||
|
||||
AT_SETUP([trailing slash in --files-from])
|
||||
AT_KEYWORDS([files-from extract T-dir T-dir01])
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
mkdir dir
|
||||
genfile -f dir/file1
|
||||
genfile -f dir/file2
|
||||
tar cf archive dir
|
||||
rm -rf dir
|
||||
echo dir/ > list
|
||||
tar xfTv archive list | sort
|
||||
],
|
||||
[0],
|
||||
[dir/
|
||||
dir/file1
|
||||
dir/file2
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
# Copyright 2006-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# 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 3, or (at your option)
|
||||
# any later version.
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Tar 1.16 coredumped if a filelist file contained empty (zero-length)
|
||||
# entries
|
||||
# Reported by: Karl Berry <karl@freefriends.org>
|
||||
# References: <200610301353.k9UDr1O30680@f7.net>
|
||||
|
||||
AT_SETUP([files-from: empty entries])
|
||||
AT_KEYWORDS([files-from empty])
|
||||
AT_SETUP([empty entries])
|
||||
AT_KEYWORDS([files-from empty-line])
|
||||
|
||||
AT_DATA([file-list],
|
||||
[jeden
|
||||
@@ -34,17 +34,16 @@ trzy
|
||||
])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
genfile --file jeden
|
||||
genfile --file dwa
|
||||
genfile --file trzy
|
||||
|
||||
tar cfvT archive ../file-list | sort
|
||||
tar cfvT archive ../file-list
|
||||
],
|
||||
[0],
|
||||
[dwa
|
||||
jeden
|
||||
[jeden
|
||||
dwa
|
||||
trzy
|
||||
],
|
||||
[],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
46
tests/T-mult.at
Normal file
46
tests/T-mult.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([multiple file lists])
|
||||
AT_KEYWORDS([files-from T-mult])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
>file1
|
||||
>file2
|
||||
>file3
|
||||
>file4
|
||||
AT_DATA([F1],[file1
|
||||
file2
|
||||
])
|
||||
AT_DATA([F2],[file3
|
||||
file4
|
||||
])
|
||||
tar cf archive -T F1 -T F2
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
file2
|
||||
file3
|
||||
file4
|
||||
],[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
46
tests/T-nest.at
Normal file
46
tests/T-nest.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
#
|
||||
# Test suite for GNU tar.
|
||||
# Copyright 2013-2025 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AT_SETUP([nested file lists])
|
||||
AT_KEYWORDS([files-from T-nest])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
>file1
|
||||
>file2
|
||||
>file3
|
||||
>file4
|
||||
AT_DATA([F1],[file1
|
||||
-T F2
|
||||
file2
|
||||
])
|
||||
AT_DATA([F2],[file3
|
||||
file4
|
||||
])
|
||||
tar cf archive -T F1
|
||||
tar tf archive
|
||||
],
|
||||
[0],
|
||||
[file1
|
||||
file3
|
||||
file4
|
||||
file2
|
||||
],[],[],[],[ustar])
|
||||
|
||||
AT_CLEANUP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user