mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
864 Commits
v2.6.0pre1
...
v2.6.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
618c8a73db | ||
|
|
aa0ea373cd | ||
|
|
6c3fda83ba | ||
|
|
a3571c6cce | ||
|
|
6fcedb7dbe | ||
|
|
18882701d2 | ||
|
|
30c041f9ad | ||
|
|
be7cf82299 | ||
|
|
fde045cd77 | ||
|
|
183150b741 | ||
|
|
a2570930e8 | ||
|
|
fdb6716c0f | ||
|
|
a20a88d235 | ||
|
|
48d3ff94c9 | ||
|
|
a33857da09 | ||
|
|
13791b1eeb | ||
|
|
9a5e37fca8 | ||
|
|
3e976df0fb | ||
|
|
42afed9c1a | ||
|
|
37c36e2692 | ||
|
|
7fbc7031f4 | ||
|
|
9f004a9ea9 | ||
|
|
23f4587f2b | ||
|
|
4d8f5b0ae7 | ||
|
|
89389a29ef | ||
|
|
29fe3961ab | ||
|
|
4e8a085ac9 | ||
|
|
fb22c2774d | ||
|
|
7d059d4c37 | ||
|
|
9715c5899a | ||
|
|
cc07f21211 | ||
|
|
b4d1e854ef | ||
|
|
075aa18fd4 | ||
|
|
e0204f5621 | ||
|
|
a9ac4411e5 | ||
|
|
50b31539c2 | ||
|
|
56194bcd95 | ||
|
|
eb8ffa9040 | ||
|
|
a7a1cc2c75 | ||
|
|
ab217f7ffa | ||
|
|
a20c9893e4 | ||
|
|
3bb400ca14 | ||
|
|
cd6aa5b5c0 | ||
|
|
dc55d7bdab | ||
|
|
8b115ac8dc | ||
|
|
c94e4afbfa | ||
|
|
6566d205e2 | ||
|
|
e484f0cc04 | ||
|
|
bd397b8cba | ||
|
|
f8c8ef9eac | ||
|
|
72c19bb3de | ||
|
|
89f7eff382 | ||
|
|
b90a6d9ff6 | ||
|
|
584ba4ebae | ||
|
|
ba3db4795e | ||
|
|
59d73bf3d2 | ||
|
|
919ca3a3cc | ||
|
|
5886edfac2 | ||
|
|
d414962af4 | ||
|
|
8fb7db245a | ||
|
|
6f0fc27e33 | ||
|
|
9c54ad58f8 | ||
|
|
f55c2dfc03 | ||
|
|
675ef1aa3a | ||
|
|
ef57235623 | ||
|
|
d66d07e883 | ||
|
|
b92693daba | ||
|
|
58b1999e08 | ||
|
|
8e5f029e02 | ||
|
|
2d41264e9e | ||
|
|
82c6be7edf | ||
|
|
0219d4dfba | ||
|
|
391516da51 | ||
|
|
1d6b8f9ad2 | ||
|
|
10796f4b6e | ||
|
|
33ffd7c37d | ||
|
|
21d1e929a0 | ||
|
|
d0bc3520de | ||
|
|
9f18657889 | ||
|
|
c16d69b292 | ||
|
|
ebeacb36fb | ||
|
|
6558854dbe | ||
|
|
7d9d5d9478 | ||
|
|
630f548ff4 | ||
|
|
100b62bb69 | ||
|
|
e012b94f21 | ||
|
|
3104620cf0 | ||
|
|
ebdd24d6d0 | ||
|
|
7cd72c79ec | ||
|
|
84a6379565 | ||
|
|
0a5f12720e | ||
|
|
73f7af0e88 | ||
|
|
e5a96f0f54 | ||
|
|
d73e7f6edd | ||
|
|
61542c41de | ||
|
|
bd1a581bee | ||
|
|
6e8a1782ab | ||
|
|
96d910c770 | ||
|
|
7560c17adc | ||
|
|
9cd339eb39 | ||
|
|
f310029387 | ||
|
|
3ed8eb3f9c | ||
|
|
007351494d | ||
|
|
6dcb93208d | ||
|
|
84e1a698bf | ||
|
|
0d7638eafd | ||
|
|
86e2f445f7 | ||
|
|
093e816c37 | ||
|
|
1cb0a3edc6 | ||
|
|
06a5054273 | ||
|
|
acd0299243 | ||
|
|
dca68b0aad | ||
|
|
c3ea09906d | ||
|
|
bf4679e8a0 | ||
|
|
c4054610c8 | ||
|
|
f6c0d3d70b | ||
|
|
ef855d198e | ||
|
|
81b07870c8 | ||
|
|
bb6721dce6 | ||
|
|
446a2987cd | ||
|
|
4de2a17409 | ||
|
|
99d24f77ed | ||
|
|
c0422cea9f | ||
|
|
8b6ad0193d | ||
|
|
33eff8bfd6 | ||
|
|
65af3dab03 | ||
|
|
065a605270 | ||
|
|
a7260c4037 | ||
|
|
44cad59f2b | ||
|
|
c52461f911 | ||
|
|
7f459268d9 | ||
|
|
9eeb3b9c88 | ||
|
|
d1b31da71e | ||
|
|
89e540e638 | ||
|
|
fab65a5bc2 | ||
|
|
e7d13fe532 | ||
|
|
ecc81fce17 | ||
|
|
b4afd23c30 | ||
|
|
af1a3f9b6e | ||
|
|
820b6c9aa0 | ||
|
|
3cb22c204c | ||
|
|
7432ccf4ed | ||
|
|
6a48e792c1 | ||
|
|
9459290ae7 | ||
|
|
741d654495 | ||
|
|
d3e182af09 | ||
|
|
d9b4d267c7 | ||
|
|
58c5c24555 | ||
|
|
341c9a137f | ||
|
|
871446fc98 | ||
|
|
0abda1b176 | ||
|
|
394bcdb5e3 | ||
|
|
28deecca55 | ||
|
|
4db88e5b8f | ||
|
|
75b243a51d | ||
|
|
9bccfc429c | ||
|
|
077e59b769 | ||
|
|
007e3c0e9a | ||
|
|
e2bc412669 | ||
|
|
e344209582 | ||
|
|
e76ca1458c | ||
|
|
16cc9ca2c9 | ||
|
|
8c90957ff5 | ||
|
|
c0d8e84c9d | ||
|
|
b0ad542928 | ||
|
|
727b35f665 | ||
|
|
aa4343211f | ||
|
|
3611989355 | ||
|
|
3381b77d71 | ||
|
|
dce70db374 | ||
|
|
2adbcdc7ea | ||
|
|
7e5fa372cf | ||
|
|
6e45e1dd86 | ||
|
|
7f290d5c82 | ||
|
|
b6609cafae | ||
|
|
efa95a1842 | ||
|
|
51bd4f0f3a | ||
|
|
562b61695e | ||
|
|
98f51bfb56 | ||
|
|
73f0ce69e7 | ||
|
|
cf338ab1be | ||
|
|
66a9dc9639 | ||
|
|
8ed9d849dc | ||
|
|
5ebab6c10c | ||
|
|
e7a69008e6 | ||
|
|
73e015683c | ||
|
|
b462781fd0 | ||
|
|
93095cbe99 | ||
|
|
399371e7b5 | ||
|
|
d7142e2328 | ||
|
|
1f75bb1066 | ||
|
|
088adfacc1 | ||
|
|
da3478b2a7 | ||
|
|
5126ed1ef0 | ||
|
|
61fb21ad28 | ||
|
|
a3221d2ac1 | ||
|
|
2c713fcdfa | ||
|
|
afd8bdb907 | ||
|
|
efd5ee5786 | ||
|
|
510b4cd4d5 | ||
|
|
de584c658c | ||
|
|
6eb770bbcc | ||
|
|
c7e11bfdc0 | ||
|
|
94327ff0c2 | ||
|
|
4602eafa87 | ||
|
|
bb3edc3b47 | ||
|
|
c769702fe5 | ||
|
|
dbbab0c4d2 | ||
|
|
9b3318b0df | ||
|
|
0fac7fe8b8 | ||
|
|
b9f592fbf5 | ||
|
|
c7b1a56b3d | ||
|
|
3896bca4d8 | ||
|
|
9774cc3344 | ||
|
|
d3979b025d | ||
|
|
01966df4f7 | ||
|
|
f38bd4a072 | ||
|
|
b1df18d76f | ||
|
|
7daccb8e72 | ||
|
|
bb91a624f1 | ||
|
|
a04d77bcbc | ||
|
|
25bd99451c | ||
|
|
ed43d0a76d | ||
|
|
066a844c4e | ||
|
|
5e252dea4b | ||
|
|
d2a918b454 | ||
|
|
da38e779ea | ||
|
|
8186ae6bc0 | ||
|
|
e1f67417d7 | ||
|
|
fd322eef82 | ||
|
|
d3a4375f78 | ||
|
|
78112d305b | ||
|
|
f7c3ee9932 | ||
|
|
e7a392c77c | ||
|
|
887e553f05 | ||
|
|
beb227ddf1 | ||
|
|
84acca07ae | ||
|
|
cc1e997dcd | ||
|
|
a7026ba90a | ||
|
|
3a69fad0f6 | ||
|
|
40564811ee | ||
|
|
dcd08dc51c | ||
|
|
fdf57ede8c | ||
|
|
bd717af8ab | ||
|
|
c54f5170bf | ||
|
|
eae4e1f9f0 | ||
|
|
9c513d678d | ||
|
|
d16c245fc4 | ||
|
|
ec8290c897 | ||
|
|
b293a7f62c | ||
|
|
d67c8bdfc3 | ||
|
|
e2ccd3578c | ||
|
|
4e834af140 | ||
|
|
7e5614383d | ||
|
|
eb84a83b47 | ||
|
|
2c2898a388 | ||
|
|
1732b6c037 | ||
|
|
314f459161 | ||
|
|
83926d3cae | ||
|
|
6218c7bf42 | ||
|
|
566fce3237 | ||
|
|
373ef16010 | ||
|
|
ea76e76104 | ||
|
|
9fd62d1588 | ||
|
|
b7061c82b4 | ||
|
|
6fb812f747 | ||
|
|
40e8d11e64 | ||
|
|
73042aae5b | ||
|
|
e5ce3bcf2c | ||
|
|
c399d22a19 | ||
|
|
1ea087a794 | ||
|
|
00bdf89977 | ||
|
|
0bb4d17634 | ||
|
|
f9c6b3e7d6 | ||
|
|
9e5a5ddb4c | ||
|
|
8c0d6a8432 | ||
|
|
553f93758a | ||
|
|
a4a7e64c19 | ||
|
|
22832c30a0 | ||
|
|
1a21666286 | ||
|
|
4033b80b51 | ||
|
|
99218d821b | ||
|
|
e626b29e10 | ||
|
|
f89b936801 | ||
|
|
17f59e818d | ||
|
|
b5bd5542eb | ||
|
|
2e94e70e2b | ||
|
|
4e1f385711 | ||
|
|
716e73d483 | ||
|
|
5b36173d11 | ||
|
|
b2ef4f6134 | ||
|
|
c7be6dec11 | ||
|
|
bd1574b208 | ||
|
|
f376e67420 | ||
|
|
ef0bc0abff | ||
|
|
71e586304b | ||
|
|
3c74c3a358 | ||
|
|
edad5898f2 | ||
|
|
fa0c1939ed | ||
|
|
9a5ade185c | ||
|
|
f1dd0f27cb | ||
|
|
f9e5a0cde2 | ||
|
|
ead751c62b | ||
|
|
0058c58edd | ||
|
|
221ddb9456 | ||
|
|
65e2487096 | ||
|
|
0501f36390 | ||
|
|
96981b9cff | ||
|
|
f51e87f5ad | ||
|
|
cb213f1c1b | ||
|
|
c8d895de26 | ||
|
|
e51094b721 | ||
|
|
b03bded70b | ||
|
|
ee1df1ccae | ||
|
|
bc6ebcd248 | ||
|
|
ba582f753a | ||
|
|
cbd85b472e | ||
|
|
7a92ded39a | ||
|
|
831f05df51 | ||
|
|
0d94a6a66c | ||
|
|
3e35c34b6b | ||
|
|
03a9ca0a97 | ||
|
|
6f481bb0e0 | ||
|
|
f98cc5685d | ||
|
|
9135621ff9 | ||
|
|
8624daa7f8 | ||
|
|
3051c46dc3 | ||
|
|
e920830ec5 | ||
|
|
7892e5ac77 | ||
|
|
b0e9bafc78 | ||
|
|
44aa070770 | ||
|
|
97f9dcae6a | ||
|
|
8cbf495a57 | ||
|
|
c1b29492c5 | ||
|
|
669a31924e | ||
|
|
5e972dcf34 | ||
|
|
8fcdc444df | ||
|
|
619d21ffc9 | ||
|
|
d62bcc17f3 | ||
|
|
982e05bbd5 | ||
|
|
a3c8b36863 | ||
|
|
630e3c408b | ||
|
|
1082b52bd4 | ||
|
|
914f3066bb | ||
|
|
de91e75724 | ||
|
|
384431886a | ||
|
|
82b302d928 | ||
|
|
4ecc9e6b64 | ||
|
|
55e50d890b | ||
|
|
6e86c951d7 | ||
|
|
c41b52c487 | ||
|
|
5c6fc4a6a3 | ||
|
|
edecdad54d | ||
|
|
5291364f1d | ||
|
|
41cc97ae64 | ||
|
|
bf2b7ddfc5 | ||
|
|
eb0cbdaa90 | ||
|
|
0d0142e812 | ||
|
|
a43e21e05c | ||
|
|
4135d091a6 | ||
|
|
534407b1f4 | ||
|
|
18cc8c7ef1 | ||
|
|
58c9b4b7f6 | ||
|
|
cde719f49f | ||
|
|
38cab94d9a | ||
|
|
6ed6d7f5a8 | ||
|
|
e40a46de71 | ||
|
|
c5bf99a1c2 | ||
|
|
2c7d63c765 | ||
|
|
3dd22903ac | ||
|
|
d8d36af452 | ||
|
|
e610e50f9c | ||
|
|
935c64173f | ||
|
|
377dbd2075 | ||
|
|
93272700d2 | ||
|
|
d508258ad8 | ||
|
|
f57b2e6150 | ||
|
|
af45f9e27e | ||
|
|
4c4d61b046 | ||
|
|
7561c3e132 | ||
|
|
1514ad2a80 | ||
|
|
d8195637d4 | ||
|
|
c8d771a0fb | ||
|
|
9130776c4e | ||
|
|
9eac94a4dd | ||
|
|
6e06d2f31a | ||
|
|
6a6d21136a | ||
|
|
f28bd83346 | ||
|
|
96fb478eae | ||
|
|
8752b3fcd8 | ||
|
|
55ffed7e42 | ||
|
|
e00df64bae | ||
|
|
080ddf58ae | ||
|
|
4ce48a5bfd | ||
|
|
20bf7f847f | ||
|
|
b66d00853b | ||
|
|
8b602edda4 | ||
|
|
9f27cd8ca6 | ||
|
|
b084f9e092 | ||
|
|
4220e1098e | ||
|
|
c30468169a | ||
|
|
c0d9e8c76b | ||
|
|
90a973fe8a | ||
|
|
7f0feb4dd6 | ||
|
|
33a5432ea6 | ||
|
|
968ff560d2 | ||
|
|
cd59be1d5e | ||
|
|
8b2869c0d2 | ||
|
|
82a51ea53d | ||
|
|
20af605eba | ||
|
|
a6536635e3 | ||
|
|
adddd075eb | ||
|
|
a0c823b22b | ||
|
|
9fdb334e85 | ||
|
|
f89e890b87 | ||
|
|
1c666c3fcb | ||
|
|
2a383be0f1 | ||
|
|
ac1d2d3384 | ||
|
|
acfcfa7053 | ||
|
|
8ef81dd452 | ||
|
|
67340e9523 | ||
|
|
a7ceddae34 | ||
|
|
24e1569f8b | ||
|
|
de31639fff | ||
|
|
8b46340924 | ||
|
|
d008bcb5cd | ||
|
|
0484b5b0b7 | ||
|
|
f01b6368a5 | ||
|
|
40d38dc0be | ||
|
|
33a2361cc2 | ||
|
|
4124540d61 | ||
|
|
5f38126817 | ||
|
|
b05b3c9b48 | ||
|
|
a03a9f4efe | ||
|
|
3e55030372 | ||
|
|
273c0420d0 | ||
|
|
5774786fa5 | ||
|
|
1a9ec1fd1c | ||
|
|
b2aa573b1c | ||
|
|
63d0331991 | ||
|
|
bf6dcd1713 | ||
|
|
495723bb26 | ||
|
|
911cb0662c | ||
|
|
5387514eaf | ||
|
|
61414c83ce | ||
|
|
43a9d0e7c2 | ||
|
|
df5cd107a5 | ||
|
|
abca4eba67 | ||
|
|
96d3590a08 | ||
|
|
8429aa9e0e | ||
|
|
79d4053048 | ||
|
|
753b6b4692 | ||
|
|
f8f726449b | ||
|
|
357406ecb2 | ||
|
|
3915fd7583 | ||
|
|
9c5e91f848 | ||
|
|
af107f6c08 | ||
|
|
a3dbb20a0e | ||
|
|
a3779426b6 | ||
|
|
2f5ca63d92 | ||
|
|
0e1d98ae92 | ||
|
|
04575bcab5 | ||
|
|
71b291d71b | ||
|
|
decba3ae73 | ||
|
|
f8ed564c9f | ||
|
|
47ba39bef6 | ||
|
|
71f7051489 | ||
|
|
3c3791e8be | ||
|
|
c39d6514ab | ||
|
|
1cb6f3bf4d | ||
|
|
f09dc86ab6 | ||
|
|
f26ac1e8cb | ||
|
|
84a3efa0ab | ||
|
|
00ed4b5bf3 | ||
|
|
e2e053bbd7 | ||
|
|
f8b33ab379 | ||
|
|
5df1fcf245 | ||
|
|
b1ad6a3260 | ||
|
|
6442ccc606 | ||
|
|
b21813060c | ||
|
|
706c75307a | ||
|
|
2b284ee33d | ||
|
|
4cfa6156e3 | ||
|
|
c1e7217fcb | ||
|
|
4b2f6a7c37 | ||
|
|
a8726d2a06 | ||
|
|
b5ebe6d9c7 | ||
|
|
ef383c0d32 | ||
|
|
8dcf93356e | ||
|
|
ce5f2732e4 | ||
|
|
3e89da86df | ||
|
|
f5450e791d | ||
|
|
cb984e620e | ||
|
|
be92ac6c36 | ||
|
|
5dc6e9c9ca | ||
|
|
0b79c324ca | ||
|
|
f39b6638f6 | ||
|
|
a4b6f30579 | ||
|
|
7be73df4e7 | ||
|
|
14b61c63f0 | ||
|
|
75a64762c2 | ||
|
|
028fdddb49 | ||
|
|
f86b0f2e7b | ||
|
|
285fba0759 | ||
|
|
92b9eb978e | ||
|
|
1e82e2cea6 | ||
|
|
a7ed6ca618 | ||
|
|
b4b90120ff | ||
|
|
16f72adc49 | ||
|
|
3d06165389 | ||
|
|
fd4893155d | ||
|
|
67e78a8231 | ||
|
|
6b320e4045 | ||
|
|
7e5cb90983 | ||
|
|
8120a98f47 | ||
|
|
8f3f8eec08 | ||
|
|
386b93dc60 | ||
|
|
b3bc31102c | ||
|
|
0f1aa0d3e5 | ||
|
|
7a08ae31d2 | ||
|
|
304f127f56 | ||
|
|
c338460d66 | ||
|
|
48d704af52 | ||
|
|
ac7aa92290 | ||
|
|
0042f81894 | ||
|
|
2c836acb37 | ||
|
|
a1d8f29a3d | ||
|
|
a174e1ed0f | ||
|
|
530adb7625 | ||
|
|
cd3fe9fb03 | ||
|
|
a8edfd53d1 | ||
|
|
dbb665180c | ||
|
|
9d78ed31a7 | ||
|
|
89afe532d7 | ||
|
|
c67d13866b | ||
|
|
3b98b08c4d | ||
|
|
9c15534511 | ||
|
|
55afbb522c | ||
|
|
27ed20f7a0 | ||
|
|
f567e9b3d7 | ||
|
|
40ae4f93a0 | ||
|
|
7a27e9b599 | ||
|
|
62c9e6b3a5 | ||
|
|
cfeed4da95 | ||
|
|
4068d8617d | ||
|
|
421c2a2448 | ||
|
|
d1e7726460 | ||
|
|
0596df00b3 | ||
|
|
417c99f637 | ||
|
|
de0e225076 | ||
|
|
e0391f8149 | ||
|
|
7de2483fbd | ||
|
|
65d6212d03 | ||
|
|
4d4df3cd2b | ||
|
|
62125b10c9 | ||
|
|
81c3a3a86e | ||
|
|
61d35e1844 | ||
|
|
15f85b1f63 | ||
|
|
5bf63a11f4 | ||
|
|
97a67bdfa9 | ||
|
|
aa0b9ca174 | ||
|
|
b96efc2f67 | ||
|
|
be20dc3448 | ||
|
|
cb869c26d9 | ||
|
|
7cf8e8d05d | ||
|
|
54fd3e5020 | ||
|
|
3e4916822d | ||
|
|
7efdcf3218 | ||
|
|
9935066b70 | ||
|
|
6c2e5b56e4 | ||
|
|
2289bf64cc | ||
|
|
b1bf649cba | ||
|
|
8ee6eb7134 | ||
|
|
f98c60bfa8 | ||
|
|
a5c1113971 | ||
|
|
736f46d1d9 | ||
|
|
a8f7e4b835 | ||
|
|
9352b0649b | ||
|
|
a85906c756 | ||
|
|
8aa81e06e6 | ||
|
|
1f9ae80a3e | ||
|
|
71020fc3aa | ||
|
|
7b74bba15e | ||
|
|
e5fbaa713a | ||
|
|
6609a9f17e | ||
|
|
5204e853e1 | ||
|
|
01363a24e2 | ||
|
|
d49def4832 | ||
|
|
4836c3eece | ||
|
|
9f7b8c3b8f | ||
|
|
ade7292aee | ||
|
|
dbd8811b85 | ||
|
|
05118158f4 | ||
|
|
1df395f7c2 | ||
|
|
5fdf2e7063 | ||
|
|
6fe05820ff | ||
|
|
670d8abf80 | ||
|
|
b2bffbb2ca | ||
|
|
13a6d667d2 | ||
|
|
1be77f8336 | ||
|
|
187e9c24f1 | ||
|
|
eddeaf76f8 | ||
|
|
33e9d10d2a | ||
|
|
46f7dc3bf6 | ||
|
|
555b0e20f7 | ||
|
|
a57dfe710d | ||
|
|
53adbd7a3d | ||
|
|
17f033b725 | ||
|
|
cefed3e8dc | ||
|
|
84fa865c0c | ||
|
|
f05f993eb7 | ||
|
|
e90cdb8adf | ||
|
|
4250941710 | ||
|
|
a2687b64a2 | ||
|
|
c284f34a49 | ||
|
|
5f5be796b0 | ||
|
|
5cb374364b | ||
|
|
f15256e156 | ||
|
|
ce37eb2d83 | ||
|
|
0d6e308b51 | ||
|
|
b1dab2363a | ||
|
|
bd6abc4939 | ||
|
|
96eeda0324 | ||
|
|
4c4266d9c9 | ||
|
|
54e87b4b06 | ||
|
|
44e9e221f3 | ||
|
|
61dec11ae0 | ||
|
|
5009de7d2d | ||
|
|
67f3feebcb | ||
|
|
b22260749f | ||
|
|
06d76beb28 | ||
|
|
7af4227ac2 | ||
|
|
9312b7325e | ||
|
|
c6edb381f5 | ||
|
|
a1d55ad095 | ||
|
|
a289addd96 | ||
|
|
13c5b46361 | ||
|
|
f3af206d8d | ||
|
|
df0054ab13 | ||
|
|
0d162bd17c | ||
|
|
e1add89334 | ||
|
|
22d49dc429 | ||
|
|
1aa4caf318 | ||
|
|
306ffb8c71 | ||
|
|
0a98201164 | ||
|
|
e0870f1d7a | ||
|
|
1923b1fce4 | ||
|
|
5dc4003e63 | ||
|
|
37c817eb81 | ||
|
|
284d628a7c | ||
|
|
ff3184ca1e | ||
|
|
12865a9762 | ||
|
|
ea847c6232 | ||
|
|
b695f2423d | ||
|
|
c3e5e5851b | ||
|
|
4337c8f856 | ||
|
|
4c7e46079d | ||
|
|
72a6e63136 | ||
|
|
37101856a6 | ||
|
|
65fc84b32e | ||
|
|
45e08edb08 | ||
|
|
05b7bab8e1 | ||
|
|
904817552d | ||
|
|
6e195fe975 | ||
|
|
3eaf615f40 | ||
|
|
6156e72f85 | ||
|
|
73a4bdfd77 | ||
|
|
4844449a5d | ||
|
|
ae289aec1e | ||
|
|
9e4c32ea54 | ||
|
|
a5f9cff256 | ||
|
|
d01d15e096 | ||
|
|
a53426441b | ||
|
|
5d1966948e | ||
|
|
f673ea84b2 | ||
|
|
64f21c31bf | ||
|
|
520cf41711 | ||
|
|
d38fc30563 | ||
|
|
6dff599288 | ||
|
|
f746dda0a0 | ||
|
|
91a1e147ae | ||
|
|
40da904230 | ||
|
|
34fada3012 | ||
|
|
f91e01d9a5 | ||
|
|
3048b0a8ea | ||
|
|
d99b4ccf93 | ||
|
|
58811a0a38 | ||
|
|
cb290916be | ||
|
|
a2b0471f1d | ||
|
|
bb18e7550c | ||
|
|
db2b5cb75f | ||
|
|
fa8c787d8b | ||
|
|
ec40899bb9 | ||
|
|
b5accabaa7 | ||
|
|
4e308a9526 | ||
|
|
4d88810810 | ||
|
|
f321922214 | ||
|
|
cab13afe8d | ||
|
|
72fc7ec59b | ||
|
|
58743a87b8 | ||
|
|
54bf456e85 | ||
|
|
a24639bb36 | ||
|
|
3fef53645d | ||
|
|
882e689312 | ||
|
|
b0a93231cf | ||
|
|
0c819b76d6 | ||
|
|
ce58b1b479 | ||
|
|
a16d8f2b25 | ||
|
|
59187666b9 | ||
|
|
808c57c343 | ||
|
|
4af8fe4e78 | ||
|
|
4034cb3f71 | ||
|
|
6fc048f438 | ||
|
|
5d2a707139 | ||
|
|
81d2b0ef9d | ||
|
|
248ed45fc6 | ||
|
|
893c4cc056 | ||
|
|
a7725e6df9 | ||
|
|
368ad70e05 | ||
|
|
b7cee9498b | ||
|
|
72d45525d2 | ||
|
|
1fb8ec4b0d | ||
|
|
beb9368481 | ||
|
|
981555bddb | ||
|
|
9c7527085c | ||
|
|
eddd5d129e | ||
|
|
26f76b7912 | ||
|
|
32eda0961e | ||
|
|
66964002df | ||
|
|
57469f6c31 | ||
|
|
13c7bcbb2b | ||
|
|
d48c806560 | ||
|
|
ad1a09a509 | ||
|
|
d6631cf3a5 | ||
|
|
5a8543b8b8 | ||
|
|
19119cbd35 | ||
|
|
442743b83c | ||
|
|
419896af47 | ||
|
|
0569a1339d | ||
|
|
f1e3656ee2 | ||
|
|
a644fc3cc4 | ||
|
|
d17e1dd2da | ||
|
|
b9b15fb165 | ||
|
|
ef732c3b54 | ||
|
|
baa4212ae1 | ||
|
|
0be976ec0a | ||
|
|
f7f10340d6 | ||
|
|
68f9910d94 | ||
|
|
fb6e0ea120 | ||
|
|
97feb557ed | ||
|
|
dc8293ff73 | ||
|
|
785db4ced0 | ||
|
|
5562deb169 | ||
|
|
983b1ed321 | ||
|
|
548abf96ce | ||
|
|
f8ebdf9265 | ||
|
|
aa23c22004 | ||
|
|
1d5cda2265 | ||
|
|
fe70ad26d3 | ||
|
|
0a00748901 | ||
|
|
03979352b4 | ||
|
|
cb7fb45e42 | ||
|
|
92cc9dd7c2 | ||
|
|
88a7fb3edd | ||
|
|
728d092201 | ||
|
|
80707c983c | ||
|
|
5911fee567 | ||
|
|
a09f6f55da | ||
|
|
caf5cc9152 | ||
|
|
58422e8393 | ||
|
|
e8d3168e3a | ||
|
|
7b1a0c19b8 | ||
|
|
536492752b | ||
|
|
7c4f063b13 | ||
|
|
1a62c49d31 | ||
|
|
fea4db62bd | ||
|
|
4499c0eebd | ||
|
|
0c42946536 | ||
|
|
ab264c9e79 | ||
|
|
dd7fb70f6e | ||
|
|
30f337c9ef | ||
|
|
9d35271938 | ||
|
|
bbfb1d016b | ||
|
|
c4b4df4fb4 | ||
|
|
a6d89d18bf | ||
|
|
75bc860093 | ||
|
|
02a279a75f | ||
|
|
584c7bf76d | ||
|
|
c4cd2ca6bf | ||
|
|
1ef00d2072 | ||
|
|
4dd4c72790 | ||
|
|
6aae748ea7 | ||
|
|
aa953c3201 | ||
|
|
3f55bd5dad | ||
|
|
279b1c1ebb | ||
|
|
fa45cda1aa | ||
|
|
11dc274054 | ||
|
|
e7bef92205 | ||
|
|
4a1991d7c5 | ||
|
|
13aefa1365 | ||
|
|
addf0c4a1c | ||
|
|
25bfc8cea1 | ||
|
|
dfd5ba6ab7 | ||
|
|
393ba2214d | ||
|
|
f358487f8e | ||
|
|
a18381aca6 | ||
|
|
f6e54812b7 | ||
|
|
31e7451aa5 | ||
|
|
0e36d9da42 | ||
|
|
da9d12f5d9 | ||
|
|
a60e2dca6b | ||
|
|
86c4601e12 | ||
|
|
173f5bf8cf | ||
|
|
823edc686f | ||
|
|
a3a841073e | ||
|
|
57385128c3 | ||
|
|
2990e06f29 | ||
|
|
2ef2e822d1 | ||
|
|
b7736c797c | ||
|
|
9b9c8aaf4d | ||
|
|
b0fd253afc | ||
|
|
e028b9ff53 | ||
|
|
9c07d25345 | ||
|
|
7352b8736b | ||
|
|
5b540e86a4 | ||
|
|
6744b62ddd | ||
|
|
e90b8acec3 | ||
|
|
925c517f19 | ||
|
|
cc964a518c | ||
|
|
3309507dd3 | ||
|
|
5e7dbaca50 | ||
|
|
76c2194714 | ||
|
|
968c8030cf | ||
|
|
446e239e2c | ||
|
|
e7bc9b64a3 | ||
|
|
8018edd3aa | ||
|
|
64c3523a6f | ||
|
|
310c9f30f0 | ||
|
|
5c1b7bfd2a | ||
|
|
faf11086d8 | ||
|
|
52fa4d7893 | ||
|
|
de0551020b | ||
|
|
c1456d83a7 | ||
|
|
1cbbaea957 | ||
|
|
f6aeaa74d1 | ||
|
|
6839140eb5 | ||
|
|
915dd20705 | ||
|
|
c53217a2b8 | ||
|
|
b2ac00eb16 | ||
|
|
45ddbf6204 | ||
|
|
276877cf77 | ||
|
|
6b45fcf160 | ||
|
|
49c24eccd4 | ||
|
|
0d7d3763f2 | ||
|
|
241dc65eee | ||
|
|
860bdd4571 | ||
|
|
55bf051bbc | ||
|
|
423dba8ea1 | ||
|
|
517c7b4dee | ||
|
|
18ced14631 | ||
|
|
ce67256218 | ||
|
|
9e83fa99fe | ||
|
|
256a9e376c | ||
|
|
ef5075e092 |
@@ -1,6 +1,6 @@
|
||||
ID
|
||||
Makefile
|
||||
autom4te.cache
|
||||
autom4te*.cache
|
||||
confdefs.h
|
||||
config.cache
|
||||
config.h
|
||||
@@ -21,4 +21,4 @@ tls
|
||||
trimslash
|
||||
t_unsafe
|
||||
wildtest
|
||||
zlib/dummy
|
||||
getfsdev
|
||||
|
||||
43
Makefile.in
43
Makefile.in
@@ -25,9 +25,9 @@ VERSION=@VERSION@
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
|
||||
lib/permstring.o @LIBOBJS@
|
||||
lib/permstring.o lib/pool_alloc.o @LIBOBJS@
|
||||
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
|
||||
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
|
||||
zlib/zutil.o zlib/adler32.o
|
||||
@@ -44,11 +44,11 @@ OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
|
||||
TLS_OBJ = tls.o syscall.o lib/permstring.o
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) \
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
|
||||
|
||||
# Objects for CHECK_PROGS to clean
|
||||
CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
CHECK_OBJS=getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
|
||||
# note that the -I. is needed to handle config.h when using VPATH
|
||||
.c.o:
|
||||
@@ -58,18 +58,16 @@ CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
|
||||
all: rsync$(EXEEXT)
|
||||
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
|
||||
install: all
|
||||
-mkdir -p ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
-mkdir -p ${DESTDIR}${mandir}/man1
|
||||
-mkdir -p ${DESTDIR}${mandir}/man5
|
||||
${INSTALLMAN} -m 644 $(srcdir)/rsync.1 ${DESTDIR}${mandir}/man1
|
||||
${INSTALLMAN} -m 644 $(srcdir)/rsyncd.conf.5 ${DESTDIR}${mandir}/man5
|
||||
|
||||
install-strip:
|
||||
$(MAKE) STRIP='-s' install
|
||||
$(MAKE) INSTALL_STRIP='-s' install
|
||||
|
||||
rsync$(EXEEXT): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
@@ -82,6 +80,9 @@ tls$(EXEEXT): $(TLS_OBJ)
|
||||
getgroups$(EXEEXT): getgroups.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
|
||||
|
||||
getfsdev$(EXEEXT): getfsdev.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
@@ -90,17 +91,15 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
# I don't like these rules because CVS can skew the timestamps and
|
||||
# produce spurious warnings, and also make "make install" fail if the
|
||||
# source directory can no longer be found. Since we don't rebuild
|
||||
# automatically they're kind of lame anyhow.
|
||||
gen: $(srcdir)/configure $(srcdir)/config.h.in proto man
|
||||
|
||||
#Makefile: Makefile.in configure config.status
|
||||
# echo "WARNING: You need to run ./config.status --recheck"
|
||||
man: $(srcdir)/rsync.1 $(srcdir)/rsyncd.conf.5
|
||||
|
||||
# don't actually run autoconf, just issue a warning
|
||||
#configure: configure.in
|
||||
# echo "WARNING: you need to rerun autoconf"
|
||||
$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4
|
||||
cd $(srcdir); autoconf
|
||||
|
||||
$(srcdir)/config.h.in: $(srcdir)/configure.in $(srcdir)/aclocal.m4
|
||||
cd $(srcdir); autoheader
|
||||
|
||||
$(srcdir)/rsync.1: $(srcdir)/rsync.yo
|
||||
yodl2man -o $(srcdir)/rsync.1 $(srcdir)/rsync.yo
|
||||
@@ -109,7 +108,12 @@ $(srcdir)/rsyncd.conf.5: $(srcdir)/rsyncd.conf.yo
|
||||
yodl2man -o $(srcdir)/rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
|
||||
proto:
|
||||
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk > $(srcdir)/proto.h
|
||||
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk >$(srcdir)/proto.h.new
|
||||
if diff $(srcdir)/proto.h $(srcdir)/proto.h.new >/dev/null; then \
|
||||
rm $(srcdir)/proto.h.new; \
|
||||
else \
|
||||
mv $(srcdir)/proto.h.new $(srcdir)/proto.h; \
|
||||
fi
|
||||
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
|
||||
@@ -146,9 +150,6 @@ test: check
|
||||
# There seems to be no standard way to specify some variables as
|
||||
# exported from a Makefile apart from listing them like this.
|
||||
|
||||
# TODO: Tests that depend on built test aide programs like tls need to
|
||||
# know where the build directory is.
|
||||
|
||||
# This depends on building rsync; if we need any helper programs it
|
||||
# should depend on them too.
|
||||
|
||||
|
||||
369
NEWS
369
NEWS
@@ -1,227 +1,252 @@
|
||||
NEWS for rsync version 2.6.0
|
||||
Protocol: 27 (changed)
|
||||
Changes since version 2.5.7:
|
||||
NEWS for rsync 2.6.3 (30 Sep 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.2:
|
||||
|
||||
ENHANCEMENTS:
|
||||
SECURITY FIXES:
|
||||
|
||||
* "ssh" is now the default remote shell for rsync. If you want to
|
||||
change this, configure like this: "./configure --with-rsh=rsh".
|
||||
- A bug in the sanitize_path routine (which affects a non-chrooted
|
||||
rsync daemon) could allow a user to craft a pathname that would get
|
||||
transformed into an absolute path for certain options (but not for
|
||||
file-transfer names). If you're running an rsync daemon with chroot
|
||||
disabled, *please upgrade*, ESPECIALLY if the user privs you run
|
||||
rsync under is anything above "nobody".
|
||||
|
||||
* Added --files-from, --no-relative, --no-implied-dirs, and --from0.
|
||||
Note that --from0 affects the line-ending character for all the
|
||||
files read by the --*-from options. (Wayne Davison)
|
||||
OUTPUT CHANGES (ATTN: those using a script to parse the verbose output):
|
||||
|
||||
* Length of csum2 is now per-file starting with protocol verison
|
||||
27. (J.W. Schultz)
|
||||
- Please note that the 2-line footer (output when verbose) now uses the
|
||||
term "sent" instead of "wrote" and "received" instead of "read". If
|
||||
you are not parsing the numeric values out of this footer, a script
|
||||
would be better off using the empty line prior to the footer as the
|
||||
indicator that the verbose output is over.
|
||||
|
||||
- The output from the --stats option was similarly affected to change
|
||||
"written" to "sent" and "read" to "received".
|
||||
|
||||
* Per-file dynamic block size is now sqrt(file length).
|
||||
The per-file checksum size is determined according
|
||||
to an algorythm provided by Donovan Baarda which
|
||||
reduces the probability of rsync algorithm
|
||||
corrupting data and falling back using the whole md4
|
||||
checksums. (J.W. Schultz, Donovan Baarda)
|
||||
- Rsync ensures that a filename that contains a newline gets mentioned
|
||||
with each newline transformed into a question mark (which prevents a
|
||||
filename from causing an empty line to be output).
|
||||
|
||||
* The --stats option no longer includes the (debug) malloc summary
|
||||
unless the verbose option was specified at least twice.
|
||||
|
||||
* Added a new error/warning code for when files vanish from the
|
||||
sending side. Made vanished source files not interfere with the
|
||||
file-deletion pass when --delete-after was specified.
|
||||
- The "backed up ..." message that is output when at least 2 --verbose
|
||||
options are specified is now the same both with and without the
|
||||
--backup-dir option.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fixed several exclude/include matching bugs when using wild-cards.
|
||||
This has a several user-visible effects, all of which make the
|
||||
matching more consistent and intuitive. This should hopefully not
|
||||
cause anyone problems since it makes the matching work more like
|
||||
what people are expecting. (Wayne Davison)
|
||||
- Fixed a crash bug that might appear when --delete was used and
|
||||
multiple source directories were specified.
|
||||
|
||||
- A pattern with a "**" no longer causes a "*" to match slashes.
|
||||
For example, with "/*/foo/**", "foo" must be 2 levels deep.
|
||||
- Fixed a 32-bit truncation of the file length when generating the
|
||||
checksums.
|
||||
|
||||
- "**/foo" now matches at the base of the transfer (i.e. /foo).
|
||||
- The --backup code no longer attempts to create some directories
|
||||
over and over again (generating warnings along the way).
|
||||
|
||||
- An non-anchored wildcard term floats to match beyond the base of
|
||||
the transfer. E.g. "CVS/R*" matches at the end of the path,
|
||||
just like the non-wildcard term "CVS/Root" does.
|
||||
- Fixed a bug in the reading of the secrets file (by the daemon) and
|
||||
the password file (by the client): the files no longer need to be
|
||||
terminated by a newline for their content to be read in.
|
||||
|
||||
- Including a "**" in the match term causes it to be matched
|
||||
against the entire path, not just the name portion, even if
|
||||
there aren't any interior slashes in the term. E.g. "foo**bar"
|
||||
would exclude "/path/foo-bar" (just like before) as well as
|
||||
"/foo-path/baz-bar" (for instance).
|
||||
- If a file has a read error on the sending side or the reconstructed
|
||||
data doesn't match the expected checksum (perhaps due to the basis
|
||||
file changing during the transfer), the receiver will no longer
|
||||
retain the resulting file unless the --partial option was specified.
|
||||
(Note: for the read-error detection to work, neither side can be
|
||||
older than 2.6.3 -- older receivers will always retain the file, and
|
||||
older senders don't tell the receiver that the file had a read
|
||||
error.)
|
||||
|
||||
* The exclude list specified in the daemon's config file is now
|
||||
properly applied to the pulled items no matter how deep the
|
||||
user's file-args are in the source tree. (Wayne Davison)
|
||||
- If a file gets resent in a single transfer and the --backup option
|
||||
is enabled, rsync no longer performs a duplicate backup (it used to
|
||||
overwrite the original file in the backup area).
|
||||
|
||||
* For protocol version >= 27, mdfour_tail() is called when the
|
||||
block size (including checksum_seed) is a multiple of 64.
|
||||
Previously it was not called, giving the wrong MD4 checksum.
|
||||
(Craig Barratt)
|
||||
|
||||
* For protocol version >= 27, a 64 bit bit counter is used in
|
||||
mdfour.c as required by the RFC. Previously only a 32 bit bit
|
||||
counter was used, causing incorrect MD4 file checksums for
|
||||
file sizes >= 512MB - 4. (Craig Barratt)
|
||||
- Files specified in the daemon's "exclude" or "exclude from" config
|
||||
items are now excluded from being uploaded (assuming that the module
|
||||
allows uploading at all) in addition to the old download exclusion.
|
||||
|
||||
* Fixed a crash bug when interacting with older rsync versions and
|
||||
multiple files of the same name are destined for the same dir.
|
||||
(Wayne Davison)
|
||||
- Got rid of a potential hang in the receiver when near the end of a
|
||||
phase.
|
||||
|
||||
* Keep tmp names from overflowing MAXPATHLEN.
|
||||
- When using --backup without a --backup-dir, rsync no longer preserves
|
||||
the modify time on directories. This avoids confusing NFS.
|
||||
|
||||
* Make --link-dest honor the absence of -p, -o, and -g.
|
||||
- When --copy-links (-L) is specified, we now output a separate error
|
||||
for a symlink that has no referent instead of claiming that a file
|
||||
"vanished".
|
||||
|
||||
* Made rsync treat a trailing slash in the destination in a more
|
||||
consistent manner.
|
||||
- The --copy-links (-L) option no longer has the side-effect of telling
|
||||
the receiving side to follow symlinks. See the --keep-dirlinks
|
||||
option (mentioned below) for a way to specify that behavior.
|
||||
|
||||
* Fixed file I/O error detection. (John Van Essen)
|
||||
- Error messages from the daemon server's option-parsing (such as
|
||||
refused options) are now successfully transferred back to the client
|
||||
(the server used to fail to send the message because the socket
|
||||
wasn't in the right state for the message to get through).
|
||||
|
||||
* Fixed a compression (-z) bug when syncing a mostly-matching file
|
||||
that contains already-compressed data. (Yasuoka Masahiko and
|
||||
Wayne Davison)
|
||||
- Most transfer errors that occur during a daemon transfer are now
|
||||
returned to the user in addition to being logged (some messages are
|
||||
intended to be daemon-only and are not affected by this).
|
||||
|
||||
* Fixed a bug in the --backup code that could cause deleted files
|
||||
to not get backed up.
|
||||
- Fixed a bug in the daemon authentication code when using one of the
|
||||
batch-processing options.
|
||||
|
||||
* Call setgroups() in a more portable manner.
|
||||
- We try to work around some buggy IPv6 implementations that fail to
|
||||
implement IPV6_V6ONLY. This should fix the "address in use" error
|
||||
that some daemons get when running on an OS with a buggy IPv6
|
||||
implementation. Also, if the new code gets this error, we might
|
||||
suggest that the user specify --ipv4 or --ipv6 (if we think it will
|
||||
help).
|
||||
|
||||
* Improved file-related error messages to better indicate exactly
|
||||
what pathname failed. (Wayne Davison)
|
||||
- When the remote rsync dies, make a better effort to recover any error
|
||||
messages it may have sent before dying (the local rsync used to just
|
||||
die with a socket-write error).
|
||||
|
||||
* Fixed some bugs in the handling of --delete and --exclude when
|
||||
using the --relative (-R) option. (Wayne Davison)
|
||||
- When using --delete and a --backup-dir that contains files that are
|
||||
hard-linked to their destination equivalents, rsync now makes sure
|
||||
that removed files really get removed (avoids a really weird rename()
|
||||
behavior).
|
||||
|
||||
* Fixed bug that prevented regular files from replacing
|
||||
special files and caused a directory in --link-dest or
|
||||
--compare-dest to block the creation of a file with the
|
||||
same path. A directory still cannot be replaced by a
|
||||
regular file unless --delete specified. (J.W. Schultz)
|
||||
- Avoid a bogus run-time complaint about a lack of 64-bit integers when
|
||||
the int64 type is defined as an off_t and it actually has 64-bits.
|
||||
|
||||
* Detect and report when open or opendir succeed but read and
|
||||
readdir fail caused by network filesystems issues and truncated
|
||||
files. (David Norwood, Michael Brown, J.W. Schultz)
|
||||
- Added a configure check for open64() without mkstemp64() so that we
|
||||
can avoid using mkstemp() when such a combination is encountered.
|
||||
This bypasses a problem writing out large temp files on OSes such as
|
||||
AIX and HP-UX.
|
||||
|
||||
* Added a fix that should give ssh time to restore the tty settings
|
||||
if the user presses Ctrl-C at an ssh password prompt.
|
||||
- Fixed an age-old crash problem with --read-batch on a local copy
|
||||
(rsync was improperly assuming --whole-file for the local copy).
|
||||
|
||||
INTERNAL:
|
||||
- When --dry-run (-n) is used and the destination directory does not
|
||||
exist, rsync now produces a correct report of files that would be
|
||||
sent instead of dying with a chdir() error.
|
||||
|
||||
* Eliminated vestigial support for old versions that we stopped
|
||||
supporting. (J.W. Schultz)
|
||||
- Fixed a bug that could cause a slow-to-connect rsync daemon to die
|
||||
with an error instead of waiting for the connection to finish.
|
||||
|
||||
* Simplified some of the option-parsing code. (Wayne Davison)
|
||||
|
||||
* Some cleanup made to the exclude code, as well as some new
|
||||
defines added to enhance readability. (Wayne Davison)
|
||||
|
||||
* Changed the protocol-version code so that it can interact at a
|
||||
lower protocol level than the maximum supported by both sides.
|
||||
Added an undocumented option, --protocol=N, to force the value
|
||||
we advertise to the other side (primarily for testing purposes).
|
||||
(Wayne Davison)
|
||||
|
||||
|
||||
NEWS for rsync version 2.5.7:
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since version 2.5.6:
|
||||
|
||||
SECURITY:
|
||||
|
||||
* Fix buffer handling bugs. (Andrew Tridgell, Martin Pool, Paul
|
||||
Russell, Andrea Barisani)
|
||||
|
||||
|
||||
NEWS for rsync version 2.5.6, aka the dwd-between-jobs release
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since version 2.5.5:
|
||||
- Fixed an ssh interaction that could cause output to be lost when the
|
||||
user chose to combine the output of rsync's stdout and stderr (e.g.
|
||||
using the "2>&1").
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* The --delete-after option now implies --delete. (Wayne Davison)
|
||||
- Added the --partial-dir=DIR option that lets you specify where to
|
||||
(temporarily) put a partially transferred file (instead of over-
|
||||
writing the destination file). E.g. --partial-dir=.rsync-partial
|
||||
Also added support for the RSYNC_PARTIAL_DIR environment variable
|
||||
that, when found, transforms a regular --partial option (such as
|
||||
the convenient -P option) into one that also specifies a directory.
|
||||
|
||||
* The --suffix option can now be used with --backup-dir. (Michael
|
||||
Zimmerman)
|
||||
- Added --keep-dirlinks (-K), which allows you to symlink a directory
|
||||
onto another partition on the receiving side and have rsync treat it
|
||||
as matching a normal directory from the sender.
|
||||
|
||||
* Combining "::" syntax with the -rsh/-e option now uses the
|
||||
specified remote-shell as a transport to talk to a (newly-spawned)
|
||||
server-daemon. This allows someone to use daemon features, such
|
||||
as modules, over a secure protocol, such as ssh. (JD Paul)
|
||||
- Added the --inplace option that tells rsync to write each destination
|
||||
file without using a temporary file. The matching of existing data
|
||||
in the destination file can be severely limited by this, but there
|
||||
are also cases where this is more efficient (such as appending data).
|
||||
Use only when needed (see the man page for more details).
|
||||
|
||||
* The rsync:// syntax for daemon connections is now accepted in the
|
||||
destination field.
|
||||
- Added the "write only" option for the daemon's config file.
|
||||
|
||||
* If the file name given to --include-from or --exclude-from is "-",
|
||||
rsync will read from standard input. (J.W. Schultz)
|
||||
- Added long-option names for -4 and -6 (namely --ipv4 and --ipv6)
|
||||
and documented all these options in the man page.
|
||||
|
||||
* New option --link-dest which is like --compare-dest except that
|
||||
unchanged files are hard-linked in to the destination directory.
|
||||
(J.W. Schultz)
|
||||
- Improved the handling of the --bwlimit option so that it's less
|
||||
bursty, more accurate, and works properly over a larger range of
|
||||
values.
|
||||
|
||||
* Don't report an error if an excluded file disappears during an
|
||||
rsync run. (Eugene Chupriyanov and Bo Kersey)
|
||||
- The rsync daemon-over-ssh code now looks for SSH_CONNECTION and
|
||||
SSH2_CLIENT in addition to SSH_CLIENT to figure out the IP address.
|
||||
|
||||
* Added .svn to --cvs-exclude list to support subversion. (Jon
|
||||
Middleton)
|
||||
- Added the --checksum-seed=N option for advanced users.
|
||||
|
||||
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
|
||||
and "hosts deny" fields. (Hideaki Yoshifuji)
|
||||
- Batch writing/reading has a brand-new implementation that is simpler,
|
||||
fixes a few weird problems with the old code (such as no longer
|
||||
sprinkling the batch files into different dirs or even onto different
|
||||
systems), and is much less intrusive into the code (making it easier
|
||||
to maintain for the future). The new code generates just one data
|
||||
file instead of three, which makes it possible to read the batch on
|
||||
stdin via a remote shell. Also, the old requirement of forcing the
|
||||
same fixed checksum-seed for all batch processing has been removed.
|
||||
|
||||
* Changed exclude file handling to permit DOS or MAC style line
|
||||
terminations. (J.W. Schultz)
|
||||
- If an rsync daemon has a module set with "list = no" (which hides its
|
||||
presence in the list of available modules), a user that fails to
|
||||
authenticate gets the same "unknown module" error that they would get
|
||||
if the module were actually unknown (while still logging the real
|
||||
error to the daemon's log file). This prevents fishing for module
|
||||
names.
|
||||
|
||||
* Ignore errors from chmod when -p/-a/--preserve-perms is not set.
|
||||
(Dave Dykstra)
|
||||
- The daemon's "refuse options" config item now allows you to match
|
||||
option names using wildcards and/or the single-letter option names.
|
||||
|
||||
BUG FIXES:
|
||||
- Each transferred file now gets its permissions and modified-time
|
||||
updated before the temp-file gets moved into place. Previously, the
|
||||
finished file would have a very brief window where its permissions
|
||||
disallowed all group and world access.
|
||||
|
||||
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
|
||||
L. Allen, Martin Pool)
|
||||
- Added the ability to parse a literal IPv6 address in an "rsync:" URL
|
||||
(e.g. rsync://[2001:638:500:101::21]:873/module/dir).
|
||||
|
||||
* Generate each file's rolling-checksum data as we send it, not
|
||||
in a separate (memory-eating) pass before hand. This prevents
|
||||
timeout errors on really large files. (Stefan Nehlsen)
|
||||
|
||||
* Fix compilation on Tru64. (Albert Chin, Zoong Pham)
|
||||
|
||||
* Better handling of some client-server errors. (Martin Pool)
|
||||
|
||||
* Fixed a crash that would occur when sending a list of files that
|
||||
contains a duplicate name (if it sorts to the end of the file
|
||||
list) and using --delete. (Wayne Davison)
|
||||
|
||||
* Fixed the file-name duplicate-removal code when dealing with multiple
|
||||
dups in a row. (Wayne Davison)
|
||||
|
||||
* Fixed a bug that caused rsync to lose the exit status of its child
|
||||
processes and sometimes return an exit code of 0 instead of showing
|
||||
an error. (David R. Staples, Dave Dykstra)
|
||||
|
||||
* Fixed bug in --copy-unsafe-links that caused it to be completely
|
||||
broken. (Dave Dykstra)
|
||||
|
||||
* Prevent infinite recursion in cleanup code under certain circumstances.
|
||||
(Sviatoslav Sviridov and Marc Espie)
|
||||
|
||||
* Fixed a bug that prevented rsync from creating intervening directories
|
||||
when --relative-paths/-R is set. (Craig Barratt)
|
||||
|
||||
* Prevent "Connection reset by peer" messages from Cygwin. (Randy O'Meara)
|
||||
- The daemon's wildcard expanding code can now handle more than 1000
|
||||
filenames (it's now limited by memory instead of having a hard-wired
|
||||
limit).
|
||||
|
||||
INTERNAL:
|
||||
|
||||
* Many code cleanups and improved internal documentation. (Martin
|
||||
Pool, Nelson Beebe)
|
||||
- Some cleanup in the exclude code has saved some per-exclude memory
|
||||
and made the code easier to maintain.
|
||||
|
||||
* Portability fixes. (Dave Dykstra and Wayne Davison)
|
||||
- Improved the argv-overflow checking for a remote command that has a
|
||||
lot of args.
|
||||
|
||||
* More test cases. (Martin Pool)
|
||||
- Use rsyserr() in the various places that were still calling rprintf()
|
||||
with strerror() as an arg.
|
||||
|
||||
* Some test-case fixes. (Brian Poole, Wayne Davison)
|
||||
- If an rsync daemon is listening on multiple sockets (to handle both
|
||||
IPv4 and IPv6 to a single port), we now close all the unneeded file
|
||||
handles after we accept a connection (we used to close just one of
|
||||
them).
|
||||
|
||||
* Updated included popt to the latest vendor drop, version 1.6.4.
|
||||
(Jos Backus)
|
||||
- Optimized the handling of larger block sizes (rsync used to slow to a
|
||||
crawl if the block size got too large).
|
||||
|
||||
- Optimized away a loop in hash_search().
|
||||
|
||||
- Some improvements to the sanitize_path() and clean_fname() functions
|
||||
makes them more efficient and produce better results (while still
|
||||
being compatible with the file-name cleaning that gets done on both
|
||||
sides when sending the file-list).
|
||||
|
||||
- Got rid of alloc_sanitize_path() after adding a destination-buffer
|
||||
arg to sanitize_path() made it possible to put all the former's
|
||||
functionality into the latter.
|
||||
|
||||
- The file-list that is output when at least 4 verbose options are
|
||||
specified reports the uid value on the sender even when rsync is
|
||||
not running as root (since we might be sending to a root receiver).
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Added a "gen" target to rebuild most of the generated files,
|
||||
including configure, config.h.in, the man pages, and proto.h.
|
||||
|
||||
- If "make proto" doesn't find some changes in the prototypes, the
|
||||
proto.h file is left untouched (its time-stamp used to always be
|
||||
updated).
|
||||
|
||||
- The variable $STRIP (that is optionally set by the install-strip
|
||||
target's rule) was changed to $INSTALL_STRIP because some systems
|
||||
have $STRIP already set in the environment.
|
||||
|
||||
- Fixed a build problem when SUPPORT_HARD_LINKS isn't defined.
|
||||
|
||||
- When cross-compiling, the gettimeofday() function is now assumed to
|
||||
be a modern version that takes two-args (since we can't test it).
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The scripts in the testsuite dir were cleaned up a bit and a few
|
||||
new tests added.
|
||||
|
||||
- Some new diffs were added to the patches dir, and some accepted
|
||||
ones were removed.
|
||||
|
||||
* Updated config.guess and config.sub to latest versions; this
|
||||
means rsync should build on more platforms. (Paul Green)
|
||||
|
||||
629
OLDNEWS
629
OLDNEWS
@@ -1,5 +1,489 @@
|
||||
rsync 2.5.5 "Snowy River" (2 April 2002)
|
||||
protocol: 26 (unchanged)
|
||||
NEWS for rsync 2.6.2 (30 Apr 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.1:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a major bug in the sorting of the filenames when --relative
|
||||
is used for some sources (just sources such as "/" and "/*" were
|
||||
affected). This fix ensures that we ask for the right file-list
|
||||
item when requesting changes from the sender.
|
||||
|
||||
- Rsync now checks the return value of the close() function to
|
||||
better report disk-full problems on an NFS file system.
|
||||
|
||||
- Restored the old daemon-server behavior of logging error messages
|
||||
rather than returning them to the user. (A better long-term fix
|
||||
will be sought in the future.)
|
||||
|
||||
- An obscure uninitialized-variable bug was fixed in the uid/gid
|
||||
code. (This bug probably had no ill effects.)
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Got rid of the configure check for sys/sysctl.h (it wasn't used
|
||||
and was causing a problem on some systems). Also improved the
|
||||
broken-largefile-locking test to try to avoid failure due to an
|
||||
NFS build-dir.
|
||||
|
||||
- Fixed a compile problem on systems that don't define
|
||||
AI_NUMERICHOST.
|
||||
|
||||
- Fixed a compile problem in the popt source for compilers that
|
||||
don't support __attribute__.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Improved the testsuite's "merge" test to work on OSF1.
|
||||
|
||||
- Two new diffs were added to the patches dir.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.1 (26 Apr 2004)
|
||||
Protocol: 28 (changed)
|
||||
Changes since 2.6.0:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
- Paths sent to an rsync daemon are more thoroughly sanitized when
|
||||
chroot is not used. If you're running a non-read-only rsync
|
||||
daemon with chroot disabled, *please upgrade*, ESPECIALLY if the
|
||||
user privs you run rsync under is anything above "nobody".
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Lower memory use, more optimal transfer of data over the socket,
|
||||
and lower CPU usage (see the INTERNAL section for details).
|
||||
|
||||
- The RSYNC_PROXY environment variable can now contain a
|
||||
"USER:PASS@" prefix before the "HOST:PORT" information.
|
||||
(Bardur Arantsson)
|
||||
|
||||
- The --progress output now mentions how far along in the transfer
|
||||
we are, including both a count of files transferred and a
|
||||
percentage of the total file-count that we've processed. It also
|
||||
shows better current-rate-of-transfer and remaining-transfer-time
|
||||
values.
|
||||
|
||||
- Documentation changes now attempt to describe some often mis-
|
||||
understood features more clearly.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- When -x (--one-file-system) is combined with -L (--copy-links) or
|
||||
--copy-unsafe-links, no symlinked files are skipped, even if the
|
||||
referent file is on a different filesystem.
|
||||
|
||||
- The --link-dest code now works properly for a non-root user when
|
||||
(1) the UIDs of the source and destination differ and -o was
|
||||
specified, or (2) when the group of the source can't be used on
|
||||
the destination and -g was specified.
|
||||
|
||||
- Fixed a bug in the handling of -H (hard-links) that might cause
|
||||
the expanded PATH/NAME value of the current item to get
|
||||
overwritten (due to an expanded-name caching bug).
|
||||
|
||||
- We now reset the "new data has been sent" flag at the start of
|
||||
each file we send. This makes sure that an interrupted transfer
|
||||
with the --partial option set doesn't keep a shorter temp file
|
||||
than the current basis file when no new data has been transfered
|
||||
over the wire for that file.
|
||||
|
||||
- Fixed a byte-order problem in --batch-mode on big-endian machines.
|
||||
(Jay Fenlason)
|
||||
|
||||
- When using --cvs-exclude, the exclude items we get from a
|
||||
per-directory's .cvsignore file once again only affect that one
|
||||
directory (not all following directories too). The items are also
|
||||
now properly word-split and parsed without any +/- prefix parsing.
|
||||
|
||||
- When specifying the USER@HOST: prefix for a file, the USER part
|
||||
can now contain an '@', if needed (i.e. the last '@' is used to
|
||||
find the HOST, not the first).
|
||||
|
||||
- Fixed some bugs in the handling of group IDs for non-root users:
|
||||
(1) It properly handles a group that the sender didn't have a name
|
||||
for (it would previously skip changing the group on any files in
|
||||
that group). (2) If --numeric-ids is used, rsync no longer
|
||||
attempts to set groups that the user doesn't have the permission
|
||||
to set.
|
||||
|
||||
- Fixed the "refuse options" setting in the rsyncd.conf file.
|
||||
|
||||
- Improved the -x (--one-file-system) flag's handling of any mount-
|
||||
point directories we encounter. It is both more optimal (in that
|
||||
it no longer does a useless scan of the contents of the mount-
|
||||
point dirs) and also fixes a bug where a remapped mount of the
|
||||
original filesystem could get discovered in a subdir we should be
|
||||
ignoring.
|
||||
|
||||
- Rsync no longer discards a double-slash at the start of a filename
|
||||
when trying to open the file. It also no longer constructs names
|
||||
that start with a double slash (unless the user supplied them).
|
||||
|
||||
- Path-specifying options to a daemon should now work the same with
|
||||
or without chroot turned on. Previously, such a option (such as
|
||||
--link-dest) would get its absolute path munged into a relative
|
||||
one if chroot was not on, making that setting fairly useless.
|
||||
Rsync now transforms the path into one that is based on the
|
||||
module's base dir when chroot is not enabled.
|
||||
|
||||
- Fixed a compatibility problem interacting with older rsync
|
||||
versions that might send us an empty --suffix value without
|
||||
telling us that --backup-dir was specified.
|
||||
|
||||
- The "hosts allow" option for a daemon-over-remote-shell process
|
||||
now has improved support for IPv6 addresses and a fix for systems
|
||||
that have a length field in their socket structs.
|
||||
|
||||
- Fixed the ability to request an empty backup --suffix when sending
|
||||
files to an rsync daemon.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Most of the I/O is now buffered, which results in a pretty large
|
||||
speedup when running under MS Windows. (Craig Barratt)
|
||||
|
||||
- Optimizations to the name-handling/comparing code have made some
|
||||
significant reductions in user-CPU time for large file sets.
|
||||
|
||||
- Some cleanup of the variable types make the code more consistent.
|
||||
|
||||
- Reduced memory requirements of hard link preservation.
|
||||
(J.W. Schultz)
|
||||
|
||||
- Implemented a new algorithm for hard-link handling that speeds up
|
||||
the code significantly. (J.W. Schultz and Wayne Davison)
|
||||
|
||||
- The --hard-link option now uses the first existing file in the
|
||||
group of linked files as the basis for the transfer. This
|
||||
prevents the sub-optimal transfer of a file's data when a new
|
||||
hardlink is added on the sending side and it sorts alphabetically
|
||||
earlier in the list than the files that are already present on the
|
||||
receiving side.
|
||||
|
||||
- Dropped support for protocol versions less than 20 (2.3.0 released
|
||||
15 Mar 1999) and activated warnings for protocols less than 25
|
||||
(2.5.0 released 23 Aug 2001). (Wayne Davison and J.W. Schultz,
|
||||
severally)
|
||||
|
||||
- More optimal data transmission for --hard-links (protocol 28).
|
||||
|
||||
- More optimal data transmission for --checksum (protocol 28).
|
||||
|
||||
- Less memory is used when --checksum is specified.
|
||||
|
||||
- Less memory is used in the file list (a per-file savings).
|
||||
|
||||
- The generator is now better about not modifying the file list
|
||||
during the transfer in order to avoid a copy-on-write memory
|
||||
bifurcation (on systems where fork() uses shared memory).
|
||||
Previously, rsync's shared memory would slowly become unshared,
|
||||
resulting in real memory usage nearly doubling on the receiving
|
||||
side by the end of the transfer. Now, as long as permissions
|
||||
are being preserved, the shared memory should remain that way
|
||||
for the entire transfer.
|
||||
|
||||
- Changed hardlink info and file_struct + strings to use allocation
|
||||
pools. This reduces memory use for large file-sets and permits
|
||||
freeing memory to the OS. (J.W. Schultz)
|
||||
|
||||
- The 2 pipes used between the receiver and generator processes
|
||||
(which are forked on the same machine) were reduced to 1 pipe and
|
||||
the protocol improved so that (1) it is now impossible to have the
|
||||
"redo" pipe fill up and hang rsync, and (2) trailing messages from
|
||||
the receiver don't get lost on their way through the generator
|
||||
over to the sender (which mainly affected hard-link messages and
|
||||
verbose --stats output).
|
||||
|
||||
- Improved the internal uid/gid code to be more portable and a
|
||||
little more optimized.
|
||||
|
||||
- The device numbers sent when using --devices are now sent as
|
||||
separate major/minor values with 32-bit accuracy (protocol 28).
|
||||
Previously, the copied devices were sent as a single 32-bit
|
||||
number. This will make inter-operation of 64-bit binaries more
|
||||
compatible with their 32-bit brethren (with both ends of the
|
||||
connection are using protocol 28). Note that optimizations in the
|
||||
binary protocol for sending the device numbers often results in
|
||||
fewer bytes being used than before, even though more precision is
|
||||
now available.
|
||||
|
||||
- Some cleanup of the exclude/include structures and its code made
|
||||
things clearer (internally), simpler, and more efficient.
|
||||
|
||||
- The reading & writing of the file-list in batch-mode is now
|
||||
handled by the same code that sends & receives the list over the
|
||||
wire. This makes it much easier to maintain. (Note that the
|
||||
batch code is still considered to be experimental.)
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- The configure script now accepts --with-rsyncd-conf=PATH to
|
||||
override the default value of the /etc/rsyncd.conf file.
|
||||
|
||||
- Fixed configure bug when running "./configure --disable-ipv6".
|
||||
|
||||
- Fixed compilation problem on Tru64 Unix (having to do with
|
||||
sockaddr.sa_len and sockaddr.sin_len).
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Fixed "make test" bug when build dir is not the source dir.
|
||||
|
||||
- Added a couple extra diffs in the "patches" dir, removed the ones
|
||||
that got applied, and rebuilt the rest.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.0 (1 Jan 2004)
|
||||
Protocol: 27 (changed)
|
||||
Changes since 2.5.7:
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* "ssh" is now the default remote shell for rsync. If you want to
|
||||
change this, configure like this: "./configure --with-rsh=rsh".
|
||||
|
||||
* Added --files-from, --no-relative, --no-implied-dirs, and --from0.
|
||||
Note that --from0 affects the line-ending character for all the
|
||||
files read by the --*-from options. (Wayne Davison)
|
||||
|
||||
* Length of csum2 is now per-file starting with protocol version
|
||||
27. (J.W. Schultz)
|
||||
|
||||
* Per-file dynamic block size is now sqrt(file length). The
|
||||
per-file checksum size is determined according to an algorithm
|
||||
provided by Donovan Baarda which reduces the probability of rsync
|
||||
algorithm corrupting data and falling back using the whole md4
|
||||
checksums. (J.W. Schultz, Donovan Baarda)
|
||||
|
||||
* The --stats option no longer includes the (debug) malloc summary
|
||||
unless the verbose option was specified at least twice.
|
||||
|
||||
* Added a new error/warning code for when files vanish from the
|
||||
sending side. Made vanished source files not interfere with the
|
||||
file-deletion pass when --delete-after was specified.
|
||||
|
||||
* Various trailing-info sections are now preceded by a newline.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fixed several exclude/include matching bugs when using wild-cards.
|
||||
This has a several user-visible effects, all of which make the
|
||||
matching more consistent and intuitive. This should hopefully not
|
||||
cause anyone problems since it makes the matching work more like
|
||||
what people are expecting. (Wayne Davison)
|
||||
|
||||
- A pattern with a "**" no longer causes a "*" to match slashes.
|
||||
For example, with "/*/foo/**", "foo" must be 2 levels deep.
|
||||
[If your string has BOTH "*" and "**" wildcards, changing the
|
||||
"*" wildcards to "**" will provide the old behavior in all
|
||||
versions.]
|
||||
|
||||
- "**/foo" now matches at the base of the transfer (like /foo
|
||||
does). [Use "/**/foo" to get the old behavior in all versions.]
|
||||
|
||||
- A non-anchored wildcard term floats to match beyond the base of
|
||||
the transfer. E.g. "CVS/R*" matches at the end of the path,
|
||||
just like the non-wildcard term "CVS/Root" does. [Use "/CVS/R*"
|
||||
to get the old behavior in all versions.]
|
||||
|
||||
- Including a "**" in the match term causes it to be matched
|
||||
against the entire path, not just the name portion, even if
|
||||
there aren't any interior slashes in the term. E.g. "foo**bar"
|
||||
would exclude "/path/foo-bar" (just like before) as well as
|
||||
"/foo-path/baz-bar" (unlike before). [Use "foo*bar" to get the
|
||||
old behavior in all versions.]
|
||||
|
||||
* The exclude list specified in the daemon's config file is now
|
||||
properly applied to the pulled items no matter how deep the
|
||||
user's file-args are in the source tree. (Wayne Davison)
|
||||
|
||||
* For protocol version >= 27, mdfour_tail() is called when the
|
||||
block size (including checksum_seed) is a multiple of 64.
|
||||
Previously it was not called, giving the wrong MD4 checksum.
|
||||
(Craig Barratt)
|
||||
|
||||
* For protocol version >= 27, a 64 bit bit counter is used in
|
||||
mdfour.c as required by the RFC. Previously only a 32 bit bit
|
||||
counter was used, causing incorrect MD4 file checksums for
|
||||
file sizes >= 512MB - 4. (Craig Barratt)
|
||||
|
||||
* Fixed a crash bug when interacting with older rsync versions and
|
||||
multiple files of the same name are destined for the same dir.
|
||||
(Wayne Davison)
|
||||
|
||||
* Keep tmp names from overflowing MAXPATHLEN.
|
||||
|
||||
* Make --link-dest honor the absence of -p, -o, and -g.
|
||||
|
||||
* Made rsync treat a trailing slash in the destination in a more
|
||||
consistent manner.
|
||||
|
||||
* Fixed file I/O error detection. (John Van Essen)
|
||||
|
||||
* Fixed bogus "malformed address {hostname}" message in rsyncd log
|
||||
when checking IP address against hostnames from "hosts allow"
|
||||
and "hosts deny" parameters in config file.
|
||||
|
||||
* Print heap statistics when verbose >= 2 instead of when >= 1.
|
||||
|
||||
* Fixed a compression (-z) bug when syncing a mostly-matching file
|
||||
that contains already-compressed data. (Yasuoka Masahiko and
|
||||
Wayne Davison)
|
||||
|
||||
* Fixed a bug in the --backup code that could cause deleted files
|
||||
to not get backed up.
|
||||
|
||||
* When the backup code makes new directories, create them with mode
|
||||
0700 instead of 0755 (since the directory permissions in the
|
||||
backup tree are not yet copied from the main tree).
|
||||
|
||||
* Call setgroups() in a more portable manner.
|
||||
|
||||
* Improved file-related error messages to better indicate exactly
|
||||
what pathname failed. (Wayne Davison)
|
||||
|
||||
* Fixed some bugs in the handling of --delete and --exclude when
|
||||
using the --relative (-R) option. (Wayne Davison)
|
||||
|
||||
* Fixed bug that prevented regular files from replacing
|
||||
special files and caused a directory in --link-dest or
|
||||
--compare-dest to block the creation of a file with the
|
||||
same path. A directory still cannot be replaced by a
|
||||
regular file unless --delete specified. (J.W. Schultz)
|
||||
|
||||
* Detect and report when open or opendir succeed but read and
|
||||
readdir fail caused by network filesystem issues and truncated
|
||||
files. (David Norwood, Michael Brown, J.W. Schultz)
|
||||
|
||||
* Added a fix that should give ssh time to restore the tty settings
|
||||
if the user presses Ctrl-C at an ssh password prompt.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
* Eliminated vestigial support for old versions that we stopped
|
||||
supporting. (J.W. Schultz)
|
||||
|
||||
* Simplified some of the option-parsing code. (Wayne Davison)
|
||||
|
||||
* Some cleanup made to the exclude code, as well as some new
|
||||
defines added to enhance readability. (Wayne Davison)
|
||||
|
||||
* Changed the protocol-version code so that it can interact at a
|
||||
lower protocol level than the maximum supported by both sides.
|
||||
Added an undocumented option, --protocol=N, to force the value
|
||||
we advertise to the other side (primarily for testing purposes).
|
||||
(Wayne Davison)
|
||||
|
||||
|
||||
NEWS for rsync 2.5.7 (4 Dec 2003)
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since 2.5.6:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
* Fix buffer handling bugs. (Andrew Tridgell, Martin Pool, Paul
|
||||
Russell, Andrea Barisani)
|
||||
|
||||
|
||||
NEWS for rsync 2.5.6, aka "the dwd-between-jobs release" (26 Jan 2003)
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since 2.5.5:
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* The --delete-after option now implies --delete. (Wayne Davison)
|
||||
|
||||
* The --suffix option can now be used with --backup-dir. (Michael
|
||||
Zimmerman)
|
||||
|
||||
* Combining "::" syntax with the -rsh/-e option now uses the
|
||||
specified remote-shell as a transport to talk to a (newly-spawned)
|
||||
server-daemon. This allows someone to use daemon features, such
|
||||
as modules, over a secure protocol, such as ssh. (JD Paul)
|
||||
|
||||
* The rsync:// syntax for daemon connections is now accepted in the
|
||||
destination field.
|
||||
|
||||
* If the file name given to --include-from or --exclude-from is "-",
|
||||
rsync will read from standard input. (J.W. Schultz)
|
||||
|
||||
* New option --link-dest which is like --compare-dest except that
|
||||
unchanged files are hard-linked in to the destination directory.
|
||||
(J.W. Schultz)
|
||||
|
||||
* Don't report an error if an excluded file disappears during an
|
||||
rsync run. (Eugene Chupriyanov and Bo Kersey)
|
||||
|
||||
* Added .svn to --cvs-exclude list to support subversion. (Jon
|
||||
Middleton)
|
||||
|
||||
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
|
||||
and "hosts deny" fields. (Hideaki Yoshifuji)
|
||||
|
||||
* Changed exclude file handling to permit DOS or MAC style line
|
||||
terminations. (J.W. Schultz)
|
||||
|
||||
* Ignore errors from chmod when -p/-a/--preserve-perms is not set.
|
||||
(Dave Dykstra)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
|
||||
L. Allen, Martin Pool)
|
||||
|
||||
* Generate each file's rolling-checksum data as we send it, not
|
||||
in a separate (memory-eating) pass before hand. This prevents
|
||||
timeout errors on really large files. (Stefan Nehlsen)
|
||||
|
||||
* Fix compilation on Tru64. (Albert Chin, Zoong Pham)
|
||||
|
||||
* Better handling of some client-server errors. (Martin Pool)
|
||||
|
||||
* Fixed a crash that would occur when sending a list of files that
|
||||
contains a duplicate name (if it sorts to the end of the file
|
||||
list) and using --delete. (Wayne Davison)
|
||||
|
||||
* Fixed the file-name duplicate-removal code when dealing with multiple
|
||||
dups in a row. (Wayne Davison)
|
||||
|
||||
* Fixed a bug that caused rsync to lose the exit status of its child
|
||||
processes and sometimes return an exit code of 0 instead of showing
|
||||
an error. (David R. Staples, Dave Dykstra)
|
||||
|
||||
* Fixed bug in --copy-unsafe-links that caused it to be completely
|
||||
broken. (Dave Dykstra)
|
||||
|
||||
* Prevent infinite recursion in cleanup code under certain circumstances.
|
||||
(Sviatoslav Sviridov and Marc Espie)
|
||||
|
||||
* Fixed a bug that prevented rsync from creating intervening directories
|
||||
when --relative-paths/-R is set. (Craig Barratt)
|
||||
|
||||
* Prevent "Connection reset by peer" messages from Cygwin. (Randy O'Meara)
|
||||
|
||||
INTERNAL:
|
||||
|
||||
* Many code cleanups and improved internal documentation. (Martin
|
||||
Pool, Nelson Beebe)
|
||||
|
||||
* Portability fixes. (Dave Dykstra and Wayne Davison)
|
||||
|
||||
* More test cases. (Martin Pool)
|
||||
|
||||
* Some test-case fixes. (Brian Poole, Wayne Davison)
|
||||
|
||||
* Updated included popt to the latest vendor drop, version 1.6.4.
|
||||
(Jos Backus)
|
||||
|
||||
* Updated config.guess and config.sub to latest versions; this
|
||||
means rsync should build on more platforms. (Paul Green)
|
||||
|
||||
|
||||
NEWS for rsync 2.5.5, aka Snowy River (2 Apr 2002)
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since 2.5.4:
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
@@ -38,16 +522,15 @@ protocol: 26 (unchanged)
|
||||
* Improved network error handling. (Greg A. Woods)
|
||||
|
||||
|
||||
rsync 2.5.4 (13 March 2002)
|
||||
protocol: 26 (unchanged)
|
||||
|
||||
"Imitation lizard skin"
|
||||
NEWS for rsync 2.5.4, aka "Imitation lizard skin" (13 Mar 2002)
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since 2.5.3:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Additional fix for zlib double-free bug. (Martin Pool, Andrew
|
||||
Tridgell) (CVE CAN-2002-0059)
|
||||
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
* Merge in changes from zlib 1.1.3 to zlib 1.1.4. (Jos Backus)
|
||||
@@ -57,10 +540,9 @@ protocol: 26 (unchanged)
|
||||
* Additional test cases for --compress. (Martin Pool)
|
||||
|
||||
|
||||
rsync 2.5.3 (11 March 2002)
|
||||
protocol: 26 (unchanged)
|
||||
|
||||
"Happy 26"
|
||||
NEWS for rsync 2.5.3, aka "Happy 26" (11 Mar 2002)
|
||||
Protocol: 26 (unchanged)
|
||||
Changes since 2.5.2:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
@@ -73,7 +555,7 @@ protocol: 26 (unchanged)
|
||||
* Fix zlib double-free bug. (Owen Taylor, Mark J Cox) (CVE
|
||||
CAN-2002-0059)
|
||||
|
||||
* Fixed problem that in many cases caused the error message
|
||||
* Fixed problem that in many cases caused the error message
|
||||
unexpected read size of 0 in map_ptr
|
||||
and resulted in the wrong data being copied.
|
||||
|
||||
@@ -94,7 +576,7 @@ protocol: 26 (unchanged)
|
||||
* Merge in changes from zlib 1.1.2 to zlib 1.1.3. (Note that
|
||||
rsync still uses a custom version of zlib; you can not just link
|
||||
against a system library. See zlib/README.rsync)
|
||||
|
||||
|
||||
* Command to initiate connections is only shown with -vv, rather
|
||||
than -v as in 2.5.2. Output from plain -v is more similar to
|
||||
what was historically used so as not to break scripts that try
|
||||
@@ -108,8 +590,10 @@ protocol: 26 (unchanged)
|
||||
* If the daemon is unable to fork a child to accept a connection,
|
||||
print an error message. (Colin Walters)
|
||||
|
||||
rsync 2.5.2 (26 Jan 2002)
|
||||
protocol: 26 (changed)
|
||||
|
||||
NEWS for rsync 2.5.2 (26 Jan 2002)
|
||||
Protocol: 26 (changed)
|
||||
Changes since 2.5.1:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
@@ -136,7 +620,7 @@ protocol: 26 (changed)
|
||||
connection.
|
||||
|
||||
* --statistics now shows memory heap usage on platforms that
|
||||
support mallinfo().
|
||||
support mallinfo().
|
||||
|
||||
* "The Ted T'so school of program optimization": make progress
|
||||
visible and people will think it's faster. (With --progress,
|
||||
@@ -145,15 +629,17 @@ protocol: 26 (changed)
|
||||
|
||||
* Improvements to batch mode support. This is still experimental
|
||||
but testing would be welcome. (Jos Backus)
|
||||
|
||||
|
||||
* New --ignore-existing option, patch previously distributed with
|
||||
Vipul's Razor. (Debian #124286)
|
||||
|
||||
rsync 2.5.1 (2002-01-03)
|
||||
protocol: 25 (unchanged)
|
||||
|
||||
NEWS for rsync 2.5.1 (3 Jan 2002)
|
||||
Protocol: 25 (unchanged)
|
||||
Changes since 2.5.0:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* Fix for segfault in --daemon mode configuration parser. (Paul
|
||||
Mackerras)
|
||||
|
||||
@@ -175,18 +661,19 @@ protocol: 25 (unchanged)
|
||||
ENHANCEMENTS:
|
||||
|
||||
* --progress and -P now show estimated data transfer rate (in a
|
||||
multiple of bytes/s) and estimated time to completion. (Rik
|
||||
Faith)
|
||||
|
||||
multiple of bytes/s) and estimated time to completion. (Rik
|
||||
Faith)
|
||||
|
||||
* --no-detach option, required to run as a W32 service and also
|
||||
useful when running on Unix under daemontools, AIX's SRC, or a
|
||||
debugger. (Max Bowsher, Jos Backus)
|
||||
useful when running on Unix under daemontools, AIX's SRC, or a
|
||||
debugger. (Max Bowsher, Jos Backus)
|
||||
|
||||
* Clearer error messages for some conditions.
|
||||
|
||||
|
||||
rsync 2.5.0 (2001-11-30)
|
||||
protocol: 25 (changed)
|
||||
NEWS for rsync 2.5.0 (30 Nov 2001)
|
||||
Protocol: 25 (changed)
|
||||
Changes since 2.4.6:
|
||||
|
||||
ANNOUNCEMENTS
|
||||
|
||||
@@ -248,7 +735,7 @@ protocol: 25 (changed)
|
||||
* Attempt to fix error handling lockup bug.
|
||||
|
||||
* Give a non-0 exit code if *any* of the files we have been asked
|
||||
to transfer fail to transfer
|
||||
to transfer fail to transfer.
|
||||
|
||||
* For log messages containing ridiculously long strings that might
|
||||
overflow a buffer rsync no longer aborts, but rather prints an
|
||||
@@ -259,7 +746,7 @@ protocol: 25 (changed)
|
||||
* Improved support for UNICOS (tested on Cray T3E and Cray SV1)
|
||||
|
||||
* autoconf2.52 (or later) is now required to rebuild the autoconf
|
||||
scripts. It is not required to simply build rsync.
|
||||
scripts. It is not required to simply build rsync.
|
||||
|
||||
* Platforms thought to work in this release:
|
||||
|
||||
@@ -302,41 +789,49 @@ protocol: 25 (changed)
|
||||
build farm.
|
||||
|
||||
Partial Protocol History
|
||||
DATE RELEASE PROTOCOL
|
||||
2003/01/26 20:11:16 release-2-5-6 26
|
||||
2002/02/23 00:17:50 release-2-5-3 26
|
||||
2002/01/25 23:00:21 release-2-5-2 26
|
||||
2001/12/18 06:47:40 release-2-5-1 25
|
||||
release-2-4-6 24
|
||||
2000/08/16 08:34:18 release-2-4-5 24
|
||||
2000/07/29 04:52:05 release-2-4-4 24
|
||||
2000/03/30 14:15:00 release-2-4-2 24
|
||||
2000/01/29 23:49:36 release-2-4-1 24
|
||||
2000/01/29 02:56:37 release-2-4-0 23
|
||||
release-2-3-3 21
|
||||
1999/06/26 01:06:38 release-2-3-2 21
|
||||
release-2-3-1 20
|
||||
1999/03/15 21:17:59 release-2-3-0 20
|
||||
1998/11/15 01:21:42 release-2-2-1 19
|
||||
1998/11/03 07:08:28 release-2-2-0 19
|
||||
1998/09/09 06:31:14 release-2-1-1 19
|
||||
1998/07/17 14:43:05 release-2-0-19 19
|
||||
1998/06/18 12:17:24 release-2-0-18 19
|
||||
1998/06/18 09:51:56 release-2-0-17 19
|
||||
1998/06/01 03:42:22 release-2-0-16 19
|
||||
1998/05/27 13:47:34 release-2-0-13 19
|
||||
1998/05/26 14:19:00 release-2-0-12 18
|
||||
1998/05/21 05:55:33 release-2-0-11 18
|
||||
1998/05/18 08:20:34 release-2-0-9 18
|
||||
1998/05/17 05:56:33 release-2-0-8 17
|
||||
1998/05/15 07:34:21 release-2-0-2 17
|
||||
1998/05/13 15:44:11 release-2-0-0 17
|
||||
1998/04/17 06:07:26 release-1-7-4 17
|
||||
1998/04/05 06:43:55 release-1-7-2 17
|
||||
1998/03/26 04:18:57 release-1-7-0 17 MAX=30
|
||||
1998/01/13 15:57:32 release-1-6-9 15 MAX=20
|
||||
1997/12/17 11:07:30 release-1-6-7 14
|
||||
1997/12/15 18:36:21 release-1-6-4 14
|
||||
RELEASE DATE VER. DATE OF COMMIT PROTOCOL
|
||||
30 Sep 2004 2.6.3 28
|
||||
30 Apr 2004 2.6.2 28
|
||||
26 Apr 2004 2.6.1 08 Jan 2004 28
|
||||
01 Jan 2004 2.6.0 10 Apr 2003 27 (MAX=40)
|
||||
04 Dec 2003 2.5.7 26
|
||||
26 Jan 2003 2.5.6 26
|
||||
02 Apr 2002 2.5.5 26
|
||||
13 Mar 2002 2.5.4 26
|
||||
11 Mar 2002 2.5.3 26
|
||||
26 Jan 2002 2.5.2 11 Jan 2002 26
|
||||
03 Jan 2002 2.5.1 25
|
||||
30 Nov 2001 2.5.0 23 Aug 2001 25
|
||||
06 Sep 2000 2.4.6 24
|
||||
19 Aug 2000 2.4.5 24
|
||||
29 Jul 2000 2.4.4 24
|
||||
09 Apr 2000 2.4.3 24
|
||||
30 Mar 2000 2.4.2 24
|
||||
30 Jan 2000 2.4.1 29 Jan 2000 24
|
||||
29 Jan 2000 2.4.0 28 Jan 2000 23
|
||||
25 Jan 2000 2.3.3 23 Jan 2000 22
|
||||
08 Nov 1999 2.3.2 26 Jun 1999 21
|
||||
06 Apr 1999 2.3.1 20
|
||||
15 Mar 1999 2.3.0 15 Mar 1999 20
|
||||
25 Nov 1998 2.2.1 19
|
||||
03 Nov 1998 2.2.0 19
|
||||
09 Sep 1998 2.1.1 19
|
||||
20 Jul 1998 2.1.0 19
|
||||
17 Jul 1998 2.0.19 19
|
||||
18 Jun 1998 2.0.17 19
|
||||
01 Jun 1998 2.0.16 19
|
||||
27 May 1998 2.0.13 27 May 1998 19
|
||||
26 May 1998 2.0.12 18
|
||||
22 May 1998 2.0.11 18
|
||||
18 May 1998 2.0.9 18 May 1998 18
|
||||
17 May 1998 2.0.8 17
|
||||
15 May 1998 2.0.1 17
|
||||
14 May 1998 2.0.0 17
|
||||
17 Apr 1998 1.7.4 17
|
||||
13 Apr 1998 1.7.3 17
|
||||
05 Apr 1998 1.7.2 17
|
||||
26 Mar 1998 1.7.1 17
|
||||
26 Mar 1998 1.7.0 26 Mar 1998 17 (MAX=30)
|
||||
13 Jan 1998 1.6.9 13 Jan 1998 15 (MAX=20)
|
||||
|
||||
* DATE OF COMMIT is the date the protocl change was committed
|
||||
to cvs, not the release date.
|
||||
* DATE OF COMMIT is the date the protocol change was committed to CVS.
|
||||
|
||||
11
README
11
README
@@ -29,9 +29,9 @@ and see the manual for more information.
|
||||
SETUP
|
||||
-----
|
||||
|
||||
Rsync normally uses rsh or ssh for communication. It does not need to
|
||||
Rsync normally uses ssh or rsh for communication. It does not need to
|
||||
be setuid and requires no special privileges for installation. You
|
||||
must, however, have a working rsh or ssh system. Using ssh is
|
||||
must, however, have a working ssh or rsh system. Using ssh is
|
||||
recommended for its security features.
|
||||
|
||||
Alternatively, rsync can run in `daemon' mode, listening on a socket.
|
||||
@@ -77,7 +77,7 @@ BUG REPORTS
|
||||
|
||||
If you have web access then please look at
|
||||
|
||||
http://rsync.samba.org
|
||||
http://rsync.samba.org/
|
||||
|
||||
That page contains links to the current bug list, and information on
|
||||
how to report a bug well. You might also like to try searching the
|
||||
@@ -86,9 +86,8 @@ mailing list archives at
|
||||
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
Please send bug reports to
|
||||
|
||||
rsync@lists.samba.org
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
|
||||
CVS TREE
|
||||
|
||||
124
TODO
124
TODO
@@ -16,19 +16,17 @@ Handling IPv6 on old machines
|
||||
Other IPv6 stuff:
|
||||
Add ACL support 2001/12/02
|
||||
Lazy directory creation
|
||||
Conditional -z for old protocols
|
||||
proxy authentication 2002/01/23
|
||||
SOCKS 2002/01/23
|
||||
FAT support
|
||||
Allow forcing arbitrary permissions 2002/03/12
|
||||
--diff david.e.sewell 2002/03/15
|
||||
Add daemon --no-detach and --no-fork options
|
||||
Add daemon --no-fork option
|
||||
Create more granular verbosity jw 2003/05/15
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
Update README
|
||||
Keep list of open issues and todos on the web site
|
||||
Update web site from CVS
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
LOGGING --------------------------------------------------------------
|
||||
@@ -58,10 +56,8 @@ Add machines to build farm
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
File list structure in memory
|
||||
Traverse just one directory at a time
|
||||
Hard-link handling
|
||||
Allow skipping MD4 file_sum 2002/04/08
|
||||
Accelerate MD4
|
||||
String area code
|
||||
|
||||
TESTING --------------------------------------------------------------
|
||||
Torture test
|
||||
@@ -74,7 +70,6 @@ If tests are skipped, say why.
|
||||
Test daemon feature to disallow particular options.
|
||||
Create pipe program for testing
|
||||
Create test makefile target for some tests
|
||||
Test "refuse options" works
|
||||
|
||||
RELATED PROJECTS -----------------------------------------------------
|
||||
rsyncsh
|
||||
@@ -257,21 +252,6 @@ Lazy directory creation
|
||||
-- --
|
||||
|
||||
|
||||
Conditional -z for old protocols
|
||||
|
||||
After we get the @RSYNCD greeting from the server, we know it's
|
||||
version but we have not yet sent the command line, so we could just
|
||||
remove the -z option if the server is too old.
|
||||
|
||||
For ssh invocation it's not so simple, because we actually use the
|
||||
command line to start the remote process. However, we only actually
|
||||
do compression in token.c, and we could therefore once we discover
|
||||
the remote version emit an error if it's too old. I'm not sure if
|
||||
that's a good tradeoff or not.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
proxy authentication 2002/01/23
|
||||
|
||||
Allow RSYNC_PROXY to be http://user:pass@proxy.foo:3128/, and do
|
||||
@@ -345,7 +325,7 @@ Allow forcing arbitrary permissions 2002/03/12
|
||||
-- --
|
||||
|
||||
|
||||
Add daemon --no-detach and --no-fork options
|
||||
Add daemon --no-fork option
|
||||
|
||||
Very useful for debugging. Also good when running under a
|
||||
daemon-monitoring process that tries to restart the service when the
|
||||
@@ -381,11 +361,6 @@ Keep list of open issues and todos on the web site
|
||||
-- --
|
||||
|
||||
|
||||
Update web site from CVS
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
The man page is getting rather large, and there is more information
|
||||
@@ -444,7 +419,9 @@ Improve error messages
|
||||
our load? (Debian #28416) Probably fixed now, but a test case would
|
||||
be good.
|
||||
|
||||
|
||||
When running as a daemon, some errors should both be returned to the
|
||||
user and logged. This will make interacting with a daemon less
|
||||
cryptic.
|
||||
|
||||
-- --
|
||||
|
||||
@@ -708,76 +685,6 @@ Traverse just one directory at a time
|
||||
-- --
|
||||
|
||||
|
||||
Hard-link handling
|
||||
|
||||
At the moment hardlink handling is very expensive, so it's off by
|
||||
default. It does not need to be so.
|
||||
|
||||
Since most of the solutions are rather intertwined with the file
|
||||
list it is probably better to fix that first, although fixing
|
||||
hardlinks is possibly simpler.
|
||||
|
||||
We can rule out hardlinked directories since they will probably
|
||||
screw us up in all kinds of ways. They simply should not be used.
|
||||
|
||||
At the moment rsync only cares about hardlinks to regular files. I
|
||||
guess you could also use them for sockets, devices and other beasts,
|
||||
but I have not seen them.
|
||||
|
||||
When trying to reproduce hard links, we only need to worry about
|
||||
files that have more than one name (nlinks>1 && !S_ISDIR).
|
||||
|
||||
The basic point of this is to discover alternate names that refer to
|
||||
the same file. All operations, including creating the file and
|
||||
writing modifications to it need only to be done for the first name.
|
||||
For all later names, we just create the link and then leave it
|
||||
alone.
|
||||
|
||||
If hard links are to be preserved:
|
||||
|
||||
Before the generator/receiver fork, the list of files is received
|
||||
from the sender (recv_file_list), and a table for detecting hard
|
||||
links is built.
|
||||
|
||||
The generator looks for hard links within the file list and does
|
||||
not send checksums for them, though it does send other metadata.
|
||||
|
||||
The sender sends the device number and inode with file entries, so
|
||||
that files are uniquely identified.
|
||||
|
||||
The receiver goes through and creates hard links (do_hard_links)
|
||||
after all data has been written, but before directory permissions
|
||||
are set.
|
||||
|
||||
At the moment device and inum are sent as 4-byte integers, which
|
||||
will probably cause problems on large filesystems. On Linux the
|
||||
kernel uses 64-bit ino_t's internally, and people will soon have
|
||||
filesystems big enough to use them. We ought to follow NFS4 in
|
||||
using 64-bit device and inode identification, perhaps with a
|
||||
protocol version bump.
|
||||
|
||||
Once we've seen all the names for a particular file, we no longer
|
||||
need to think about it and we can deallocate the memory.
|
||||
|
||||
We can also have the case where there are links to a file that are
|
||||
not in the tree being transferred. There's nothing we can do about
|
||||
that. Because we rename the destination into place after writing,
|
||||
any hardlinks to the old file are always going to be orphaned. In
|
||||
fact that is almost necessary because otherwise we'd get really
|
||||
confused if we were generating checksums for one name of a file and
|
||||
modifying another.
|
||||
|
||||
At the moment the code seems to make a whole second copy of the file
|
||||
list, which seems unnecessary.
|
||||
|
||||
We should have a test case that exercises hard links. Since it
|
||||
might be hard to compare ./tls output where the inodes change we
|
||||
might need a little program to check whether several names refer to
|
||||
the same file.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Allow skipping MD4 file_sum 2002/04/08
|
||||
|
||||
If we're doing a local transfer, or using -W, then perhaps don't
|
||||
@@ -806,14 +713,6 @@ Accelerate MD4
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
String area code
|
||||
|
||||
Test whether this is actually faster than just using malloc(). If
|
||||
it's not (anymore), throw it out.
|
||||
|
||||
-- --
|
||||
|
||||
TESTING --------------------------------------------------------------
|
||||
|
||||
Torture test
|
||||
@@ -905,19 +804,6 @@ Create test makefile target for some tests
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Test "refuse options" works
|
||||
|
||||
What about for --recursive?
|
||||
|
||||
If you specify an unrecognized option here, you should get an error.
|
||||
|
||||
We need a test case for this...
|
||||
|
||||
Was this broken when we changed to popt?
|
||||
|
||||
-- --
|
||||
|
||||
RELATED PROJECTS -----------------------------------------------------
|
||||
|
||||
rsyncsh
|
||||
|
||||
31
access.c
31
access.c
@@ -88,9 +88,13 @@ static int match_address(char *addr, char *tok)
|
||||
/* Fail quietly if tok is a hostname (not an address) */
|
||||
if (strspn(tok, ".0123456789") != len
|
||||
#ifdef INET6
|
||||
&& !strchr(tok, ':')
|
||||
&& strchr(tok, ':') == NULL
|
||||
#endif
|
||||
) return 0;
|
||||
) {
|
||||
if (p)
|
||||
*p = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
@@ -99,17 +103,18 @@ static int match_address(char *addr, char *tok)
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
|
||||
gai = getaddrinfo(addr, NULL, &hints, &resa);
|
||||
if (gai) return 0;
|
||||
if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
|
||||
if (p)
|
||||
*p = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
gai = getaddrinfo(tok, NULL, &hints, &rest);
|
||||
if (p)
|
||||
*p++ = '/';
|
||||
if (gai) {
|
||||
rprintf(FERROR,
|
||||
"error matching address %s: %s\n",
|
||||
tok,
|
||||
gai_strerror(gai));
|
||||
if (gai != 0) {
|
||||
rprintf(FLOG, "error matching address %s: %s\n",
|
||||
tok, gai_strerror(gai));
|
||||
freeaddrinfo(resa);
|
||||
return 0;
|
||||
}
|
||||
@@ -152,7 +157,7 @@ static int match_address(char *addr, char *tok)
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
rprintf(FERROR,"unknown family %u\n", rest->ai_family);
|
||||
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -169,14 +174,14 @@ static int match_address(char *addr, char *tok)
|
||||
#ifdef HAVE_STRTOL
|
||||
bits = strtol(p, &ep, 10);
|
||||
if (!*p || *ep) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
for (pp = (unsigned char *)p; *pp; pp++) {
|
||||
if (!isascii(*pp) || !isdigit(*pp)) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -188,7 +193,7 @@ static int match_address(char *addr, char *tok)
|
||||
goto out;
|
||||
}
|
||||
if (bits < 0 || bits > (addrlen << 3)) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
11
acconfig.h
11
acconfig.h
@@ -1,11 +0,0 @@
|
||||
#undef ino_t
|
||||
#undef HAVE_CONNECT
|
||||
#undef HAVE_SHORT_INO_T
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#undef REPLACE_INET_NTOA
|
||||
#undef REPLACE_INET_ATON
|
||||
#undef HAVE_GETTIMEOFDAY_TZ
|
||||
#undef ENABLE_IPV6
|
||||
#undef HAVE_SOCKADDR_LEN
|
||||
#undef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
#undef HAVE_SOCKETPAIR
|
||||
214
authenticate.c
214
authenticate.c
@@ -1,17 +1,17 @@
|
||||
/* -*- c-file-style: "linux"; -*-
|
||||
|
||||
Copyright (C) 1998-2000 by Andrew Tridgell
|
||||
|
||||
|
||||
Copyright (C) 1998-2000 by Andrew Tridgell
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -20,11 +20,14 @@
|
||||
/* support rsync authentication */
|
||||
#include "rsync.h"
|
||||
|
||||
extern char *password_file;
|
||||
extern int am_root;
|
||||
|
||||
/***************************************************************************
|
||||
encode a buffer using base64 - simple and slow algorithm. null terminates
|
||||
the result.
|
||||
***************************************************************************/
|
||||
static void base64_encode(char *buf, int len, char *out)
|
||||
void base64_encode(char *buf, int len, char *out)
|
||||
{
|
||||
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i;
|
||||
@@ -33,7 +36,7 @@ static void base64_encode(char *buf, int len, char *out)
|
||||
|
||||
memset(out, 0, bytes+1);
|
||||
|
||||
for (i=0;i<bytes;i++) {
|
||||
for (i = 0; i < bytes; i++) {
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
if (bit_offset < 3) {
|
||||
@@ -54,7 +57,7 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
char input[32];
|
||||
struct timeval tv;
|
||||
|
||||
memset(input, 0, sizeof(input));
|
||||
memset(input, 0, sizeof input);
|
||||
|
||||
strlcpy((char *)input, addr, 17);
|
||||
sys_gettimeofday(&tv);
|
||||
@@ -62,121 +65,131 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
|
||||
sum_init();
|
||||
sum_update(input, sizeof(input));
|
||||
sum_init(0);
|
||||
sum_update(input, sizeof input);
|
||||
sum_end(challenge);
|
||||
}
|
||||
|
||||
|
||||
/* return the secret for a user from the sercret file. maximum length
|
||||
is len. null terminate it */
|
||||
/* Return the secret for a user from the secret file, null terminated.
|
||||
* Maximum length is len (not counting the null). */
|
||||
static int get_secret(int module, char *user, char *secret, int len)
|
||||
{
|
||||
char *fname = lp_secrets_file(module);
|
||||
int fd, found=0;
|
||||
char line[MAXPATHLEN];
|
||||
char *p, *pass=NULL;
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
extern int am_root;
|
||||
int fd, ok = 1;
|
||||
char ch, *p;
|
||||
|
||||
if (!fname || !*fname) return 0;
|
||||
if (!fname || !*fname)
|
||||
return 0;
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) return 0;
|
||||
if ((fd = open(fname, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
|
||||
if (do_stat(fname, &st) == -1) {
|
||||
rsyserr(FERROR, errno, "stat(%s)", fname);
|
||||
rsyserr(FLOG, errno, "stat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR,"secrets file must not be other-accessible (see strict modes option)\n");
|
||||
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
|
||||
ok = 0;
|
||||
} else if (am_root && (st.st_uid != 0)) {
|
||||
rprintf(FERROR,"secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
rprintf(FERROR,"continuing without secrets file\n");
|
||||
rprintf(FLOG, "continuing without secrets file\n");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!found) {
|
||||
int i = 0;
|
||||
memset(line, 0, sizeof line);
|
||||
while ((size_t) i < (sizeof(line)-1)) {
|
||||
if (read(fd, &line[i], 1) != 1) {
|
||||
memset(line, 0, sizeof(line));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (line[i] == '\r') continue;
|
||||
if (line[i] == '\n') break;
|
||||
i++;
|
||||
}
|
||||
line[i] = 0;
|
||||
if (line[0] == '#') continue;
|
||||
p = strchr(line,':');
|
||||
if (!p) continue;
|
||||
*p = 0;
|
||||
if (strcmp(user, line)) continue;
|
||||
pass = p+1;
|
||||
found = 1;
|
||||
if (*user == '#') {
|
||||
/* Reject attempt to match a comment. */
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (!found) return 0;
|
||||
/* Try to find a line that starts with the user name and a ':'. */
|
||||
p = user;
|
||||
while (1) {
|
||||
if (read(fd, &ch, 1) != 1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (ch == '\n')
|
||||
p = user;
|
||||
else if (p) {
|
||||
if (*p == ch)
|
||||
p++;
|
||||
else if (!*p && ch == ':')
|
||||
break;
|
||||
else
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Slurp the secret into the "secret" buffer. */
|
||||
p = secret;
|
||||
while (len > 0) {
|
||||
if (read(fd, p, 1) != 1 || *p == '\n')
|
||||
break;
|
||||
if (*p == '\r')
|
||||
continue;
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
*p = '\0';
|
||||
close(fd);
|
||||
|
||||
strlcpy(secret, pass, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *getpassf(char *filename)
|
||||
{
|
||||
char buffer[100];
|
||||
int fd=0;
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
extern int am_root;
|
||||
char *envpw=getenv("RSYNC_PASSWORD");
|
||||
char buffer[512], *p;
|
||||
int fd, n, ok = 1;
|
||||
char *envpw = getenv("RSYNC_PASSWORD");
|
||||
|
||||
if (!filename) return NULL;
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
if ( (fd=open(filename,O_RDONLY)) == -1) {
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FERROR, errno, "could not open password file \"%s\"",filename);
|
||||
if (envpw) rprintf(FERROR,"falling back to RSYNC_PASSWORD environment variable.\n");
|
||||
if (envpw)
|
||||
rprintf(FERROR, "falling back to RSYNC_PASSWORD environment variable.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (do_stat(filename, &st) == -1) {
|
||||
rsyserr(FERROR, errno, "stat(%s)", filename);
|
||||
ok = 0;
|
||||
} else if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR,"password file must not be other-accessible\n");
|
||||
ok = 0;
|
||||
} else if (am_root && (st.st_uid != 0)) {
|
||||
} else if (am_root && st.st_uid != 0) {
|
||||
rprintf(FERROR,"password file must be owned by root when running as root\n");
|
||||
ok = 0;
|
||||
}
|
||||
if (!ok) {
|
||||
rprintf(FERROR,"continuing without password file\n");
|
||||
if (envpw) rprintf(FERROR,"using RSYNC_PASSWORD environment variable.\n");
|
||||
if (envpw)
|
||||
rprintf(FERROR, "using RSYNC_PASSWORD environment variable.\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (envpw) rprintf(FERROR,"RSYNC_PASSWORD environment variable ignored\n");
|
||||
if (envpw)
|
||||
rprintf(FERROR, "RSYNC_PASSWORD environment variable ignored\n");
|
||||
|
||||
buffer[sizeof(buffer)-1]='\0';
|
||||
if (read(fd,buffer,sizeof(buffer)-1) > 0)
|
||||
{
|
||||
char *p = strtok(buffer,"\n\r");
|
||||
close(fd);
|
||||
if (p) p = strdup(p);
|
||||
return p;
|
||||
}
|
||||
n = read(fd, buffer, sizeof buffer - 1);
|
||||
close(fd);
|
||||
if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
if ((p = strtok(buffer, "\n\r")) != NULL)
|
||||
return strdup(p);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -186,7 +199,7 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
sum_init();
|
||||
sum_init(0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
sum_end(buf);
|
||||
@@ -194,15 +207,12 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
base64_encode(buf, 16, out);
|
||||
}
|
||||
|
||||
/* possible negotiate authentication with the client. Use "leader" to
|
||||
start off the auth if necessary
|
||||
|
||||
return NULL if authentication failed
|
||||
|
||||
return "" if anonymous access
|
||||
|
||||
otherwise return username
|
||||
*/
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
* start off the auth if necessary.
|
||||
*
|
||||
* Return NULL if authentication failed. Return "" if anonymous access.
|
||||
* Otherwise return username.
|
||||
*/
|
||||
char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
@@ -216,46 +226,46 @@ char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
|
||||
char *tok;
|
||||
|
||||
/* if no auth list then allow anyone in! */
|
||||
if (!users || !*users) return "";
|
||||
if (!users || !*users)
|
||||
return "";
|
||||
|
||||
gen_challenge(addr, challenge);
|
||||
|
||||
|
||||
base64_encode(challenge, 16, b64_challenge);
|
||||
|
||||
io_printf(f_out, "%s%s\n", leader, b64_challenge);
|
||||
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(user, 0, sizeof(user));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
memset(user, 0, sizeof user);
|
||||
memset(pass, 0, sizeof pass);
|
||||
|
||||
if (sscanf(line,"%99s %29s", user, pass) != 2) {
|
||||
if (sscanf(line,"%99s %29s", user, pass) != 2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
users = strdup(users);
|
||||
if (!users) return NULL;
|
||||
if (!users)
|
||||
return NULL;
|
||||
|
||||
for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
|
||||
if (wildmatch(tok, user)) break;
|
||||
if (wildmatch(tok, user))
|
||||
break;
|
||||
}
|
||||
free(users);
|
||||
|
||||
if (!tok) {
|
||||
if (!tok)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(secret, 0, sizeof(secret));
|
||||
if (!get_secret(module, user, secret, sizeof(secret)-1)) {
|
||||
memset(secret, 0, sizeof(secret));
|
||||
|
||||
memset(secret, 0, sizeof secret);
|
||||
if (!get_secret(module, user, secret, sizeof secret - 1)) {
|
||||
memset(secret, 0, sizeof secret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
generate_hash(secret, b64_challenge, pass2);
|
||||
memset(secret, 0, sizeof(secret));
|
||||
|
||||
memset(secret, 0, sizeof secret);
|
||||
|
||||
if (strcmp(pass, pass2) == 0)
|
||||
return user;
|
||||
|
||||
@@ -267,11 +277,12 @@ void auth_client(int fd, char *user, char *challenge)
|
||||
{
|
||||
char *pass;
|
||||
char pass2[30];
|
||||
extern char *password_file;
|
||||
|
||||
if (!user || !*user) return;
|
||||
if (!user || !*user)
|
||||
user = "nobody";
|
||||
|
||||
if (!(pass=getpassf(password_file)) && !(pass=getenv("RSYNC_PASSWORD"))) {
|
||||
if (!(pass = getpassf(password_file))
|
||||
&& !(pass = getenv("RSYNC_PASSWORD"))) {
|
||||
/* XXX: cyeoh says that getpass is deprecated, because
|
||||
* it may return a truncated password on some systems,
|
||||
* and it is not in the LSB.
|
||||
@@ -284,9 +295,8 @@ void auth_client(int fd, char *user, char *challenge)
|
||||
pass = getpass("Password: ");
|
||||
}
|
||||
|
||||
if (!pass || !*pass) {
|
||||
if (!pass)
|
||||
pass = "";
|
||||
}
|
||||
|
||||
generate_hash(pass, challenge, pass2);
|
||||
io_printf(fd, "%s %s\n", user, pass2);
|
||||
|
||||
315
backup.c
315
backup.c
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1999
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -23,6 +23,8 @@
|
||||
extern int verbose;
|
||||
extern int backup_suffix_len;
|
||||
extern int backup_dir_len;
|
||||
extern unsigned int backup_dir_remainder;
|
||||
extern char backup_dir_buf[MAXPATHLEN];
|
||||
extern char *backup_suffix;
|
||||
extern char *backup_dir;
|
||||
|
||||
@@ -30,21 +32,39 @@ extern int am_root;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int orig_umask;
|
||||
extern int safe_symlinks;
|
||||
|
||||
/* make a complete pathname for backup file */
|
||||
char *get_backup_name(char *fname)
|
||||
{
|
||||
if (backup_dir) {
|
||||
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
|
||||
fname, backup_suffix, NULL) < backup_dir_remainder)
|
||||
return backup_dir_buf;
|
||||
} else {
|
||||
if (stringjoin(backup_dir_buf, MAXPATHLEN,
|
||||
fname, backup_suffix, NULL) < MAXPATHLEN)
|
||||
return backup_dir_buf;
|
||||
}
|
||||
|
||||
rprintf(FERROR, "backup filename too long\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* simple backup creates a backup with a suffix in the same directory */
|
||||
static int make_simple_backup(char *fname)
|
||||
{
|
||||
char fnamebak[MAXPATHLEN];
|
||||
if (strlen(fname) + backup_suffix_len > MAXPATHLEN-1) {
|
||||
rprintf(FERROR, "backup filename too long\n");
|
||||
return 0;
|
||||
}
|
||||
char *fnamebak = get_backup_name(fname);
|
||||
|
||||
if (!fnamebak)
|
||||
return 0;
|
||||
|
||||
snprintf(fnamebak, sizeof(fnamebak), "%s%s", fname, backup_suffix);
|
||||
if (do_rename(fname, fnamebak) != 0) {
|
||||
/* cygwin (at least version b19) reports EINVAL */
|
||||
if (errno != ENOENT && errno != EINVAL) {
|
||||
rsyserr(FERROR, errno, "rename %s to backup %s", fname, fnamebak);
|
||||
rsyserr(FERROR, errno,
|
||||
"rename %s to backup %s", fname, fnamebak);
|
||||
return 0;
|
||||
}
|
||||
} else if (verbose > 1) {
|
||||
@@ -54,177 +74,121 @@ static int make_simple_backup(char *fname)
|
||||
}
|
||||
|
||||
|
||||
/* recursively make a directory path */
|
||||
static int make_dir(char *name, int mask)
|
||||
{
|
||||
char newdir [MAXPATHLEN];
|
||||
char *p, *d;
|
||||
|
||||
/* copy pathname over, look for last '/' */
|
||||
for (p = d = newdir; *name; *d++ = *name++)
|
||||
if (*name == '/')
|
||||
p = d;
|
||||
if (p == newdir)
|
||||
return 0;
|
||||
*p = 0;
|
||||
|
||||
/* make the new directory, if that fails then make its parent */
|
||||
while (do_mkdir (newdir, mask) != 0)
|
||||
if ((errno != ENOENT) || !make_dir (newdir, mask))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
} /* make_dir */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Create a directory given an absolute path, perms based upon another directory
|
||||
path
|
||||
****************************************************************************/
|
||||
static int make_bak_dir(char *fname, char *bak_path)
|
||||
static int make_bak_dir(char *fullpath)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
STRUCT_STAT *st2;
|
||||
char fullpath[MAXPATHLEN];
|
||||
extern int orig_umask;
|
||||
char *p;
|
||||
char *q;
|
||||
char *rel = fullpath + backup_dir_len;
|
||||
char *end = rel + strlen(rel);
|
||||
char *p = end;
|
||||
|
||||
while(strncmp(bak_path, "./", 2) == 0) bak_path += 2;
|
||||
while (strncmp(fullpath, "./", 2) == 0)
|
||||
fullpath += 2;
|
||||
|
||||
if(bak_path[strlen(bak_path)-1] != '/') {
|
||||
snprintf(fullpath, sizeof(fullpath), "%s/", bak_path);
|
||||
} else {
|
||||
snprintf(fullpath, sizeof(fullpath), "%s", bak_path);
|
||||
/* Try to find an existing dir, starting from the deepest dir. */
|
||||
while (1) {
|
||||
if (--p == fullpath) {
|
||||
p += strlen(p);
|
||||
goto failure;
|
||||
}
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (do_mkdir(fullpath, 0777 & ~orig_umask) == 0)
|
||||
break;
|
||||
if (errno != ENOENT) {
|
||||
rsyserr(FERROR, errno,
|
||||
"make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
p = fullpath;
|
||||
q = &fullpath[strlen(fullpath)]; /* End of bak_path string */
|
||||
strcat(fullpath, fname);
|
||||
|
||||
/* Make the directories */
|
||||
while ((p = strchr(p, '/'))) {
|
||||
*p = 0;
|
||||
if(do_lstat(fullpath, &st) != 0) {
|
||||
do_mkdir(fullpath, 0777 & ~orig_umask);
|
||||
if(p>q) {
|
||||
if(do_lstat(q, &st) != 0) {
|
||||
rprintf(FERROR, "make_bak_dir stat %s failed: %s\n",
|
||||
full_fname(fullpath), strerror(errno));
|
||||
} else {
|
||||
st2 = &st;
|
||||
set_modtime(fullpath, st2->st_mtime);
|
||||
if(do_lchown(fullpath, st2->st_uid, st2->st_gid) != 0) {
|
||||
rprintf(FERROR, "make_bak_dir chown %s failed: %s\n",
|
||||
full_fname(fullpath), strerror(errno));
|
||||
}
|
||||
if(do_chmod(fullpath, st2->st_mode) != 0) {
|
||||
rprintf(FERROR, "make_bak_dir failed to set permissions on %s: %s\n",
|
||||
full_fname(fullpath), strerror(errno));
|
||||
}
|
||||
}
|
||||
/* Make all the dirs that we didn't find on the way here. */
|
||||
while (1) {
|
||||
if (p >= rel) {
|
||||
/* Try to transfer the directory settings of the
|
||||
* actual dir that the files are coming from. */
|
||||
if (do_stat(rel, &st) < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"make_bak_dir stat %s failed",
|
||||
full_fname(rel));
|
||||
} else {
|
||||
do_lchown(fullpath, st.st_uid, st.st_gid);
|
||||
do_chmod(fullpath, st.st_mode);
|
||||
}
|
||||
}
|
||||
*p = '/';
|
||||
p++;
|
||||
p += strlen(p);
|
||||
if (p == end)
|
||||
break;
|
||||
if (do_mkdir(fullpath, 0777 & ~orig_umask) < 0) {
|
||||
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
while (p != end) {
|
||||
*p = '/';
|
||||
p += strlen(p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* robustly move a file, creating new directory structures if necessary */
|
||||
static int robust_move(char *src, char *dst)
|
||||
{
|
||||
int keep_trying = 4;
|
||||
int keep_path_extfs = 0;
|
||||
int failed;
|
||||
|
||||
while (keep_trying) {
|
||||
if (keep_path_extfs) {
|
||||
failed = copy_file(src, dst, 0755);
|
||||
if (!failed) {
|
||||
do_unlink(src);
|
||||
}
|
||||
} else {
|
||||
failed = robust_rename (src, dst);
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
if (verbose > 2)
|
||||
rprintf (FERROR, "robust_move failed: %s(%d)\n",
|
||||
strerror (errno), errno);
|
||||
switch (errno) {
|
||||
/* external filesystem */
|
||||
case EXDEV:
|
||||
keep_path_extfs = 1;
|
||||
keep_trying--;
|
||||
break;
|
||||
/* no directory to write to */
|
||||
case ENOENT:
|
||||
make_dir(dst, 0700);
|
||||
keep_trying--;
|
||||
break;
|
||||
default:
|
||||
keep_trying = 0;
|
||||
} /* switch */
|
||||
} else
|
||||
keep_trying = 0;
|
||||
} /* while */
|
||||
return (!failed);
|
||||
} /* robust_move */
|
||||
if (robust_rename(src, dst, 0755) < 0 && (errno != ENOENT
|
||||
|| make_bak_dir(dst) < 0 || robust_rename(src, dst, 0755) < 0))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* if we have a backup_dir, then we get here from make_backup().
|
||||
We will move the file to be deleted into a parallel directory tree */
|
||||
/* If we have a --backup-dir, then we get here from make_backup().
|
||||
* We will move the file to be deleted into a parallel directory tree. */
|
||||
static int keep_backup(char *fname)
|
||||
{
|
||||
|
||||
static int initialised;
|
||||
|
||||
char keep_name [MAXPATHLEN];
|
||||
STRUCT_STAT st;
|
||||
struct file_struct *file;
|
||||
|
||||
char *buf;
|
||||
int kept = 0;
|
||||
int ret_code;
|
||||
|
||||
if (!initialised) {
|
||||
if (backup_dir_len && backup_dir[backup_dir_len - 1] == '/')
|
||||
backup_dir[--backup_dir_len] = '\0';
|
||||
if (verbose > 0)
|
||||
rprintf (FINFO, "backup_dir is %s\n", backup_dir);
|
||||
initialised = 1;
|
||||
}
|
||||
|
||||
/* return if no file to keep */
|
||||
#if SUPPORT_LINKS
|
||||
if (do_lstat (fname, &st)) return 1;
|
||||
ret_code = do_lstat(fname, &st);
|
||||
#else
|
||||
if (do_stat (fname, &st)) return 1;
|
||||
ret_code = do_stat(fname, &st);
|
||||
#endif
|
||||
if (ret_code < 0)
|
||||
return 1;
|
||||
|
||||
file = make_file(fname, NULL, NO_EXCLUDES);
|
||||
if (!(file = make_file(fname, NULL, NO_EXCLUDES)))
|
||||
return 1; /* the file could have disappeared */
|
||||
|
||||
/* the file could have disappeared */
|
||||
if (!file) return 1;
|
||||
|
||||
/* make a complete pathname for backup file */
|
||||
if (backup_dir_len+strlen(fname)+backup_suffix_len > MAXPATHLEN-1) {
|
||||
rprintf (FERROR, "keep_backup filename too long\n");
|
||||
if (!(buf = get_backup_name(fname)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(keep_name, sizeof (keep_name), "%s/%s%s",
|
||||
backup_dir, fname, backup_suffix);
|
||||
|
||||
#ifdef HAVE_MKNOD
|
||||
/* Check to see if this is a device file, or link */
|
||||
if(IS_DEVICE(file->mode)) {
|
||||
if(am_root && preserve_devices) {
|
||||
make_bak_dir(fname, backup_dir);
|
||||
if(do_mknod(keep_name, file->mode, file->rdev) != 0) {
|
||||
rprintf(FERROR, "mknod %s failed: %s\n",
|
||||
full_fname(keep_name), strerror(errno));
|
||||
} else if(verbose>2) {
|
||||
rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
|
||||
if (IS_DEVICE(file->mode)) {
|
||||
if (am_root && preserve_devices) {
|
||||
if (do_mknod(buf, file->mode, file->u.rdev) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_mknod(buf, file->mode, file->u.rdev) < 0)) {
|
||||
rsyserr(FERROR, errno, "mknod %s failed",
|
||||
full_fname(buf));
|
||||
} else if (verbose > 2) {
|
||||
rprintf(FINFO,
|
||||
"make_backup: DEVICE %s successful.\n",
|
||||
fname);
|
||||
}
|
||||
}
|
||||
kept = 1;
|
||||
@@ -232,13 +196,17 @@ static int keep_backup(char *fname)
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!kept && S_ISDIR(file->mode)) {
|
||||
if (!kept && S_ISDIR(file->mode)) {
|
||||
/* make an empty directory */
|
||||
make_bak_dir(fname, backup_dir);
|
||||
do_mkdir(keep_name, file->mode);
|
||||
ret_code = do_rmdir(fname);
|
||||
if (do_mkdir(buf, file->mode) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_mkdir(buf, file->mode) < 0)) {
|
||||
rsyserr(FINFO, errno, "mkdir %s failed",
|
||||
full_fname(buf));
|
||||
}
|
||||
|
||||
if(verbose>2) {
|
||||
ret_code = do_rmdir(fname);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
|
||||
full_fname(fname), ret_code);
|
||||
}
|
||||
@@ -246,56 +214,55 @@ static int keep_backup(char *fname)
|
||||
}
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
if(!kept && preserve_links && S_ISLNK(file->mode)) {
|
||||
extern int safe_symlinks;
|
||||
if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
|
||||
if (!kept && preserve_links && S_ISLNK(file->mode)) {
|
||||
if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
|
||||
full_fname(keep_name), file->link);
|
||||
full_fname(buf), file->u.link);
|
||||
}
|
||||
kept = 1;
|
||||
}
|
||||
make_bak_dir(fname, backup_dir);
|
||||
if(do_symlink(file->link, keep_name) != 0) {
|
||||
rprintf(FERROR, "link %s -> %s : %s\n",
|
||||
full_fname(keep_name), file->link, strerror(errno));
|
||||
if (do_symlink(file->u.link, buf) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_symlink(file->u.link, buf) < 0)) {
|
||||
rsyserr(FERROR, errno, "link %s -> \"%s\"",
|
||||
full_fname(buf), file->u.link);
|
||||
}
|
||||
do_unlink(fname);
|
||||
kept = 1;
|
||||
}
|
||||
#endif
|
||||
if(!kept && preserve_hard_links && check_hard_link(file)) {
|
||||
if(verbose > 1)
|
||||
rprintf(FINFO, "%s is a hard link\n", f_name(file));
|
||||
}
|
||||
|
||||
if(!kept && !S_ISREG(file->mode)) {
|
||||
if (!kept && !S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
|
||||
fname);
|
||||
fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* move to keep tree if a file */
|
||||
if(!kept) {
|
||||
if (!robust_move (fname, keep_name)) {
|
||||
rprintf(FERROR, "keep_backup failed: %s -> \"%s\": %s\n",
|
||||
full_fname(fname), keep_name, strerror(errno));
|
||||
if (!kept) {
|
||||
if (robust_move(fname, buf) != 0) {
|
||||
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
|
||||
full_fname(fname), buf);
|
||||
} else if (st.st_nlink > 1) {
|
||||
/* If someone has hard-linked the file into the backup
|
||||
* dir, rename() might return success but do nothing! */
|
||||
robust_unlink(fname); /* Just in case... */
|
||||
}
|
||||
}
|
||||
set_perms (keep_name, file, NULL, 0);
|
||||
free_file (file);
|
||||
free (file);
|
||||
set_perms(buf, file, NULL, 0);
|
||||
free(file);
|
||||
|
||||
if (verbose > 1)
|
||||
rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
|
||||
return 1;
|
||||
} /* keep_backup */
|
||||
}
|
||||
|
||||
|
||||
/* main backup switch routine */
|
||||
int make_backup(char *fname)
|
||||
{
|
||||
if (backup_dir)
|
||||
return (keep_backup(fname));
|
||||
else
|
||||
return (make_simple_backup(fname));
|
||||
return keep_backup(fname);
|
||||
return make_simple_backup(fname);
|
||||
}
|
||||
|
||||
688
batch.c
688
batch.c
@@ -1,5 +1,5 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
|
||||
Weiss 1/1999
|
||||
Batch utilities for rsync.
|
||||
|
||||
@@ -8,565 +8,171 @@
|
||||
#include "rsync.h"
|
||||
#include <time.h>
|
||||
|
||||
extern char *batch_prefix;
|
||||
extern char *batch_name;
|
||||
extern int eol_nulls;
|
||||
extern int recurse;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int always_checksum;
|
||||
|
||||
struct file_list *batch_flist;
|
||||
extern struct exclude_list_struct exclude_list;
|
||||
|
||||
static char rsync_flist_file[] = ".rsync_flist";
|
||||
static char rsync_csums_file[] = ".rsync_csums";
|
||||
static char rsync_delta_file[] = ".rsync_delta";
|
||||
static char rsync_argvs_file[] = ".rsync_argvs";
|
||||
static int *flag_ptr[] = {
|
||||
&recurse,
|
||||
&preserve_uid,
|
||||
&preserve_gid,
|
||||
&preserve_links,
|
||||
&preserve_devices,
|
||||
&preserve_hard_links,
|
||||
&always_checksum,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int fdb;
|
||||
static int fdb_delta;
|
||||
static int fdb_open;
|
||||
static int fdb_close;
|
||||
static char *flag_name[] = {
|
||||
"--recurse (-r)",
|
||||
"--owner (-o)",
|
||||
"--group (-g)",
|
||||
"--links (-l)",
|
||||
"--devices (-D)",
|
||||
"--hard-links (-H)",
|
||||
"--checksum (-c)",
|
||||
NULL
|
||||
};
|
||||
|
||||
void write_batch_flist_file(char *buff, int bytes_to_write)
|
||||
void write_stream_flags(int fd)
|
||||
{
|
||||
char filename[MAXPATHLEN];
|
||||
int i, flags;
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_flist_file, sizeof(filename));
|
||||
/* Start the batch file with a bitmap of data-stream-affecting
|
||||
* flags. */
|
||||
for (i = 0, flags = 0; flag_ptr[i]; i++) {
|
||||
if (*flag_ptr[i])
|
||||
flags |= 1 << i;
|
||||
}
|
||||
write_int(fd, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open batch flist file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
void read_stream_flags(int fd)
|
||||
{
|
||||
int i, flags;
|
||||
|
||||
for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) {
|
||||
int set = flags & (1 << i) ? 1 : 0;
|
||||
if (*flag_ptr[i] != set) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO,
|
||||
"%sing the %s option to match the batchfile.\n",
|
||||
set ? "Sett" : "Clear", flag_name[i]);
|
||||
}
|
||||
*flag_ptr[i] = set;
|
||||
}
|
||||
fdb_open = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_arg(int fd, char *arg)
|
||||
{
|
||||
char *x, *s;
|
||||
|
||||
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
|
||||
write(fd, arg, x - arg + 1);
|
||||
arg += x - arg + 1;
|
||||
}
|
||||
|
||||
/* Write buffer to batch flist file */
|
||||
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
|
||||
write(fd, "'", 1);
|
||||
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
|
||||
write(fd, s, x - s + 1);
|
||||
write(fd, "'", 1);
|
||||
}
|
||||
write(fd, s, strlen(s));
|
||||
write(fd, "'", 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (write(fdb, buff, bytes_to_write) == -1) {
|
||||
rprintf(FERROR, "Batch file %s write error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
write(fd, arg, strlen(arg));
|
||||
}
|
||||
|
||||
static void write_excludes(int fd)
|
||||
{
|
||||
struct exclude_struct *ent;
|
||||
|
||||
write_sbuf(fd, " <<'#E#'\n");
|
||||
for (ent = exclude_list.head; ent; ent = ent->next) {
|
||||
char *p = ent->pattern;
|
||||
if (ent->match_flags & MATCHFLG_INCLUDE)
|
||||
write_buf(fd, "+ ", 2);
|
||||
else if (((*p == '-' || *p == '+') && p[1] == ' ')
|
||||
|| *p == '#' || *p == ';')
|
||||
write_buf(fd, "- ", 2);
|
||||
write_sbuf(fd, p);
|
||||
if (ent->match_flags & MATCHFLG_DIRECTORY)
|
||||
write_byte(fd, '/');
|
||||
write_byte(fd, eol_nulls ? 0 : '\n');
|
||||
}
|
||||
if (eol_nulls)
|
||||
write_sbuf(fd, ";\n");
|
||||
write_sbuf(fd, "#E#");
|
||||
}
|
||||
|
||||
/* This routine tries to write out an equivalent --read-batch command
|
||||
* given the user's --write-batch args. However, it doesn't really
|
||||
* understand most of the options, so it uses some overly simple
|
||||
* heuristics to munge the command line into something that will
|
||||
* (hopefully) work. */
|
||||
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
{
|
||||
int fd, i;
|
||||
char *p, filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_name, ".sh", NULL);
|
||||
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IEXEC);
|
||||
if (fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error", filename);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
if (fdb_close) {
|
||||
close(fdb);
|
||||
}
|
||||
}
|
||||
|
||||
void write_batch_flist_info(int flist_count, struct file_struct **fptr)
|
||||
{
|
||||
int i;
|
||||
int bytes_to_write;
|
||||
|
||||
/* Write flist info to batch file */
|
||||
|
||||
bytes_to_write =
|
||||
sizeof(unsigned) +
|
||||
sizeof(time_t) +
|
||||
sizeof(OFF_T) +
|
||||
sizeof(mode_t) +
|
||||
sizeof(INO64_T) +
|
||||
sizeof(DEV64_T) +
|
||||
sizeof(DEV64_T) +
|
||||
sizeof(uid_t) +
|
||||
sizeof(gid_t);
|
||||
|
||||
fdb_open = 1;
|
||||
fdb_close = 0;
|
||||
|
||||
for (i = 0; i < flist_count; i++) {
|
||||
write_batch_flist_file((char *) fptr[i], bytes_to_write);
|
||||
write_char_bufs(fptr[i]->basename);
|
||||
write_char_bufs(fptr[i]->dirname);
|
||||
write_char_bufs(fptr[i]->basedir);
|
||||
write_char_bufs(fptr[i]->link);
|
||||
if (i == flist_count - 1) {
|
||||
fdb_close = 1;
|
||||
/* Write argvs info to BATCH.sh file */
|
||||
write_arg(fd, argv[0]);
|
||||
if (exclude_list.head)
|
||||
write_sbuf(fd, " --exclude-from=-");
|
||||
for (i = 1; i < argc - file_arg_cnt; i++) {
|
||||
p = argv[i];
|
||||
if (strncmp(p, "--files-from", 12) == 0
|
||||
|| strncmp(p, "--include", 9) == 0
|
||||
|| strncmp(p, "--exclude", 9) == 0) {
|
||||
if (strchr(p, '=') == NULL)
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
write_char_bufs(fptr[i]->sum);
|
||||
}
|
||||
}
|
||||
|
||||
void write_char_bufs(char *buf)
|
||||
{
|
||||
/* Write the size of the string which will follow */
|
||||
|
||||
char b[4];
|
||||
|
||||
SIVAL(b, 0, buf != NULL ? strlen(buf) : 0);
|
||||
|
||||
write_batch_flist_file(b, sizeof(int));
|
||||
|
||||
/* Write the string if there is one */
|
||||
|
||||
if (buf != NULL) {
|
||||
write_batch_flist_file(buf, strlen(buf));
|
||||
}
|
||||
}
|
||||
|
||||
void write_batch_argvs_file(int argc, char *argv[])
|
||||
{
|
||||
int fdb;
|
||||
int i;
|
||||
char buff[256]; /* XXX */
|
||||
char buff2[MAXPATHLEN + 6];
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_argvs_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch argvs file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE | S_IEXEC);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Write argvs info to batch file */
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (i == argc - 2) /* Skip source directory on cmdline */
|
||||
continue;
|
||||
/*
|
||||
* FIXME:
|
||||
* I think directly manipulating argv[] is probably bogus
|
||||
*/
|
||||
if (!strncmp(argv[i], "--write-batch",
|
||||
strlen("--write-batch"))) {
|
||||
/* Safer to change it here than script */
|
||||
/*
|
||||
* Change to --read-batch=prefix
|
||||
* to get ready for remote
|
||||
*/
|
||||
strlcat(buff, "--read-batch=", sizeof(buff));
|
||||
strlcat(buff, batch_prefix, sizeof(buff));
|
||||
write(fd, " ", 1);
|
||||
if (strncmp(p, "--write-batch", 13) == 0) {
|
||||
write(fd, "--read-batch", 12);
|
||||
if (p[13] == '=') {
|
||||
write(fd, "=", 1);
|
||||
write_arg(fd, p + 14);
|
||||
}
|
||||
} else
|
||||
if (i == argc - 1) {
|
||||
snprintf(buff2, sizeof(buff2), "${1:-%s}", argv[i]);
|
||||
strlcat(buff, buff2, sizeof(buff));
|
||||
}
|
||||
else {
|
||||
strlcat(buff, argv[i], sizeof(buff));
|
||||
}
|
||||
|
||||
if (i < (argc - 1)) {
|
||||
strlcat(buff, " ", sizeof(buff));
|
||||
}
|
||||
write_arg(fd, p);
|
||||
}
|
||||
strlcat(buff, "\n", sizeof(buff));
|
||||
if (!write(fdb, buff, strlen(buff))) {
|
||||
rprintf(FERROR, "Batch file %s write error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
if ((p = find_colon(argv[argc - 1])) != NULL) {
|
||||
if (*++p == ':')
|
||||
p++;
|
||||
} else
|
||||
p = argv[argc - 1];
|
||||
write(fd, " ${1:-", 6);
|
||||
write_arg(fd, p);
|
||||
write_byte(fd, '}');
|
||||
if (exclude_list.head)
|
||||
write_excludes(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error", filename);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
close(fdb);
|
||||
}
|
||||
|
||||
struct file_list *create_flist_from_batch(void)
|
||||
{
|
||||
unsigned char flags;
|
||||
|
||||
fdb_open = 1;
|
||||
fdb_close = 0;
|
||||
|
||||
batch_flist = new(struct file_list);
|
||||
if (!batch_flist) {
|
||||
out_of_memory("create_flist_from_batch");
|
||||
}
|
||||
batch_flist->count = 0;
|
||||
batch_flist->malloced = 1000;
|
||||
batch_flist->files = new_array(struct file_struct *,
|
||||
batch_flist->malloced);
|
||||
if (!batch_flist->files) {
|
||||
out_of_memory("create_flist_from_batch");
|
||||
}
|
||||
|
||||
for (flags = read_batch_flags(); flags; flags = read_batch_flags()) {
|
||||
|
||||
int i = batch_flist->count;
|
||||
|
||||
if (i >= batch_flist->malloced) {
|
||||
if (batch_flist->malloced < 1000)
|
||||
batch_flist->malloced += 1000;
|
||||
else
|
||||
batch_flist->malloced *= 2;
|
||||
batch_flist->files
|
||||
= realloc_array(batch_flist->files,
|
||||
struct file_struct *,
|
||||
batch_flist->malloced);
|
||||
if (!batch_flist->files)
|
||||
out_of_memory("create_flist_from_batch");
|
||||
}
|
||||
read_batch_flist_info(&batch_flist->files[i]);
|
||||
batch_flist->files[i]->flags = flags;
|
||||
|
||||
batch_flist->count++;
|
||||
}
|
||||
|
||||
return batch_flist;
|
||||
}
|
||||
|
||||
int read_batch_flist_file(char *buff, int len)
|
||||
{
|
||||
int bytes_read;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_flist_file, sizeof(filename));
|
||||
|
||||
/* Open batch flist file for reading */
|
||||
fdb = do_open(filename, O_RDONLY, 0);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
fdb_open = 0;
|
||||
}
|
||||
|
||||
/* Read flist batch file */
|
||||
|
||||
switch (bytes_read = read(fdb, buff, len)) {
|
||||
case -1:
|
||||
rprintf(FERROR, "Batch file %s read error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
break;
|
||||
case 0: /* EOF */
|
||||
close(fdb);
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
unsigned char read_batch_flags(void)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if (read_batch_flist_file((char *) &flags, 4)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void read_batch_flist_info(struct file_struct **fptr)
|
||||
{
|
||||
int int_str_len;
|
||||
char char_str_len[4];
|
||||
char buff[256];
|
||||
struct file_struct *file;
|
||||
|
||||
file = new(struct file_struct);
|
||||
if (!file)
|
||||
out_of_memory("read_batch_flist_info");
|
||||
memset((char *) file, 0, sizeof(*file));
|
||||
|
||||
*fptr = file;
|
||||
|
||||
/*
|
||||
* Keep these in sync with bytes_to_write assignment
|
||||
* in write_batch_flist_info()
|
||||
*/
|
||||
read_batch_flist_file((char *) &file->modtime, sizeof(time_t));
|
||||
read_batch_flist_file((char *) &file->length, sizeof(OFF_T));
|
||||
read_batch_flist_file((char *) &file->mode, sizeof(mode_t));
|
||||
read_batch_flist_file((char *) &file->inode, sizeof(INO64_T));
|
||||
read_batch_flist_file((char *) &file->dev, sizeof(DEV64_T));
|
||||
read_batch_flist_file((char *) &file->rdev, sizeof(DEV64_T));
|
||||
read_batch_flist_file((char *) &file->uid, sizeof(uid_t));
|
||||
read_batch_flist_file((char *) &file->gid, sizeof(gid_t));
|
||||
read_batch_flist_file(char_str_len, sizeof(char_str_len));
|
||||
int_str_len = IVAL(char_str_len, 0);
|
||||
if (int_str_len > 0) {
|
||||
read_batch_flist_file(buff, int_str_len);
|
||||
buff[int_str_len] = '\0';
|
||||
file->basename = strdup(buff);
|
||||
} else {
|
||||
file->basename = NULL;
|
||||
}
|
||||
|
||||
read_batch_flist_file(char_str_len, sizeof(char_str_len));
|
||||
int_str_len = IVAL(char_str_len, 0);
|
||||
if (int_str_len > 0) {
|
||||
read_batch_flist_file(buff, int_str_len);
|
||||
buff[int_str_len] = '\0';
|
||||
file[0].dirname = strdup(buff);
|
||||
} else {
|
||||
file[0].dirname = NULL;
|
||||
}
|
||||
|
||||
read_batch_flist_file(char_str_len, sizeof(char_str_len));
|
||||
int_str_len = IVAL(char_str_len, 0);
|
||||
if (int_str_len > 0) {
|
||||
read_batch_flist_file(buff, int_str_len);
|
||||
buff[int_str_len] = '\0';
|
||||
file[0].basedir = strdup(buff);
|
||||
} else {
|
||||
file[0].basedir = NULL;
|
||||
}
|
||||
|
||||
read_batch_flist_file(char_str_len, sizeof(char_str_len));
|
||||
int_str_len = IVAL(char_str_len, 0);
|
||||
if (int_str_len > 0) {
|
||||
read_batch_flist_file(buff, int_str_len);
|
||||
buff[int_str_len] = '\0';
|
||||
file[0].link = strdup(buff);
|
||||
} else {
|
||||
file[0].link = NULL;
|
||||
}
|
||||
|
||||
read_batch_flist_file(char_str_len, sizeof(char_str_len));
|
||||
int_str_len = IVAL(char_str_len, 0);
|
||||
if (int_str_len > 0) {
|
||||
read_batch_flist_file(buff, int_str_len);
|
||||
buff[int_str_len] = '\0';
|
||||
file[0].sum = strdup(buff);
|
||||
} else {
|
||||
file[0].sum = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void write_batch_csums_file(void *buff, int bytes_to_write)
|
||||
{
|
||||
static int fdb_open = 1;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_csums_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch csums file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
fdb_open = 0;
|
||||
}
|
||||
|
||||
/* Write buffer to batch csums file */
|
||||
|
||||
if (write(fdb, buff, bytes_to_write) == -1) {
|
||||
rprintf(FERROR, "Batch file %s write error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_batch_csums_file(void)
|
||||
{
|
||||
close(fdb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write csum info to batch file
|
||||
*
|
||||
* @todo This will break if s->count is ever larger than maxint. The
|
||||
* batch code should probably be changed to consistently use the
|
||||
* variable-length integer routines, which is probably a compatible
|
||||
* change.
|
||||
**/
|
||||
void write_batch_csum_info(int *flist_entry, int flist_count,
|
||||
struct sum_struct *s)
|
||||
{
|
||||
size_t i;
|
||||
int int_count;
|
||||
extern int csum_length;
|
||||
|
||||
fdb_open = 1;
|
||||
|
||||
write_batch_csums_file(flist_entry, sizeof(int));
|
||||
int_count = s ? (int) s->count : 0;
|
||||
write_batch_csums_file(&int_count, sizeof int_count);
|
||||
|
||||
if (s) {
|
||||
for (i = 0; i < s->count; i++) {
|
||||
write_batch_csums_file(&s->sums[i].sum1, sizeof(uint32));
|
||||
if ((*flist_entry == flist_count - 1)
|
||||
&& (i == s->count - 1)) {
|
||||
fdb_close = 1;
|
||||
}
|
||||
write_batch_csums_file(s->sums[i].sum2, csum_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int read_batch_csums_file(char *buff, int len)
|
||||
{
|
||||
static int fdb_open = 1;
|
||||
int bytes_read;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_csums_file, sizeof(filename));
|
||||
|
||||
/* Open batch flist file for reading */
|
||||
fdb = do_open(filename, O_RDONLY, 0);
|
||||
if (fdb == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
fdb_open = 0;
|
||||
}
|
||||
|
||||
/* Read csums batch file */
|
||||
|
||||
bytes_read = read(fdb, buff, len);
|
||||
|
||||
if (bytes_read == -1) {
|
||||
rprintf(FERROR, "Batch file %s read error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void read_batch_csum_info(int flist_entry, struct sum_struct *s,
|
||||
int *checksums_match)
|
||||
{
|
||||
int i;
|
||||
int file_flist_entry;
|
||||
int file_chunk_ct;
|
||||
uint32 file_sum1;
|
||||
char file_sum2[SUM_LENGTH];
|
||||
extern int csum_length;
|
||||
|
||||
read_batch_csums_file((char *) &file_flist_entry, sizeof(int));
|
||||
if (file_flist_entry != flist_entry) {
|
||||
rprintf(FINFO, "file_flist_entry (%d) != flist_entry (%d)\n",
|
||||
file_flist_entry, flist_entry);
|
||||
close(fdb);
|
||||
exit_cleanup(1);
|
||||
|
||||
} else {
|
||||
read_batch_csums_file((char *) &file_chunk_ct,
|
||||
sizeof(int));
|
||||
*checksums_match = 1;
|
||||
for (i = 0; i < file_chunk_ct; i++) {
|
||||
|
||||
read_batch_csums_file((char *) &file_sum1,
|
||||
sizeof(uint32));
|
||||
read_batch_csums_file(file_sum2, csum_length);
|
||||
|
||||
if ((s->sums[i].sum1 != file_sum1) ||
|
||||
(memcmp(s->sums[i].sum2, file_sum2, csum_length)
|
||||
!= 0)) {
|
||||
*checksums_match = 0;
|
||||
}
|
||||
} /* end for */
|
||||
}
|
||||
}
|
||||
|
||||
void write_batch_delta_file(char *buff, int bytes_to_write)
|
||||
{
|
||||
static int fdb_delta_open = 1;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_delta_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_delta_file, sizeof(filename));
|
||||
|
||||
/*
|
||||
* Open batch delta file for writing;
|
||||
* create it if it doesn't exist
|
||||
*/
|
||||
fdb_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IREAD | S_IWRITE);
|
||||
if (fdb_delta == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
fdb_delta_open = 0;
|
||||
}
|
||||
|
||||
/* Write buffer to batch delta file */
|
||||
|
||||
if (write(fdb_delta, buff, bytes_to_write) == -1) {
|
||||
rprintf(FERROR, "Batch file %s write error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_batch_delta_file(void)
|
||||
{
|
||||
close(fdb_delta);
|
||||
}
|
||||
|
||||
int read_batch_delta_file(char *buff, int len)
|
||||
{
|
||||
static int fdb_delta_open = 1;
|
||||
int bytes_read;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (fdb_delta_open) {
|
||||
/* Set up file extension */
|
||||
strlcpy(filename, batch_prefix, sizeof(filename));
|
||||
strlcat(filename, rsync_delta_file, sizeof(filename));
|
||||
|
||||
/* Open batch flist file for reading */
|
||||
fdb_delta = do_open(filename, O_RDONLY, 0);
|
||||
if (fdb_delta == -1) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
fdb_delta_open = 0;
|
||||
}
|
||||
|
||||
/* Read delta batch file */
|
||||
|
||||
bytes_read = read(fdb_delta, buff, len);
|
||||
|
||||
if (bytes_read == -1) {
|
||||
rprintf(FERROR, "Batch file %s read error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(fdb_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void show_flist(int index, struct file_struct **fptr)
|
||||
|
||||
64
checksum.c
64
checksum.c
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -23,7 +23,7 @@ int csum_length=2; /* initial value */
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
int checksum_seed = 0;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
|
||||
/*
|
||||
@@ -38,9 +38,9 @@ uint32 get_checksum1(char *buf1,int len)
|
||||
|
||||
s1 = s2 = 0;
|
||||
for (i = 0; i < (len-4); i+=4) {
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
|
||||
10*CHAR_OFFSET;
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
|
||||
@@ -62,15 +62,15 @@ void get_checksum2(char *buf,int len,char *sum)
|
||||
len1 = len;
|
||||
if (!buf1) out_of_memory("get_checksum2");
|
||||
}
|
||||
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
|
||||
memcpy(buf1,buf,len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(buf1,len,checksum_seed);
|
||||
len += 4;
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ void get_checksum2(char *buf,int len,char *sum)
|
||||
if (len - i > 0 || protocol_version >= 27) {
|
||||
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
|
||||
}
|
||||
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
|
||||
@@ -94,35 +94,29 @@ void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
struct map_struct *buf;
|
||||
int fd;
|
||||
OFF_T len = size;
|
||||
char tmpchunk[CSUM_CHUNK];
|
||||
struct mdfour m;
|
||||
|
||||
|
||||
memset(sum,0,MD4_SUM_LENGTH);
|
||||
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) return;
|
||||
|
||||
buf = map_file(fd,size);
|
||||
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
|
||||
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0) {
|
||||
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
|
||||
}
|
||||
if (len - i > 0 || protocol_version >= 27) {
|
||||
mdfour_update(&m, (uchar *)tmpchunk, (len-i));
|
||||
}
|
||||
* even when there are no more bytes. */
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, len-i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
|
||||
@@ -135,13 +129,13 @@ static int sumresidue;
|
||||
static char sumrbuf[CSUM_CHUNK];
|
||||
static struct mdfour md;
|
||||
|
||||
void sum_init(void)
|
||||
void sum_init(int seed)
|
||||
{
|
||||
char s[4];
|
||||
mdfour_begin(&md);
|
||||
sumresidue=0;
|
||||
SIVAL(s,0,checksum_seed);
|
||||
sum_update(s,4);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +172,7 @@ void sum_update(char *p, int len)
|
||||
sumresidue = len-i;
|
||||
memcpy(sumrbuf,p+i,sumresidue);
|
||||
} else {
|
||||
sumresidue = 0;
|
||||
sumresidue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
72
cleanup.c
72
cleanup.c
@@ -1,19 +1,19 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
|
||||
Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int io_error;
|
||||
extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
|
||||
/**
|
||||
* Close all open sockets and files, allowing a (somewhat) graceful
|
||||
* shutdown() of socket connections. This eliminates the abortive
|
||||
@@ -38,9 +42,8 @@ void close_all(void)
|
||||
for (fd = max_fd; fd >= 0; fd--) {
|
||||
ret = fstat(fd,&st);
|
||||
if (fstat(fd,&st) == 0) {
|
||||
if (is_a_socket(fd)) {
|
||||
if (is_a_socket(fd))
|
||||
ret = shutdown(fd, 2);
|
||||
}
|
||||
ret = close(fd);
|
||||
}
|
||||
}
|
||||
@@ -65,15 +68,13 @@ void close_all(void)
|
||||
* --partial is selected. We need to ensure that the partial file is
|
||||
* kept if any real data has been transferred.
|
||||
**/
|
||||
int cleanup_got_literal=0;
|
||||
int cleanup_got_literal = 0;
|
||||
|
||||
static char *cleanup_fname;
|
||||
static char *cleanup_new_fname;
|
||||
static struct file_struct *cleanup_file;
|
||||
static int cleanup_fd1, cleanup_fd2;
|
||||
static struct map_struct *cleanup_buf;
|
||||
static int cleanup_pid = 0;
|
||||
extern int io_error;
|
||||
static int cleanup_fd_r, cleanup_fd_w;
|
||||
static pid_t cleanup_pid = 0;
|
||||
|
||||
pid_t cleanup_child_pid = -1;
|
||||
|
||||
@@ -85,8 +86,6 @@ pid_t cleanup_child_pid = -1;
|
||||
void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
int ocode = code;
|
||||
extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
static int inside_cleanup = 0;
|
||||
|
||||
if (inside_cleanup > 10) {
|
||||
@@ -98,37 +97,39 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
code, file, line);
|
||||
}
|
||||
|
||||
if (cleanup_child_pid != -1) {
|
||||
int status;
|
||||
if (waitpid(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) {
|
||||
status = WEXITSTATUS(status);
|
||||
if (status > code) code = status;
|
||||
if (status > code)
|
||||
code = status;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanup_got_literal && cleanup_fname && keep_partial) {
|
||||
if (cleanup_got_literal && cleanup_fname && keep_partial
|
||||
&& handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
|
||||
char *fname = cleanup_fname;
|
||||
cleanup_fname = NULL;
|
||||
if (cleanup_buf) unmap_file(cleanup_buf);
|
||||
if (cleanup_fd1 != -1) close(cleanup_fd1);
|
||||
if (cleanup_fd2 != -1) close(cleanup_fd2);
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file);
|
||||
if (cleanup_fd_r != -1)
|
||||
close(cleanup_fd_r);
|
||||
if (cleanup_fd_w != -1)
|
||||
close(cleanup_fd_w);
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file, 0);
|
||||
}
|
||||
io_flush();
|
||||
io_flush(FULL_FLUSH);
|
||||
if (cleanup_fname)
|
||||
do_unlink(cleanup_fname);
|
||||
if (code) {
|
||||
if (code)
|
||||
kill_all(SIGUSR1);
|
||||
}
|
||||
if ((cleanup_pid != 0) && (cleanup_pid == (int) getpid())) {
|
||||
if (cleanup_pid && cleanup_pid == getpid()) {
|
||||
char *pidf = lp_pid_file();
|
||||
if (pidf && *pidf) {
|
||||
if (pidf && *pidf)
|
||||
unlink(lp_pid_file());
|
||||
}
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
@@ -138,11 +139,13 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
code = RERR_VANISHED;
|
||||
}
|
||||
|
||||
if (code) log_exit(code, file, line);
|
||||
if (code)
|
||||
log_exit(code, file, line);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
|
||||
ocode, file, line, code);
|
||||
}
|
||||
|
||||
close_all();
|
||||
exit(code);
|
||||
@@ -156,17 +159,16 @@ void cleanup_disable(void)
|
||||
|
||||
|
||||
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
|
||||
struct map_struct *buf, int fd1, int fd2)
|
||||
int fd_r, int fd_w)
|
||||
{
|
||||
cleanup_fname = fnametmp;
|
||||
cleanup_new_fname = fname;
|
||||
cleanup_file = file;
|
||||
cleanup_buf = buf;
|
||||
cleanup_fd1 = fd1;
|
||||
cleanup_fd2 = fd2;
|
||||
cleanup_fd_r = fd_r;
|
||||
cleanup_fd_w = fd_w;
|
||||
}
|
||||
|
||||
void cleanup_set_pid(int pid)
|
||||
void cleanup_set_pid(pid_t pid)
|
||||
{
|
||||
cleanup_pid = pid;
|
||||
}
|
||||
|
||||
178
clientname.c
178
clientname.c
@@ -1,20 +1,20 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
|
||||
rsync -- fast file replication program
|
||||
|
||||
|
||||
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
|
||||
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/**
|
||||
* @file clientname.c
|
||||
*
|
||||
*
|
||||
* Functions for looking up the remote name or addr of a socket.
|
||||
*
|
||||
* This file is now converted to use the new-style getaddrinfo()
|
||||
@@ -39,33 +39,30 @@ extern int am_server;
|
||||
|
||||
|
||||
/**
|
||||
* Return the IP addr of the client as a string
|
||||
* Return the IP addr of the client as a string
|
||||
**/
|
||||
char *client_addr(int fd)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
char *ssh_client, *p;
|
||||
int len;
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
char *ssh_info, *p;
|
||||
|
||||
if (initialised) return addr_buf;
|
||||
if (initialised)
|
||||
return addr_buf;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) {
|
||||
/* daemon over --rsh mode */
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
strcpy(addr_buf, "0.0.0.0");
|
||||
if ((ssh_client = getenv("SSH_CLIENT")) != NULL) {
|
||||
/* truncate SSH_CLIENT to just IP address */
|
||||
p = strchr(ssh_client, ' ');
|
||||
if (p) {
|
||||
len = MIN((unsigned int) (p - ssh_client),
|
||||
sizeof(addr_buf) - 1);
|
||||
strncpy(addr_buf, ssh_client, len);
|
||||
*(addr_buf + len) = '\0';
|
||||
}
|
||||
if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
|
||||
|| (ssh_info = getenv("SSH_CLIENT")) != NULL
|
||||
|| (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
|
||||
strlcpy(addr_buf, ssh_info, sizeof addr_buf);
|
||||
/* Truncate the value to just the IP address. */
|
||||
if ((p = strchr(addr_buf, ' ')) != NULL)
|
||||
*p = '\0';
|
||||
}
|
||||
} else {
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
@@ -101,58 +98,56 @@ char *client_name(int fd)
|
||||
static char name_buf[100];
|
||||
static char port_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss, *ssp;
|
||||
struct sockaddr_in sin;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t ss_len;
|
||||
|
||||
if (initialised) return name_buf;
|
||||
if (initialised)
|
||||
return name_buf;
|
||||
|
||||
strcpy(name_buf, default_name);
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) {
|
||||
/* daemon over --rsh mode */
|
||||
memset(&ss, 0, sizeof ss);
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
char *addr = client_addr(fd);
|
||||
#ifdef INET6
|
||||
int dots = 0;
|
||||
char *p;
|
||||
struct addrinfo hint, *answer;
|
||||
int err;
|
||||
|
||||
for (p = addr; *p && (dots <= 3); p++) {
|
||||
if (*p == '.')
|
||||
dots++;
|
||||
}
|
||||
if (dots > 3) {
|
||||
/* more than 4 parts to IP address, must be ipv6 */
|
||||
ssp = (struct sockaddr_storage *) &sin6;
|
||||
ss_len = sizeof sin6;
|
||||
memset(ssp, 0, ss_len);
|
||||
inet_pton(AF_INET6, addr, &sin6.sin6_addr);
|
||||
sin6.sin6_family = AF_INET6;
|
||||
} else
|
||||
memset(&hint, 0, sizeof hint);
|
||||
|
||||
#ifdef AI_NUMERICHOST
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
{
|
||||
ssp = (struct sockaddr_storage *) &sin;
|
||||
ss_len = sizeof sin;
|
||||
memset(ssp, 0, ss_len);
|
||||
inet_pton(AF_INET, addr, &sin.sin_addr);
|
||||
sin.sin_family = AF_INET;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FLOG, "malformed address %s: %s\n",
|
||||
addr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
switch (answer->ai_family) {
|
||||
case AF_INET:
|
||||
ss_len = sizeof (struct sockaddr_in);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ss_len = sizeof (struct sockaddr_in6);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
freeaddrinfo(answer);
|
||||
} else {
|
||||
ss_len = sizeof ss;
|
||||
ssp = &ss;
|
||||
|
||||
client_sockaddr(fd, &ss, &ss_len);
|
||||
|
||||
}
|
||||
|
||||
if (!lookup_name(fd, ssp, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf))
|
||||
check_name(fd, ssp, name_buf);
|
||||
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf) == 0)
|
||||
check_name(fd, &ss, name_buf);
|
||||
|
||||
return name_buf;
|
||||
}
|
||||
@@ -169,17 +164,16 @@ void client_sockaddr(int fd,
|
||||
struct sockaddr_storage *ss,
|
||||
socklen_t *ss_len)
|
||||
{
|
||||
memset(ss, 0, sizeof(*ss));
|
||||
memset(ss, 0, sizeof *ss);
|
||||
|
||||
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
|
||||
/* FIXME: Can we really not continue? */
|
||||
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
|
||||
fd, strerror(errno));
|
||||
rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
if (get_sockaddr_family(ss) == AF_INET6 &&
|
||||
if (get_sockaddr_family(ss) == AF_INET6 &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
|
||||
/* OK, so ss is in the IPv6 family, but it is really
|
||||
* an IPv4 address: something like
|
||||
@@ -190,12 +184,12 @@ void client_sockaddr(int fd,
|
||||
struct sockaddr_in6 sin6;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
memcpy(&sin6, ss, sizeof(sin6));
|
||||
memcpy(&sin6, ss, sizeof sin6);
|
||||
sin = (struct sockaddr_in *)ss;
|
||||
memset(sin, 0, sizeof(*sin));
|
||||
memset(sin, 0, sizeof *sin);
|
||||
sin->sin_family = AF_INET;
|
||||
*ss_len = sizeof(struct sockaddr_in);
|
||||
#ifdef HAVE_SOCKADDR_LEN
|
||||
*ss_len = sizeof (struct sockaddr_in);
|
||||
#if HAVE_SOCKADDR_IN_LEN
|
||||
sin->sin_len = *ss_len;
|
||||
#endif
|
||||
sin->sin_port = sin6.sin6_port;
|
||||
@@ -204,8 +198,8 @@ void client_sockaddr(int fd,
|
||||
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
|
||||
* to be present in the Linux headers. */
|
||||
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
|
||||
sizeof(sin->sin_addr));
|
||||
}
|
||||
sizeof sin->sin_addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -221,7 +215,7 @@ int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
char *port_buf, size_t port_buf_len)
|
||||
{
|
||||
int name_err;
|
||||
|
||||
|
||||
/* reverse lookup */
|
||||
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
|
||||
name_buf, name_buf_len,
|
||||
@@ -229,9 +223,8 @@ int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (name_err != 0) {
|
||||
strcpy(name_buf, default_name);
|
||||
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
|
||||
client_addr(fd),
|
||||
gai_strerror(name_err));
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n",
|
||||
client_addr(fd), gai_strerror(name_err));
|
||||
return name_err;
|
||||
}
|
||||
|
||||
@@ -250,10 +243,9 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
{
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
const char fn[] = "compare_addrinfo_sockaddr";
|
||||
|
||||
|
||||
if (ai->ai_family != ss_family) {
|
||||
rprintf(FERROR,
|
||||
"%s: response family %d != %d\n",
|
||||
rprintf(FLOG, "%s: response family %d != %d\n",
|
||||
fn, ai->ai_family, ss_family);
|
||||
return 1;
|
||||
}
|
||||
@@ -264,20 +256,20 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
|
||||
sin1 = (const struct sockaddr_in *) ss;
|
||||
sin2 = (const struct sockaddr_in *) ai->ai_addr;
|
||||
|
||||
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
|
||||
sizeof sin1->sin_addr);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
else if (ss_family == AF_INET6) {
|
||||
if (ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *sin1, *sin2;
|
||||
|
||||
sin1 = (const struct sockaddr_in6 *) ss;
|
||||
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
|
||||
|
||||
if (ai->ai_addrlen < sizeof(struct sockaddr_in6)) {
|
||||
rprintf(FERROR,
|
||||
"%s: too short sockaddr_in6; length=%d\n",
|
||||
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
|
||||
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
|
||||
fn, ai->ai_addrlen);
|
||||
return 1;
|
||||
}
|
||||
@@ -293,10 +285,9 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
return 0;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
else {
|
||||
/* don't know */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* don't know */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -318,14 +309,13 @@ int check_name(int fd,
|
||||
int error;
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = ss_family;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
error = getaddrinfo(name_buf, NULL, &hints, &res0);
|
||||
if (error) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
|
||||
rprintf(FLOG, "forward name lookup for %s failed: %s\n",
|
||||
name_buf, gai_strerror(error));
|
||||
strcpy(name_buf, default_name);
|
||||
return error;
|
||||
@@ -342,23 +332,17 @@ int check_name(int fd,
|
||||
if (!res0) {
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": no known address for \"%s\": "
|
||||
"spoofed address?\n",
|
||||
name_buf);
|
||||
rprintf(FLOG, "no known address for \"%s\": "
|
||||
"spoofed address?\n", name_buf);
|
||||
strcpy(name_buf, default_name);
|
||||
} else if (res == NULL) {
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": %s is not a known address for \"%s\": "
|
||||
"spoofed address?\n",
|
||||
client_addr(fd),
|
||||
name_buf);
|
||||
rprintf(FLOG, "%s is not a known address for \"%s\": "
|
||||
"spoofed address?\n", client_addr(fd), name_buf);
|
||||
strcpy(name_buf, default_name);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
311
clientserver.c
311
clientserver.c
@@ -27,17 +27,32 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
extern int module_id;
|
||||
extern int read_only;
|
||||
extern int verbose;
|
||||
extern int rsync_port;
|
||||
char *auth_user;
|
||||
extern int kludge_around_eof;
|
||||
extern int daemon_over_rsh;
|
||||
extern int list_only;
|
||||
extern int sanitize_paths;
|
||||
extern int filesfrom_fd;
|
||||
extern int remote_protocol;
|
||||
extern int protocol_version;
|
||||
extern struct exclude_struct **server_exclude_list;
|
||||
extern int io_timeout;
|
||||
extern int orig_umask;
|
||||
extern int no_detach;
|
||||
extern int default_af_hint;
|
||||
extern char *bind_address;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
extern char *exclude_path_prefix;
|
||||
extern char *config_file;
|
||||
extern char *files_from;
|
||||
|
||||
char *auth_user;
|
||||
|
||||
/**
|
||||
* Run a client connected to an rsyncd. The alternative to this
|
||||
@@ -56,65 +71,55 @@ extern char *exclude_path_prefix;
|
||||
int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
{
|
||||
int fd, ret;
|
||||
char *p, *user=NULL;
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
char *p, *user = NULL;
|
||||
|
||||
/* this is redundant with code in start_inband_exchange(), but
|
||||
* this short-circuits a problem before we open a socket, and
|
||||
* the extra check won't hurt */
|
||||
/* This is redundant with code in start_inband_exchange(), but this
|
||||
* short-circuits a problem in the client before we open a socket,
|
||||
* and the extra check won't hurt. */
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR,"ERROR: The remote path must start with a module name not a /\n");
|
||||
rprintf(FERROR,
|
||||
"ERROR: The remote path must start with a module name not a /\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = strchr(host, '@');
|
||||
if (p) {
|
||||
if ((p = strchr(host, '@')) != NULL) {
|
||||
user = host;
|
||||
host = p+1;
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (verbose >= 2) {
|
||||
/* FIXME: If we're going to use a socket program for
|
||||
* testing, then this message is wrong. We need to
|
||||
* say something like "(except really using %s)" */
|
||||
rprintf(FINFO, "opening tcp connection to %s port %d\n",
|
||||
host, rsync_port);
|
||||
}
|
||||
fd = open_socket_out_wrapped(host, rsync_port, bind_address,
|
||||
default_af_hint);
|
||||
if (fd == -1) {
|
||||
if (fd == -1)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
ret = start_inband_exchange(user, path, fd, fd, argc);
|
||||
|
||||
return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
|
||||
}
|
||||
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
int argc)
|
||||
{
|
||||
int i;
|
||||
char *sargs[MAX_ARGS];
|
||||
int sargc = 0;
|
||||
char line[MAXPATHLEN];
|
||||
char *p;
|
||||
extern int kludge_around_eof;
|
||||
extern int am_sender;
|
||||
extern int daemon_over_rsh;
|
||||
extern int list_only;
|
||||
|
||||
if (argc == 0 && !am_sender)
|
||||
list_only = 1;
|
||||
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR, "ERROR: The remote path must start with a module name\n");
|
||||
rprintf(FERROR,
|
||||
"ERROR: The remote path must start with a module name\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!user) user = getenv("USER");
|
||||
if (!user) user = getenv("LOGNAME");
|
||||
if (!user)
|
||||
user = getenv("USER");
|
||||
if (!user)
|
||||
user = getenv("LOGNAME");
|
||||
|
||||
/* set daemon_over_rsh to false since we need to build the
|
||||
* true set of args passed through the rsh/ssh connection;
|
||||
@@ -129,9 +134,9 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
|
||||
sargs[sargc] = NULL;
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", PROTOCOL_VERSION);
|
||||
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
|
||||
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
rprintf(FERROR, "rsync: did not see server greeting\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -155,7 +160,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
kludge_around_eof = list_only && (protocol_version < 25);
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
rprintf(FERROR, "rsync: didn't get server startup line\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -165,7 +170,8 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(line,"@RSYNCD: OK") == 0) break;
|
||||
if (strcmp(line,"@RSYNCD: OK") == 0)
|
||||
break;
|
||||
|
||||
if (strcmp(line,"@RSYNCD: EXIT") == 0) {
|
||||
/* This is sent by recent versions of the
|
||||
@@ -176,7 +182,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
}
|
||||
|
||||
if (strncmp(line, "@ERROR", 6) == 0) {
|
||||
rprintf(FERROR,"%s\n", line);
|
||||
rprintf(FERROR, "%s\n", line);
|
||||
/* This is always fatal; the server will now
|
||||
* close the socket. */
|
||||
return RERR_STARTCLIENT;
|
||||
@@ -192,8 +198,8 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
io_printf(f_out, "\n");
|
||||
|
||||
if (protocol_version < 23) {
|
||||
if (protocol_version == 22 || (protocol_version > 17 && !am_sender))
|
||||
io_start_multiplex_in(f_in);
|
||||
if (protocol_version == 22 || !am_sender)
|
||||
io_start_multiplex_in();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -203,8 +209,9 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i)
|
||||
{
|
||||
int argc=0;
|
||||
char *argv[MAX_ARGS];
|
||||
int argc = 0;
|
||||
int maxargs;
|
||||
char **argv;
|
||||
char **argp;
|
||||
char line[MAXPATHLEN];
|
||||
uid_t uid = (uid_t)-2; /* canonically "nobody" */
|
||||
@@ -214,35 +221,36 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
char *host = client_name(f_in);
|
||||
char *name = lp_name(i);
|
||||
int use_chroot = lp_use_chroot(i);
|
||||
int start_glob=0;
|
||||
int start_glob = 0;
|
||||
int ret;
|
||||
char *request=NULL;
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
char *request = NULL;
|
||||
|
||||
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
|
||||
rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
|
||||
rprintf(FLOG, "rsync denied on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
io_printf(f_out, "@ERROR: access denied to %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
if (!lp_list(i))
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", name);
|
||||
else {
|
||||
io_printf(f_out,
|
||||
"@ERROR: access denied to %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (am_daemon && am_server) {
|
||||
rprintf(FINFO, "rsync allowed access on module %s from %s (%s)\n",
|
||||
rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
}
|
||||
|
||||
if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
|
||||
if (errno) {
|
||||
rprintf(FERROR,"failed to open lock file %s : %s\n",
|
||||
lp_lock_file(i), strerror(errno));
|
||||
io_printf(f_out, "@ERROR: failed to open lock file %s : %s\n",
|
||||
lp_lock_file(i), strerror(errno));
|
||||
rsyserr(FLOG, errno, "failed to open lock file %s",
|
||||
lp_lock_file(i));
|
||||
io_printf(f_out, "@ERROR: failed to open lock file %s\n",
|
||||
lp_lock_file(i));
|
||||
} else {
|
||||
rprintf(FERROR,"max connections (%d) reached\n",
|
||||
rprintf(FLOG, "max connections (%d) reached\n",
|
||||
lp_max_connections(i));
|
||||
io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n",
|
||||
lp_max_connections(i));
|
||||
@@ -250,11 +258,10 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
auth_user = auth_server(f_in, f_out, i, addr, "@RSYNCD: AUTHREQD ");
|
||||
|
||||
if (!auth_user) {
|
||||
rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
io_printf(f_out, "@ERROR: auth failed on module %s\n", name);
|
||||
return -1;
|
||||
@@ -262,13 +269,13 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
module_id = i;
|
||||
|
||||
am_root = (getuid() == 0);
|
||||
am_root = (MY_UID() == 0);
|
||||
|
||||
if (am_root) {
|
||||
p = lp_uid(i);
|
||||
if (!name_to_uid(p, &uid)) {
|
||||
if (!isdigit(* (unsigned char *) p)) {
|
||||
rprintf(FERROR,"Invalid uid %s\n", p);
|
||||
if (!isdigit(*(unsigned char *)p)) {
|
||||
rprintf(FLOG, "Invalid uid %s\n", p);
|
||||
io_printf(f_out, "@ERROR: invalid uid %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
@@ -277,8 +284,8 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
p = lp_gid(i);
|
||||
if (!name_to_gid(p, &gid)) {
|
||||
if (!isdigit(* (unsigned char *) p)) {
|
||||
rprintf(FERROR,"Invalid gid %s\n", p);
|
||||
if (!isdigit(*(unsigned char *)p)) {
|
||||
rprintf(FLOG, "Invalid gid %s\n", p);
|
||||
io_printf(f_out, "@ERROR: invalid gid %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
@@ -298,16 +305,19 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
exclude_path_prefix = "";
|
||||
|
||||
p = lp_include_from(i);
|
||||
add_exclude_file(&server_exclude_list, p, MISSING_FATAL, ADD_INCLUDE);
|
||||
add_exclude_file(&server_exclude_list, p,
|
||||
XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
|
||||
|
||||
p = lp_include(i);
|
||||
add_exclude_line(&server_exclude_list, p, ADD_INCLUDE);
|
||||
add_exclude(&server_exclude_list, p,
|
||||
XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE);
|
||||
|
||||
p = lp_exclude_from(i);
|
||||
add_exclude_file(&server_exclude_list, p, MISSING_FATAL, ADD_EXCLUDE);
|
||||
add_exclude_file(&server_exclude_list, p,
|
||||
XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_exclude(i);
|
||||
add_exclude_line(&server_exclude_list, p, ADD_EXCLUDE);
|
||||
add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT);
|
||||
|
||||
exclude_path_prefix = NULL;
|
||||
|
||||
@@ -327,20 +337,20 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
* in which case we fail.
|
||||
*/
|
||||
if (chroot(lp_path(i))) {
|
||||
rsyserr(FERROR, errno, "chroot %s failed", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chroot %s failed", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/", 0)) {
|
||||
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
|
||||
if (!push_dir("/")) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!push_dir(lp_path(i), 0)) {
|
||||
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
|
||||
if (!push_dir(lp_path(i))) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -359,7 +369,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
* all their supplementary groups. */
|
||||
|
||||
if (setgid(gid)) {
|
||||
rsyserr(FERROR, errno, "setgid %d failed", (int) gid);
|
||||
rsyserr(FLOG, errno, "setgid %d failed", (int)gid);
|
||||
io_printf(f_out, "@ERROR: setgid failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -367,69 +377,56 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
/* Get rid of any supplementary groups this process
|
||||
* might have inheristed. */
|
||||
if (setgroups(1, &gid)) {
|
||||
rsyserr(FERROR, errno, "setgroups failed");
|
||||
rsyserr(FLOG, errno, "setgroups failed");
|
||||
io_printf(f_out, "@ERROR: setgroups failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (setuid(uid)) {
|
||||
rsyserr(FERROR, errno, "setuid %d failed", (int) uid);
|
||||
rsyserr(FLOG, errno, "setuid %d failed", (int)uid);
|
||||
io_printf(f_out, "@ERROR: setuid failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
am_root = (getuid() == 0);
|
||||
am_root = (MY_UID() == 0);
|
||||
}
|
||||
|
||||
io_printf(f_out, "@RSYNCD: OK\n");
|
||||
|
||||
maxargs = MAX_ARGS;
|
||||
if (!(argv = new_array(char *, maxargs)))
|
||||
out_of_memory("rsync_module");
|
||||
argv[argc++] = "rsyncd";
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!*line) break;
|
||||
if (!*line)
|
||||
break;
|
||||
|
||||
p = line;
|
||||
|
||||
argv[argc] = strdup(p);
|
||||
if (!argv[argc]) {
|
||||
return -1;
|
||||
if (argc == maxargs) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("rsync_module");
|
||||
}
|
||||
if (!(argv[argc] = strdup(p)))
|
||||
out_of_memory("rsync_module");
|
||||
|
||||
if (start_glob) {
|
||||
if (start_glob == 1) {
|
||||
request = strdup(p);
|
||||
start_glob++;
|
||||
}
|
||||
glob_expand(name, argv, &argc, MAX_ARGS);
|
||||
} else {
|
||||
glob_expand(name, &argv, &argc, &maxargs);
|
||||
} else
|
||||
argc++;
|
||||
}
|
||||
|
||||
if (strcmp(line,".") == 0) {
|
||||
if (strcmp(line, ".") == 0)
|
||||
start_glob = 1;
|
||||
}
|
||||
|
||||
if (argc == MAX_ARGS) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sanitize_paths) {
|
||||
/*
|
||||
* Note that this is applied to all parameters, whether or not
|
||||
* they are filenames, but no other legal parameters contain
|
||||
* the forms that need to be sanitized so it doesn't hurt;
|
||||
* it is not known at this point which parameters are files
|
||||
* and which aren't.
|
||||
*/
|
||||
for (i = 1; i < argc; i++) {
|
||||
sanitize_path(argv[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
argp = argv;
|
||||
@@ -440,12 +437,12 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
if (request) {
|
||||
if (*auth_user) {
|
||||
rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
|
||||
am_sender?"on":"to",
|
||||
rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n",
|
||||
am_sender ? "on" : "to",
|
||||
request, auth_user, host, addr);
|
||||
} else {
|
||||
rprintf(FINFO,"rsync %s %s from %s (%s)\n",
|
||||
am_sender?"on":"to",
|
||||
rprintf(FLOG, "rsync %s %s from %s (%s)\n",
|
||||
am_sender ? "on" : "to",
|
||||
request, host, addr);
|
||||
}
|
||||
free(request);
|
||||
@@ -453,31 +450,31 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
#ifndef DEBUG
|
||||
/* don't allow the logs to be flooded too fast */
|
||||
if (verbose > 1) verbose = 1;
|
||||
if (verbose > lp_max_verbosity())
|
||||
verbose = lp_max_verbosity();
|
||||
#endif
|
||||
|
||||
if (protocol_version < 23) {
|
||||
if (protocol_version == 22 || (protocol_version > 17 && am_sender))
|
||||
io_start_multiplex_out(f_out);
|
||||
if (protocol_version < 23
|
||||
&& (protocol_version == 22 || am_sender))
|
||||
io_start_multiplex_out();
|
||||
else if (!ret) {
|
||||
/* We have to get I/O multiplexing started so that we can
|
||||
* get the error back to the client. This means getting
|
||||
* the protocol setup finished first in later versions. */
|
||||
setup_protocol(f_out, f_in);
|
||||
if (files_from && !am_sender && strcmp(files_from, "-") != 0)
|
||||
write_byte(f_out, 0);
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
/* For later protocol versions, we don't start multiplexing
|
||||
* until we've configured nonblocking in start_server. That
|
||||
* means we're in a sticky situation now: there's no way to
|
||||
* convey errors to the client. */
|
||||
|
||||
/* FIXME: Hold off on reporting option processing errors until
|
||||
* we've set up nonblocking and multiplexed IO and can get the
|
||||
* message back to them. */
|
||||
if (!ret) {
|
||||
option_error();
|
||||
msleep(400);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (lp_timeout(i)) {
|
||||
extern int io_timeout;
|
||||
if (lp_timeout(i))
|
||||
io_timeout = lp_timeout(i);
|
||||
}
|
||||
|
||||
start_server(f_in, f_out, argc, argp);
|
||||
|
||||
@@ -491,9 +488,10 @@ static void send_listing(int fd)
|
||||
int n = lp_numservices();
|
||||
int i;
|
||||
|
||||
for (i=0;i<n;i++)
|
||||
for (i = 0; i < n; i++) {
|
||||
if (lp_list(i))
|
||||
io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i));
|
||||
}
|
||||
|
||||
if (protocol_version >= 25)
|
||||
io_printf(fd,"@RSYNCD: EXIT\n");
|
||||
@@ -506,13 +504,12 @@ int start_daemon(int f_in, int f_out)
|
||||
{
|
||||
char line[200];
|
||||
char *motd;
|
||||
int i = -1;
|
||||
extern char *config_file;
|
||||
extern int am_server;
|
||||
int i;
|
||||
|
||||
if (!lp_load(config_file, 0)) {
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
|
||||
if (!lp_load(config_file, 0))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
log_init();
|
||||
|
||||
@@ -522,25 +519,25 @@ int start_daemon(int f_in, int f_out)
|
||||
set_nonblocking(f_in);
|
||||
}
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", PROTOCOL_VERSION);
|
||||
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
|
||||
|
||||
motd = lp_motd_file();
|
||||
if (motd && *motd) {
|
||||
FILE *f = fopen(motd,"r");
|
||||
while (f && !feof(f)) {
|
||||
int len = fread(line, 1, sizeof(line)-1, f);
|
||||
int len = fread(line, 1, sizeof line - 1, f);
|
||||
if (len > 0) {
|
||||
line[len] = 0;
|
||||
io_printf(f_out, "%s", line);
|
||||
}
|
||||
}
|
||||
if (f) fclose(f);
|
||||
if (f)
|
||||
fclose(f);
|
||||
io_printf(f_out, "\n");
|
||||
}
|
||||
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(line,"@RSYNCD: %d", &remote_protocol) != 1) {
|
||||
io_printf(f_out, "@ERROR: protocol startup error\n");
|
||||
@@ -549,28 +546,28 @@ int start_daemon(int f_in, int f_out)
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
|
||||
while (i == -1) {
|
||||
line[0] = 0;
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
return -1;
|
||||
}
|
||||
line[0] = 0;
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
|
||||
if (!*line || strcmp(line,"#list")==0) {
|
||||
send_listing(f_out);
|
||||
return -1;
|
||||
}
|
||||
if (!*line || strcmp(line, "#list") == 0) {
|
||||
send_listing(f_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*line == '#') {
|
||||
/* it's some sort of command that I don't understand */
|
||||
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
if (*line == '#') {
|
||||
/* it's some sort of command that I don't understand */
|
||||
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = lp_number(line);
|
||||
if (i == -1) {
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
if ((i = lp_number(line)) < 0) {
|
||||
char *addr = client_addr(f_in);
|
||||
char *host = client_name(f_in);
|
||||
rprintf(FLOG, "unknown module '%s' tried from %s (%s)\n",
|
||||
line, host, addr);
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rsync_module(f_in, f_out, i);
|
||||
@@ -579,10 +576,7 @@ int start_daemon(int f_in, int f_out)
|
||||
|
||||
int daemon_main(void)
|
||||
{
|
||||
extern char *config_file;
|
||||
extern int orig_umask;
|
||||
char *pid_file;
|
||||
extern int no_detach;
|
||||
|
||||
if (is_a_socket(STDIN_FILENO)) {
|
||||
int i;
|
||||
@@ -590,7 +584,7 @@ int daemon_main(void)
|
||||
/* we are running via inetd - close off stdout and
|
||||
* stderr so that library functions (and getopt) don't
|
||||
* try to use them. Redirect them to /dev/null */
|
||||
for (i=1;i<3;i++) {
|
||||
for (i = 1; i < 3; i++) {
|
||||
close(i);
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
@@ -601,13 +595,12 @@ int daemon_main(void)
|
||||
if (!no_detach)
|
||||
become_daemon();
|
||||
|
||||
if (!lp_load(config_file, 1)) {
|
||||
if (!lp_load(config_file, 1))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
log_init();
|
||||
|
||||
rprintf(FINFO, "rsyncd version %s starting, listening on port %d\n",
|
||||
rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n",
|
||||
RSYNC_VERSION, rsync_port);
|
||||
/* TODO: If listening on a particular address, then show that
|
||||
* address too. In fact, why not just do inet_ntop on the
|
||||
@@ -616,7 +609,7 @@ int daemon_main(void)
|
||||
if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
|
||||
char pidbuf[16];
|
||||
int fd;
|
||||
int pid = (int) getpid();
|
||||
pid_t pid = getpid();
|
||||
cleanup_set_pid(pid);
|
||||
if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC,
|
||||
0666 & ~orig_umask)) == -1) {
|
||||
@@ -624,7 +617,7 @@ int daemon_main(void)
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof(pidbuf), "%d\n", pid);
|
||||
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
|
||||
write(fd, pidbuf, strlen(pidbuf));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
38
compat.c
38
compat.c
@@ -27,37 +27,27 @@
|
||||
|
||||
int remote_protocol = 0;
|
||||
|
||||
extern int am_server;
|
||||
|
||||
extern int preserve_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_times;
|
||||
extern int always_checksum;
|
||||
extern int checksum_seed;
|
||||
|
||||
|
||||
extern int protocol_version;
|
||||
extern int verbose;
|
||||
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
if (remote_protocol == 0) {
|
||||
if (am_server) {
|
||||
remote_protocol = read_int(f_in);
|
||||
if (!read_batch)
|
||||
write_int(f_out, protocol_version);
|
||||
} else {
|
||||
write_int(f_out, protocol_version);
|
||||
remote_protocol = read_int(f_in);
|
||||
}
|
||||
remote_protocol = read_int(f_in);
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
}
|
||||
if (read_batch && remote_protocol > protocol_version) {
|
||||
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
|
||||
remote_protocol, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
|
||||
@@ -85,11 +75,9 @@ void setup_protocol(int f_out,int f_in)
|
||||
}
|
||||
|
||||
if (am_server) {
|
||||
if (read_batch || write_batch)
|
||||
checksum_seed = 32761;
|
||||
else
|
||||
if (!checksum_seed)
|
||||
checksum_seed = time(NULL);
|
||||
write_int(f_out,checksum_seed);
|
||||
write_int(f_out, checksum_seed);
|
||||
} else {
|
||||
checksum_seed = read_int(f_in);
|
||||
}
|
||||
|
||||
133
config.guess
vendored
133
config.guess
vendored
@@ -3,7 +3,7 @@
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2003-01-10'
|
||||
timestamp='2003-10-03'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
@@ -106,6 +106,7 @@ trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
|
||||
: ${TMPDIR=/tmp} ;
|
||||
{ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
|
||||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
|
||||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
|
||||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
|
||||
dummy=$tmp/dummy ;
|
||||
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
|
||||
@@ -235,74 +236,56 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
*:OpenBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
*:MicroBSD:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-microbsd${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
alpha:OSF1:*:*)
|
||||
if test $UNAME_RELEASE = "V4.0"; then
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
|
||||
fi
|
||||
# According to Compaq, /usr/sbin/psrinfo has been available on
|
||||
# OSF/1 and Tru64 systems produced since 1995. I hope that
|
||||
# covers most systems running today. This code pipes the CPU
|
||||
# types through head -n 1, so we only detect the type of CPU 0.
|
||||
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
|
||||
case "$ALPHA_CPU_TYPE" in
|
||||
"EV4 (21064)")
|
||||
UNAME_MACHINE="alpha" ;;
|
||||
"EV4.5 (21064)")
|
||||
UNAME_MACHINE="alpha" ;;
|
||||
"LCA4 (21066/21068)")
|
||||
UNAME_MACHINE="alpha" ;;
|
||||
"EV5 (21164)")
|
||||
UNAME_MACHINE="alphaev5" ;;
|
||||
"EV5.6 (21164A)")
|
||||
UNAME_MACHINE="alphaev56" ;;
|
||||
"EV5.6 (21164PC)")
|
||||
UNAME_MACHINE="alphapca56" ;;
|
||||
"EV5.7 (21164PC)")
|
||||
UNAME_MACHINE="alphapca57" ;;
|
||||
"EV6 (21264)")
|
||||
UNAME_MACHINE="alphaev6" ;;
|
||||
"EV6.7 (21264A)")
|
||||
UNAME_MACHINE="alphaev67" ;;
|
||||
"EV6.8CB (21264C)")
|
||||
UNAME_MACHINE="alphaev68" ;;
|
||||
"EV6.8AL (21264B)")
|
||||
UNAME_MACHINE="alphaev68" ;;
|
||||
"EV6.8CX (21264D)")
|
||||
UNAME_MACHINE="alphaev68" ;;
|
||||
"EV6.9A (21264/EV69A)")
|
||||
UNAME_MACHINE="alphaev69" ;;
|
||||
"EV7 (21364)")
|
||||
UNAME_MACHINE="alphaev7" ;;
|
||||
"EV7.9 (21364A)")
|
||||
UNAME_MACHINE="alphaev79" ;;
|
||||
esac
|
||||
# A Vn.n version is a released version.
|
||||
# A Tn.n version is a released field test version.
|
||||
# A Xn.n version is an unreleased experimental baselevel.
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
eval $set_cc_for_build
|
||||
cat <<EOF >$dummy.s
|
||||
.data
|
||||
\$Lformat:
|
||||
.byte 37,100,45,37,120,10,0 # "%d-%x\n"
|
||||
|
||||
.text
|
||||
.globl main
|
||||
.align 4
|
||||
.ent main
|
||||
main:
|
||||
.frame \$30,16,\$26,0
|
||||
ldgp \$29,0(\$27)
|
||||
.prologue 1
|
||||
.long 0x47e03d80 # implver \$0
|
||||
lda \$2,-1
|
||||
.long 0x47e20c21 # amask \$2,\$1
|
||||
lda \$16,\$Lformat
|
||||
mov \$0,\$17
|
||||
not \$1,\$18
|
||||
jsr \$26,printf
|
||||
ldgp \$29,0(\$26)
|
||||
mov 0,\$16
|
||||
jsr \$26,exit
|
||||
.end main
|
||||
EOF
|
||||
$CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null
|
||||
if test "$?" = 0 ; then
|
||||
case `$dummy` in
|
||||
0-0)
|
||||
UNAME_MACHINE="alpha"
|
||||
;;
|
||||
1-0)
|
||||
UNAME_MACHINE="alphaev5"
|
||||
;;
|
||||
1-1)
|
||||
UNAME_MACHINE="alphaev56"
|
||||
;;
|
||||
1-101)
|
||||
UNAME_MACHINE="alphapca56"
|
||||
;;
|
||||
2-303)
|
||||
UNAME_MACHINE="alphaev6"
|
||||
;;
|
||||
2-307)
|
||||
UNAME_MACHINE="alphaev67"
|
||||
;;
|
||||
2-1307)
|
||||
UNAME_MACHINE="alphaev68"
|
||||
;;
|
||||
3-1307)
|
||||
UNAME_MACHINE="alphaev7"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
exit 0 ;;
|
||||
Alpha*:OpenVMS:*:*)
|
||||
echo alpha-hp-vms
|
||||
exit 0 ;;
|
||||
Alpha\ *:Windows_NT*:*)
|
||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
||||
# Should we change UNAME_MACHINE based on the output of uname instead
|
||||
@@ -341,6 +324,9 @@ EOF
|
||||
NILE*:*:*:dcosx)
|
||||
echo pyramid-pyramid-svr4
|
||||
exit 0 ;;
|
||||
DRS?6000:unix:4.0:6*)
|
||||
echo sparc-icl-nx6
|
||||
exit 0 ;;
|
||||
DRS?6000:UNIX_SV:4.2*:7*)
|
||||
case `/usr/bin/uname -p` in
|
||||
sparc) echo sparc-icl-nx7 && exit 0 ;;
|
||||
@@ -748,7 +734,7 @@ EOF
|
||||
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
|
||||
exit 0 ;;
|
||||
*:UNICOS/mp:*:*)
|
||||
echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
|
||||
echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
|
||||
exit 0 ;;
|
||||
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
|
||||
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
@@ -765,7 +751,7 @@ EOF
|
||||
*:BSD/OS:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
*:FreeBSD:*:*)
|
||||
*:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
|
||||
# Determine whether the default compiler uses glibc.
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
@@ -777,7 +763,10 @@ EOF
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
|
||||
# GNU/FreeBSD systems have a "k" prefix to indicate we are using
|
||||
# FreeBSD's kernel, but not the complete OS.
|
||||
case ${LIBC} in gnu) kernel_only='k' ;; esac
|
||||
echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
|
||||
exit 0 ;;
|
||||
i*:CYGWIN*:*)
|
||||
echo ${UNAME_MACHINE}-pc-cygwin
|
||||
@@ -788,8 +777,8 @@ EOF
|
||||
i*:PW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-pw32
|
||||
exit 0 ;;
|
||||
x86:Interix*:3*)
|
||||
echo i586-pc-interix3
|
||||
x86:Interix*:[34]*)
|
||||
echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
|
||||
exit 0 ;;
|
||||
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
|
||||
echo i${UNAME_MACHINE}-pc-mks
|
||||
@@ -818,6 +807,9 @@ EOF
|
||||
arm*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
cris:Linux:*:*)
|
||||
echo cris-axis-linux-gnu
|
||||
exit 0 ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
@@ -896,6 +888,9 @@ EOF
|
||||
s390:Linux:*:* | s390x:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-linux
|
||||
exit 0 ;;
|
||||
sh64*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
sh*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
@@ -953,6 +948,9 @@ EOF
|
||||
LIBC=gnuaout
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __dietlibc__
|
||||
LIBC=dietlibc
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
|
||||
test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
|
||||
@@ -1054,7 +1052,7 @@ EOF
|
||||
exit 0 ;;
|
||||
M68*:*:R3V[567]*:*)
|
||||
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
|
||||
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0)
|
||||
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
|
||||
OS_REL=''
|
||||
test -r /etc/.relid \
|
||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||
@@ -1169,7 +1167,7 @@ EOF
|
||||
*:QNX:*:4*)
|
||||
echo i386-pc-qnx
|
||||
exit 0 ;;
|
||||
NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
|
||||
NSR-[DGKLNPTVWY]:NONSTOP_KERNEL:*:*)
|
||||
echo nsr-tandem-nsk${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
*:NonStop-UX:*:*)
|
||||
@@ -1210,6 +1208,9 @@ EOF
|
||||
*:ITS:*:*)
|
||||
echo pdp10-unknown-its
|
||||
exit 0 ;;
|
||||
SEI:*:*:SEIUX)
|
||||
echo mips-sei-seiux${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
|
||||
72
config.sub
vendored
72
config.sub
vendored
@@ -3,7 +3,7 @@
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2003-01-22'
|
||||
timestamp='2003-08-18'
|
||||
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
@@ -118,7 +118,7 @@ esac
|
||||
# Here we must recognize all the valid KERNEL-OS combinations.
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
nto-qnx* | linux-gnu* | linux-dietlibc | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
@@ -228,13 +228,14 @@ case $basic_machine in
|
||||
| a29k \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| am33_2.0 \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||
| clipper \
|
||||
| c4x | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k \
|
||||
| ip2k | iq2000 \
|
||||
| m32r | m68000 | m68k | m88k | mcore \
|
||||
| mips | mipsbe | mipseb | mipsel | mipsle \
|
||||
| mips16 \
|
||||
@@ -247,6 +248,7 @@ case $basic_machine in
|
||||
| mipsisa32 | mipsisa32el \
|
||||
| mipsisa32r2 | mipsisa32r2el \
|
||||
| mipsisa64 | mipsisa64el \
|
||||
| mipsisa64r2 | mipsisa64r2el \
|
||||
| mipsisa64sb1 | mipsisa64sb1el \
|
||||
| mipsisa64sr71k | mipsisa64sr71kel \
|
||||
| mipstx39 | mipstx39el \
|
||||
@@ -257,11 +259,11 @@ case $basic_machine in
|
||||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
|
||||
| pyramid \
|
||||
| sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh64 | sh64le \
|
||||
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
|
||||
| strongarm \
|
||||
| tahoe | thumb | tic80 | tron \
|
||||
| tahoe | thumb | tic4x | tic80 | tron \
|
||||
| v850 | v850e \
|
||||
| we32k \
|
||||
| x86 | xscale | xstormy16 | xtensa \
|
||||
@@ -296,7 +298,7 @@ case $basic_machine in
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* \
|
||||
| bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
|
||||
| clipper-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
@@ -304,7 +306,7 @@ case $basic_machine in
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* \
|
||||
| ip2k-* | iq2000-* \
|
||||
| m32r-* \
|
||||
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||
| m88110-* | m88k-* | mcore-* \
|
||||
@@ -319,6 +321,7 @@ case $basic_machine in
|
||||
| mipsisa32-* | mipsisa32el-* \
|
||||
| mipsisa32r2-* | mipsisa32r2el-* \
|
||||
| mipsisa64-* | mipsisa64el-* \
|
||||
| mipsisa64r2-* | mipsisa64r2el-* \
|
||||
| mipsisa64sb1-* | mipsisa64sb1el-* \
|
||||
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
|
||||
| mipstx39-* | mipstx39el-* \
|
||||
@@ -329,11 +332,13 @@ case $basic_machine in
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
|
||||
| pyramid-* \
|
||||
| romp-* | rs6000-* \
|
||||
| sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
|
||||
| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
|
||||
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
|
||||
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
|
||||
| tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \
|
||||
| tahoe-* | thumb-* \
|
||||
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||
| tron-* \
|
||||
| v850-* | v850e-* | vax-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
|
||||
@@ -371,6 +376,9 @@ case $basic_machine in
|
||||
basic_machine=a29k-none
|
||||
os=-bsd
|
||||
;;
|
||||
amd64)
|
||||
basic_machine=x86_64-pc
|
||||
;;
|
||||
amdahl)
|
||||
basic_machine=580-amdahl
|
||||
os=-sysv
|
||||
@@ -766,18 +774,24 @@ case $basic_machine in
|
||||
pentiumpro | p6 | 6x86 | athlon | athlon_*)
|
||||
basic_machine=i686-pc
|
||||
;;
|
||||
pentiumii | pentium2)
|
||||
pentiumii | pentium2 | pentiumiii | pentium3)
|
||||
basic_machine=i686-pc
|
||||
;;
|
||||
pentium4)
|
||||
basic_machine=i786-pc
|
||||
;;
|
||||
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
|
||||
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentiumpro-* | p6-* | 6x86-* | athlon-*)
|
||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentiumii-* | pentium2-*)
|
||||
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
|
||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentium4-*)
|
||||
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pn)
|
||||
basic_machine=pn-gould
|
||||
;;
|
||||
@@ -836,6 +850,10 @@ case $basic_machine in
|
||||
sb1el)
|
||||
basic_machine=mipsisa64sb1el-unknown
|
||||
;;
|
||||
sei)
|
||||
basic_machine=mips-sei
|
||||
os=-seiux
|
||||
;;
|
||||
sequent)
|
||||
basic_machine=i386-sequent
|
||||
;;
|
||||
@@ -843,6 +861,9 @@ case $basic_machine in
|
||||
basic_machine=sh-hitachi
|
||||
os=-hms
|
||||
;;
|
||||
sh64)
|
||||
basic_machine=sh64-unknown
|
||||
;;
|
||||
sparclite-wrs | simso-wrs)
|
||||
basic_machine=sparclite-wrs
|
||||
os=-vxworks
|
||||
@@ -917,14 +938,18 @@ case $basic_machine in
|
||||
basic_machine=t90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
tic4x | c4x*)
|
||||
basic_machine=tic4x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic54x | c54x*)
|
||||
basic_machine=tic54x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic55x | c55x*)
|
||||
basic_machine=tic55x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic6x | c6x*)
|
||||
basic_machine=tic6x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tx39)
|
||||
basic_machine=mipstx39-unknown
|
||||
;;
|
||||
@@ -1027,7 +1052,7 @@ case $basic_machine in
|
||||
we32k)
|
||||
basic_machine=we32k-att
|
||||
;;
|
||||
sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele)
|
||||
sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
basic_machine=sh-unknown
|
||||
;;
|
||||
sh64)
|
||||
@@ -1106,7 +1131,7 @@ case $os in
|
||||
| -aos* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
|
||||
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
|
||||
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
@@ -1118,7 +1143,7 @@ case $os in
|
||||
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -microbsd*)
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
@@ -1142,6 +1167,9 @@ case $os in
|
||||
-mac*)
|
||||
os=`echo $os | sed -e 's|mac|macos|'`
|
||||
;;
|
||||
-linux-dietlibc)
|
||||
os=-linux-dietlibc
|
||||
;;
|
||||
-linux*)
|
||||
os=`echo $os | sed -e 's|linux|linux-gnu|'`
|
||||
;;
|
||||
@@ -1230,6 +1258,9 @@ case $os in
|
||||
-aros*)
|
||||
os=-aros
|
||||
;;
|
||||
-kaos*)
|
||||
os=-kaos
|
||||
;;
|
||||
-none)
|
||||
;;
|
||||
*)
|
||||
@@ -1261,6 +1292,9 @@ case $basic_machine in
|
||||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
# This must come before the *-dec entry.
|
||||
pdp10-*)
|
||||
os=-tops20
|
||||
|
||||
134
configure.in
134
configure.in
@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.52)
|
||||
|
||||
RSYNC_VERSION=2.6.0pre1
|
||||
RSYNC_VERSION=2.6.3
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -18,6 +18,7 @@ AC_CANONICAL_TARGET([])
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_CC_STDC
|
||||
AC_SUBST(SHELL)
|
||||
@@ -96,6 +97,27 @@ AC_ARG_WITH(rsync-path,
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
|
||||
|
||||
AC_ARG_WITH(rsyncd-conf,
|
||||
AC_HELP_STRING([--with-rsyncd-conf=PATH], [set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
|
||||
[ if test ! -z "$with_rsyncd_conf" ; then
|
||||
case $with_rsyncd_conf in
|
||||
yes|no)
|
||||
RSYNCD_SYSCONF="/etc/rsyncd.conf"
|
||||
;;
|
||||
/*)
|
||||
RSYNCD_SYSCONF="$with_rsyncd_conf"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(You must specify an absolute path to --with-rsyncd-conf=PATH)
|
||||
;;
|
||||
esac
|
||||
else
|
||||
RSYNCD_SYSCONF="/etc/rsyncd.conf"
|
||||
fi ],
|
||||
[ RSYNCD_SYSCONF="/etc/rsyncd.conf" ])
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
|
||||
|
||||
AC_ARG_WITH(rsh,
|
||||
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
|
||||
|
||||
@@ -121,24 +143,29 @@ AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(void)
|
||||
int main(void)
|
||||
{
|
||||
struct flock lock;
|
||||
int status;
|
||||
int fd = open("conftest.dat", O_CREAT|O_RDWR, 0600);
|
||||
int status;
|
||||
char tpl[32] = "/tmp/locktest.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
if (fd < 0) {
|
||||
strcpy(tpl, "conftest.dat");
|
||||
fd = open(tpl, O_CREAT|O_RDWR, 0600);
|
||||
}
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
lock.l_pid = 0;
|
||||
|
||||
fcntl(fd,F_SETLK,&lock);
|
||||
if (fork() == 0) {
|
||||
lock.l_start = 1;
|
||||
exit(fcntl(fd,F_SETLK,&lock) == 0);
|
||||
}
|
||||
wait(&status);
|
||||
unlink("conftest.dat");
|
||||
lock.l_start = 1;
|
||||
_exit(fcntl(fd,F_SETLK,&lock) == 0);
|
||||
}
|
||||
wait(&status);
|
||||
unlink(tpl);
|
||||
exit(WEXITSTATUS(status));
|
||||
}
|
||||
],
|
||||
@@ -151,7 +178,7 @@ ipv6type=unknown
|
||||
ipv6lib=none
|
||||
ipv6trylibc=yes
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--disable-ipv6], [don't even try to use IPv6]))
|
||||
|
||||
if test "x$enable_ipv6" != xno
|
||||
@@ -177,7 +204,7 @@ yes
|
||||
#ifdef __KAME__
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
[ipv6type=$i;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
linux-glibc)
|
||||
@@ -247,7 +274,7 @@ fi
|
||||
AC_MSG_CHECKING([whether to call shutdown on all sockets])
|
||||
case $host_os in
|
||||
*cygwin* ) AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
|
||||
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
|
||||
[Define if sockets need to be shutdown])
|
||||
;;
|
||||
* ) AC_MSG_RESULT(no);;
|
||||
@@ -257,13 +284,12 @@ AC_C_BIGENDIAN
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_TIME
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h unistd.h utime.h grp.h)
|
||||
AC_CHECK_HEADERS(compat.h sys/param.h ctype.h sys/wait.h sys/ioctl.h)
|
||||
AC_CHECK_HEADERS(sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h sys/un.h)
|
||||
AC_CHECK_HEADERS(glob.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h)
|
||||
AC_CHECK_HEADERS(netdb.h)
|
||||
AC_CHECK_HEADERS(malloc.h)
|
||||
AC_CHECK_HEADERS(float.h)
|
||||
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
|
||||
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
|
||||
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
|
||||
sys/un.h glob.h mcheck.h arpa/inet.h arpa/nameser.h \
|
||||
netdb.h malloc.h float.h)
|
||||
AC_HEADER_MAJOR
|
||||
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
@@ -318,7 +344,7 @@ if test x"$ac_cv_func_connect" = x"no"; then
|
||||
esac
|
||||
dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
|
||||
dnl has been cached.
|
||||
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
|
||||
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
|
||||
test x"$ac_cv_lib_inet_connect" = x"yes"; then
|
||||
# ac_cv_func_connect=yes
|
||||
# don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
|
||||
@@ -330,8 +356,8 @@ AC_CHECK_LIB(resolv, inet_ntop)
|
||||
|
||||
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
|
||||
|
||||
AC_CHECK_FUNCS(inet_ntop, , AC_LIBOBJ(lib/inet_ntop))
|
||||
AC_CHECK_FUNCS(inet_pton, , AC_LIBOBJ(lib/inet_pton))
|
||||
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
|
||||
AC_CHECK_FUNCS(inet_pton, , [AC_LIBOBJ(lib/inet_pton)])
|
||||
|
||||
# Irix 6.5 has getaddrinfo but not the corresponding defines, so use
|
||||
# builtin getaddrinfo if one of the defines don't exist
|
||||
@@ -343,7 +369,7 @@ AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
|
||||
#include <netdb.h>
|
||||
#ifdef AI_PASSIVE
|
||||
yes
|
||||
#endif],
|
||||
#endif],
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=yes,
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=no)])
|
||||
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
|
||||
@@ -360,32 +386,40 @@ if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
|
||||
[Define if you have the `getaddrinfo' function.])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ(lib/getaddrinfo)])])
|
||||
AC_CHECK_FUNCS(getnameinfo, , AC_LIBOBJ(lib/getnameinfo))
|
||||
AC_CHECK_FUNCS(getnameinfo, , [AC_LIBOBJ(lib/getnameinfo)])
|
||||
else
|
||||
AC_LIBOBJ(lib/getaddrinfo)
|
||||
AC_LIBOBJ(lib/getnameinfo)
|
||||
fi
|
||||
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr.sa_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_LEN) ],
|
||||
AC_CHECK_MEMBER([struct sockaddr.sa_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in.sin_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_IN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING(struct sockaddr_storage)
|
||||
AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <sys/socket.h>],
|
||||
[struct sockaddr_storage x;],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
|
||||
AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1,
|
||||
[Define if you have strct sockaddr_storage.] ),
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID) ],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID, 1, [Do we have sockaddr_in6.sin6_scope_id?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
@@ -402,15 +436,16 @@ fi
|
||||
|
||||
dnl At the moment we don't test for a broken memcmp(), because all we
|
||||
dnl need to do is test for equality, not comparison, and it seems that
|
||||
dnl every platform has a memcmp that can do at least that.
|
||||
dnl every platform has a memcmp that can do at least that.
|
||||
dnl AC_FUNC_MEMCMP
|
||||
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo)
|
||||
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
|
||||
AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk)
|
||||
AC_CHECK_FUNCS(strlcat strlcpy strtol mtrace mallinfo setgroups)
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \
|
||||
fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \
|
||||
memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
open64 mkstemp64)
|
||||
|
||||
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
|
||||
AC_TRY_RUN([
|
||||
@@ -508,7 +543,7 @@ AC_TRY_RUN([
|
||||
#include <unistd.h>
|
||||
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
|
||||
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no,rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ])
|
||||
fi
|
||||
|
||||
@@ -516,7 +551,7 @@ AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
void foo(const char *format, ...) {
|
||||
void foo(const char *format, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char buf[5];
|
||||
@@ -543,10 +578,10 @@ AC_TRY_RUN([#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
main() {
|
||||
main() {
|
||||
struct stat st;
|
||||
char tpl[20]="/tmp/test.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
char tpl[20]="/tmp/test.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
if (fd == -1) exit(1);
|
||||
unlink(tpl);
|
||||
if (fstat(fd, &st) != 0) exit(1);
|
||||
@@ -569,7 +604,7 @@ AC_TRY_RUN([
|
||||
#include <arpa/inet.h>
|
||||
main() { struct in_addr ip; ip.s_addr = 0x12345678;
|
||||
if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
|
||||
strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(1); }
|
||||
strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(1); }
|
||||
exit(0);}],
|
||||
rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=cross)])
|
||||
if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then
|
||||
@@ -583,7 +618,7 @@ AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
main() { struct in_addr ip;
|
||||
main() { struct in_addr ip;
|
||||
if (inet_aton("example", &ip) == 0) exit(0); exit(1);}],
|
||||
rsync_cv_REPLACE_INET_ATON=no,rsync_cv_REPLACE_INET_ATON=yes,rsync_cv_REPLACE_INET_ATON=cross)])
|
||||
if test x"$rsync_cv_REPLACE_INET_ATON" = x"yes"; then
|
||||
@@ -624,6 +659,21 @@ AC_SUBST(BUILD_POPT)
|
||||
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
|
||||
AC_OUTPUT
|
||||
|
||||
if test x"$with_rsh" = x; then
|
||||
if test x"$HAVE_REMSH" = x1; then
|
||||
rmsh1='remsh:'
|
||||
rmsh2='=remsh'
|
||||
else
|
||||
rmsh1='rsh: '
|
||||
rmsh2='=rsh '
|
||||
fi
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT([ **********************************************************************])
|
||||
AC_MSG_RESULT([ * As of v2.6.0, the default remote shell is ssh instead of rsh!! *])
|
||||
AC_MSG_RESULT([ * To use previous default of $rmsh1 ./configure --with-rsh$rmsh2 *])
|
||||
AC_MSG_RESULT([ **********************************************************************])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
|
||||
AC_MSG_RESULT()
|
||||
|
||||
452
exclude.c
452
exclude.c
@@ -27,100 +27,101 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int eol_nulls;
|
||||
extern int list_only;
|
||||
extern int recurse;
|
||||
|
||||
struct exclude_struct **exclude_list;
|
||||
struct exclude_struct **local_exclude_list;
|
||||
struct exclude_struct **server_exclude_list;
|
||||
extern char curr_dir[];
|
||||
|
||||
struct exclude_list_struct exclude_list = { 0, 0, "" };
|
||||
struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " };
|
||||
struct exclude_list_struct server_exclude_list = { 0, 0, "server " };
|
||||
char *exclude_path_prefix = NULL;
|
||||
|
||||
/** Build an exclude structure given a exclude pattern */
|
||||
static struct exclude_struct *make_exclude(const char *pattern, int include)
|
||||
/** Build an exclude structure given an exclude pattern. */
|
||||
static void make_exclude(struct exclude_list_struct *listp, const char *pat,
|
||||
unsigned int pat_len, unsigned int mflags)
|
||||
{
|
||||
struct exclude_struct *ret;
|
||||
char *cp;
|
||||
int pat_len;
|
||||
const char *cp;
|
||||
unsigned int ex_len;
|
||||
|
||||
ret = new(struct exclude_struct);
|
||||
if (!ret) out_of_memory("make_exclude");
|
||||
if (!ret)
|
||||
out_of_memory("make_exclude");
|
||||
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
|
||||
if (strncmp(pattern,"- ",2) == 0) {
|
||||
pattern += 2;
|
||||
} else if (strncmp(pattern,"+ ",2) == 0) {
|
||||
ret->include = 1;
|
||||
pattern += 2;
|
||||
} else {
|
||||
ret->include = include;
|
||||
}
|
||||
memset(ret, 0, sizeof ret[0]);
|
||||
|
||||
if (exclude_path_prefix)
|
||||
ret->match_flags |= MATCHFLG_ABS_PATH;
|
||||
if (exclude_path_prefix && *pattern == '/') {
|
||||
ret->pattern = new_array(char,
|
||||
strlen(exclude_path_prefix) + strlen(pattern) + 1);
|
||||
if (!ret->pattern) out_of_memory("make_exclude");
|
||||
sprintf(ret->pattern, "%s%s", exclude_path_prefix, pattern);
|
||||
}
|
||||
else {
|
||||
ret->pattern = strdup(pattern);
|
||||
if (!ret->pattern) out_of_memory("make_exclude");
|
||||
}
|
||||
mflags |= MATCHFLG_ABS_PATH;
|
||||
if (exclude_path_prefix && *pat == '/')
|
||||
ex_len = strlen(exclude_path_prefix);
|
||||
else
|
||||
ex_len = 0;
|
||||
ret->pattern = new_array(char, ex_len + pat_len + 1);
|
||||
if (!ret->pattern)
|
||||
out_of_memory("make_exclude");
|
||||
if (ex_len)
|
||||
memcpy(ret->pattern, exclude_path_prefix, ex_len);
|
||||
strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
|
||||
pat_len += ex_len;
|
||||
|
||||
if (strpbrk(pattern, "*[?")) {
|
||||
ret->match_flags |= MATCHFLG_WILD;
|
||||
if (strstr(pattern, "**")) {
|
||||
ret->match_flags |= MATCHFLG_WILD2;
|
||||
if (strpbrk(ret->pattern, "*[?")) {
|
||||
mflags |= MATCHFLG_WILD;
|
||||
if ((cp = strstr(ret->pattern, "**")) != NULL) {
|
||||
mflags |= MATCHFLG_WILD2;
|
||||
/* If the pattern starts with **, note that. */
|
||||
if (*pattern == '*' && pattern[1] == '*')
|
||||
ret->match_flags |= MATCHFLG_WILD2_PREFIX;
|
||||
if (cp == ret->pattern)
|
||||
mflags |= MATCHFLG_WILD2_PREFIX;
|
||||
}
|
||||
}
|
||||
|
||||
pat_len = strlen(ret->pattern);
|
||||
if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
|
||||
ret->pattern[pat_len-1] = 0;
|
||||
ret->directory = 1;
|
||||
mflags |= MATCHFLG_DIRECTORY;
|
||||
}
|
||||
|
||||
for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
|
||||
ret->slash_cnt++;
|
||||
|
||||
return ret;
|
||||
ret->match_flags = mflags;
|
||||
|
||||
if (!listp->tail)
|
||||
listp->head = listp->tail = ret;
|
||||
else {
|
||||
listp->tail->next = ret;
|
||||
listp->tail = ret;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_exclude(struct exclude_struct *ex)
|
||||
{
|
||||
free(ex->pattern);
|
||||
memset(ex,0,sizeof(*ex));
|
||||
free(ex);
|
||||
}
|
||||
|
||||
|
||||
void free_exclude_list(struct exclude_struct ***listp)
|
||||
void clear_exclude_list(struct exclude_list_struct *listp)
|
||||
{
|
||||
struct exclude_struct **list = *listp;
|
||||
struct exclude_struct *ent, *next;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"clearing exclude list\n");
|
||||
for (ent = listp->head; ent; ent = next) {
|
||||
next = ent->next;
|
||||
free_exclude(ent);
|
||||
}
|
||||
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
while (*list)
|
||||
free_exclude(*list++);
|
||||
|
||||
free(*listp);
|
||||
*listp = NULL;
|
||||
listp->head = listp->tail = NULL;
|
||||
}
|
||||
|
||||
static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
int name_is_dir)
|
||||
{
|
||||
char *p;
|
||||
char *p, full_name[MAXPATHLEN];
|
||||
int match_start = 0;
|
||||
char *pattern = ex->pattern;
|
||||
|
||||
if (!*name)
|
||||
return 0;
|
||||
|
||||
/* If the pattern does not have any slashes AND it does not have
|
||||
* a "**" (which could match a slash), then we just match the
|
||||
* name portion of the path. */
|
||||
@@ -128,18 +129,14 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
if ((p = strrchr(name,'/')) != NULL)
|
||||
name = p+1;
|
||||
}
|
||||
else if ((ex->match_flags & MATCHFLG_ABS_PATH) && *name != '/') {
|
||||
static char full_name[MAXPATHLEN];
|
||||
extern char curr_dir[];
|
||||
int plus = curr_dir[1] == '\0'? 1 : 0;
|
||||
snprintf(full_name, sizeof full_name,
|
||||
"%s/%s", curr_dir+plus, name);
|
||||
else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
|
||||
&& curr_dir[1]) {
|
||||
pathjoin(full_name, sizeof full_name, curr_dir + 1, name);
|
||||
name = full_name;
|
||||
}
|
||||
|
||||
if (!name[0]) return 0;
|
||||
|
||||
if (ex->directory && !name_is_dir) return 0;
|
||||
if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir)
|
||||
return 0;
|
||||
|
||||
if (*pattern == '/') {
|
||||
match_start = 1;
|
||||
@@ -151,8 +148,8 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
if (ex->match_flags & MATCHFLG_WILD) {
|
||||
/* A non-anchored match with an infix slash and no "**"
|
||||
* needs to match the last slash_cnt+1 name elements. */
|
||||
if (!match_start && ex->slash_cnt &&
|
||||
!(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
if (!match_start && ex->slash_cnt
|
||||
&& !(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
int cnt = ex->slash_cnt + 1;
|
||||
for (p = name + strlen(name) - 1; p >= name; p--) {
|
||||
if (*p == '/' && !--cnt)
|
||||
@@ -198,33 +195,36 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
|
||||
static void report_exclude_result(char const *name,
|
||||
struct exclude_struct const *ent,
|
||||
int name_is_dir)
|
||||
int name_is_dir, const char *type)
|
||||
{
|
||||
/* If a trailing slash is present to match only directories,
|
||||
* then it is stripped out by make_exclude. So as a special
|
||||
* case we add it back in here. */
|
||||
|
||||
if (verbose >= 2)
|
||||
rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
|
||||
ent->include ? "including" : "excluding",
|
||||
name_is_dir ? "directory" : "file",
|
||||
name, ent->pattern,
|
||||
ent->directory ? "/" : "");
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n",
|
||||
who_am_i(),
|
||||
ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex",
|
||||
name_is_dir ? "directory" : "file", name, type,
|
||||
ent->pattern,
|
||||
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return true if file NAME is defined to be excluded by either
|
||||
* LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
|
||||
* Return -1 if file "name" is defined to be excluded by the specified
|
||||
* exclude list, 1 if it is included, and 0 if it was not matched.
|
||||
*/
|
||||
int check_exclude(struct exclude_struct **list, char *name, int name_is_dir)
|
||||
int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir)
|
||||
{
|
||||
struct exclude_struct *ent;
|
||||
|
||||
while ((ent = *list++) != NULL) {
|
||||
for (ent = listp->head; ent; ent = ent->next) {
|
||||
if (check_one_exclude(name, ent, name_is_dir)) {
|
||||
report_exclude_result(name, ent, name_is_dir);
|
||||
return !ent->include;
|
||||
report_exclude_result(name, ent, name_is_dir,
|
||||
listp->debug_type);
|
||||
return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,53 +232,113 @@ int check_exclude(struct exclude_struct **list, char *name, int name_is_dir)
|
||||
}
|
||||
|
||||
|
||||
void add_exclude(struct exclude_struct ***listp, const char *pattern, int include)
|
||||
/* Get the next include/exclude arg from the string. The token will not
|
||||
* be '\0' terminated, so use the returned length to limit the string.
|
||||
* Also, be sure to add this length to the returned pointer before passing
|
||||
* it back to ask for the next token. This routine parses the +/- prefixes
|
||||
* and the "!" token unless xflags contains XFLG_WORDS_ONLY. The *flag_ptr
|
||||
* value will also be set to the MATCHFLG_* bits for the current token.
|
||||
*/
|
||||
static const char *get_exclude_tok(const char *p, unsigned int *len_ptr,
|
||||
unsigned int *flag_ptr, int xflags)
|
||||
{
|
||||
struct exclude_struct **list = *listp;
|
||||
int len = 0;
|
||||
const unsigned char *s = (const unsigned char *)p;
|
||||
unsigned int len, mflags = 0;
|
||||
|
||||
if (*pattern == '!' && !pattern[1]) {
|
||||
free_exclude_list(listp);
|
||||
return;
|
||||
if (xflags & XFLG_WORD_SPLIT) {
|
||||
/* Skip over any initial whitespace. */
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
/* Update for "!" check. */
|
||||
p = (const char *)s;
|
||||
}
|
||||
|
||||
if (list)
|
||||
for (; list[len]; len++) {}
|
||||
/* Is this a '+' or '-' followed by a space (not whitespace)? */
|
||||
if (!(xflags & XFLG_WORDS_ONLY)
|
||||
&& (*s == '-' || *s == '+') && s[1] == ' ') {
|
||||
if (*s == '+')
|
||||
mflags |= MATCHFLG_INCLUDE;
|
||||
s += 2;
|
||||
} else if (xflags & XFLG_DEF_INCLUDE)
|
||||
mflags |= MATCHFLG_INCLUDE;
|
||||
if (xflags & XFLG_DIRECTORY)
|
||||
mflags |= MATCHFLG_DIRECTORY;
|
||||
|
||||
list = *listp = realloc_array(list, struct exclude_struct *, len+2);
|
||||
if (xflags & XFLG_WORD_SPLIT) {
|
||||
const unsigned char *cp = s;
|
||||
/* Token ends at whitespace or the end of the string. */
|
||||
while (!isspace(*cp) && *cp != '\0')
|
||||
cp++;
|
||||
len = cp - s;
|
||||
} else
|
||||
len = strlen(s);
|
||||
|
||||
if (!list || !(list[len] = make_exclude(pattern, include)))
|
||||
out_of_memory("add_exclude");
|
||||
if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY))
|
||||
mflags |= MATCHFLG_CLEAR_LIST;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"add_exclude(%s,%s)\n",pattern,
|
||||
include ? "include" : "exclude");
|
||||
}
|
||||
|
||||
list[len+1] = NULL;
|
||||
*len_ptr = len;
|
||||
*flag_ptr = mflags;
|
||||
return (const char *)s;
|
||||
}
|
||||
|
||||
|
||||
void add_exclude_file(struct exclude_struct ***listp, const char *fname,
|
||||
int fatal, int include)
|
||||
void add_exclude(struct exclude_list_struct *listp, const char *pattern,
|
||||
int xflags)
|
||||
{
|
||||
int fd;
|
||||
char line[MAXPATHLEN];
|
||||
char *eob = line + MAXPATHLEN - 1;
|
||||
extern int eol_nulls;
|
||||
unsigned int pat_len, mflags;
|
||||
const char *cp;
|
||||
|
||||
if (!pattern)
|
||||
return;
|
||||
|
||||
cp = pattern;
|
||||
pat_len = 0;
|
||||
while (1) {
|
||||
cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags);
|
||||
if (!pat_len)
|
||||
break;
|
||||
|
||||
if (mflags & MATCHFLG_CLEAR_LIST) {
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,
|
||||
"[%s] clearing %sexclude list\n",
|
||||
who_am_i(), listp->debug_type);
|
||||
}
|
||||
clear_exclude_list(listp);
|
||||
continue;
|
||||
}
|
||||
|
||||
make_exclude(listp, cp, pat_len, mflags);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] add_exclude(%.*s, %s%sclude)\n",
|
||||
who_am_i(), (int)pat_len, cp, listp->debug_type,
|
||||
mflags & MATCHFLG_INCLUDE ? "in" : "ex");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
|
||||
int xflags)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
|
||||
char *eob = line + sizeof line - 1;
|
||||
int word_split = xflags & XFLG_WORD_SPLIT;
|
||||
|
||||
if (!fname || !*fname)
|
||||
return;
|
||||
|
||||
if (*fname != '-' || fname[1])
|
||||
fd = open(fname, O_RDONLY|O_BINARY);
|
||||
fp = fopen(fname, "rb");
|
||||
else
|
||||
fd = 0;
|
||||
if (fd < 0) {
|
||||
if (fatal) {
|
||||
fp = stdin;
|
||||
if (!fp) {
|
||||
if (xflags & XFLG_FATAL_ERRORS) {
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to open %s file %s",
|
||||
include ? "include" : "exclude",
|
||||
xflags & XFLG_DEF_INCLUDE ? "include" : "exclude",
|
||||
fname);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
@@ -286,172 +346,114 @@ void add_exclude_file(struct exclude_struct ***listp, const char *fname,
|
||||
}
|
||||
|
||||
while (1) {
|
||||
char ch, *s = line;
|
||||
int cnt;
|
||||
char *s = line;
|
||||
int ch, overflow = 0;
|
||||
while (1) {
|
||||
if ((cnt = read(fd, &ch, 1)) <= 0) {
|
||||
if (cnt < 0 && errno == EINTR)
|
||||
if ((ch = getc(fp)) == EOF) {
|
||||
if (ferror(fp) && errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (word_split && isspace(ch))
|
||||
break;
|
||||
if (eol_nulls? !ch : (ch == '\n' || ch == '\r'))
|
||||
break;
|
||||
if (s < eob)
|
||||
*s++ = ch;
|
||||
else
|
||||
overflow = 1;
|
||||
}
|
||||
if (overflow) {
|
||||
rprintf(FERROR, "discarding over-long exclude: %s...\n", line);
|
||||
s = line;
|
||||
}
|
||||
*s = '\0';
|
||||
if (*line && *line != ';' && *line != '#') {
|
||||
/* Skip lines starting with semicolon or pound.
|
||||
* It probably wouldn't cause any harm to not skip
|
||||
* them but there's no need to save them. */
|
||||
add_exclude(listp, line, include);
|
||||
}
|
||||
if (cnt <= 0)
|
||||
/* Skip an empty token and (when line parsing) comments. */
|
||||
if (*line && (word_split || (*line != ';' && *line != '#')))
|
||||
add_exclude(listp, line, xflags);
|
||||
if (ch == EOF)
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
void send_exclude_list(int f)
|
||||
{
|
||||
int i;
|
||||
extern int protocol_version;
|
||||
extern int list_only, recurse;
|
||||
struct exclude_struct *ent;
|
||||
|
||||
/* This is a complete hack - blame Rusty.
|
||||
*
|
||||
* FIXME: This pattern shows up in the output of
|
||||
* report_exclude_result(), which is not ideal. */
|
||||
if (list_only && !recurse)
|
||||
add_exclude(&exclude_list, "/*/*", ADD_EXCLUDE);
|
||||
add_exclude(&exclude_list, "/*/*", 0);
|
||||
|
||||
if (!exclude_list) {
|
||||
write_int(f,0);
|
||||
return;
|
||||
}
|
||||
for (ent = exclude_list.head; ent; ent = ent->next) {
|
||||
unsigned int l;
|
||||
char p[MAXPATHLEN+1];
|
||||
|
||||
for (i=0;exclude_list[i];i++) {
|
||||
int l;
|
||||
char pattern[MAXPATHLEN];
|
||||
|
||||
strlcpy(pattern,exclude_list[i]->pattern,sizeof(pattern));
|
||||
if (exclude_list[i]->directory) strlcat(pattern,"/", sizeof(pattern));
|
||||
|
||||
l = strlen(pattern);
|
||||
if (l == 0) continue;
|
||||
if (exclude_list[i]->include) {
|
||||
if (protocol_version < 19) {
|
||||
rprintf(FERROR,"remote rsync does not support include syntax - aborting\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
write_int(f,l+2);
|
||||
write_buf(f,"+ ",2);
|
||||
} else {
|
||||
write_int(f,l);
|
||||
l = strlcpy(p, ent->pattern, sizeof p);
|
||||
if (l == 0 || l >= MAXPATHLEN)
|
||||
continue;
|
||||
if (ent->match_flags & MATCHFLG_DIRECTORY) {
|
||||
p[l++] = '/';
|
||||
p[l] = '\0';
|
||||
}
|
||||
write_buf(f,pattern,l);
|
||||
|
||||
if (ent->match_flags & MATCHFLG_INCLUDE) {
|
||||
write_int(f, l + 2);
|
||||
write_buf(f, "+ ", 2);
|
||||
} else if ((*p == '-' || *p == '+') && p[1] == ' ') {
|
||||
write_int(f, l + 2);
|
||||
write_buf(f, "- ", 2);
|
||||
} else
|
||||
write_int(f, l);
|
||||
write_buf(f, p, l);
|
||||
}
|
||||
|
||||
write_int(f,0);
|
||||
write_int(f, 0);
|
||||
}
|
||||
|
||||
|
||||
void recv_exclude_list(int f)
|
||||
{
|
||||
char line[MAXPATHLEN];
|
||||
char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
|
||||
unsigned int l;
|
||||
|
||||
while ((l=read_int(f))) {
|
||||
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
|
||||
read_sbuf(f,line,l);
|
||||
add_exclude(&exclude_list, line, ADD_EXCLUDE);
|
||||
while ((l = read_int(f)) != 0) {
|
||||
if (l >= sizeof line)
|
||||
overflow("recv_exclude_list");
|
||||
read_sbuf(f, line, l);
|
||||
add_exclude(&exclude_list, line, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the next include/exclude arg from the string. It works in a similar way
|
||||
** to strtok - initially an arg is sent over, from then on NULL. This
|
||||
** routine takes into account any +/- in the strings and does not
|
||||
** consider the space following it as a delimeter.
|
||||
*/
|
||||
char *get_exclude_tok(char *p)
|
||||
{
|
||||
static char *s;
|
||||
static int more;
|
||||
char *t;
|
||||
|
||||
if (p) {
|
||||
s=p;
|
||||
if (*p)
|
||||
more=1;
|
||||
}
|
||||
|
||||
if (!more)
|
||||
return(NULL);
|
||||
|
||||
/* Skip over any initial spaces */
|
||||
while (isspace(* (unsigned char *) s))
|
||||
s++;
|
||||
|
||||
/* Are we at the end of the string? */
|
||||
if (*s) {
|
||||
/* remember the beginning of the token */
|
||||
t=s;
|
||||
|
||||
/* Is this a '+' or '-' followed by a space (not whitespace)? */
|
||||
if ((*s=='+' || *s=='-') && *(s+1)==' ')
|
||||
s+=2;
|
||||
|
||||
/* Skip to the next space or the end of the string */
|
||||
while (!isspace(* (unsigned char *) s) && *s != '\0')
|
||||
s++;
|
||||
} else {
|
||||
t=NULL;
|
||||
}
|
||||
|
||||
/* Have we reached the end of the string? */
|
||||
if (*s)
|
||||
*s++='\0';
|
||||
else
|
||||
more=0;
|
||||
return(t);
|
||||
}
|
||||
|
||||
|
||||
void add_exclude_line(struct exclude_struct ***listp,
|
||||
const char *line, int include)
|
||||
{
|
||||
char *tok, *p;
|
||||
if (!line || !*line) return;
|
||||
p = strdup(line);
|
||||
if (!p) out_of_memory("add_exclude_line");
|
||||
for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
|
||||
add_exclude(listp, tok, include);
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
||||
static char *cvs_ignore_list[] = {
|
||||
"RCS/", "SCCS/", "CVS/", ".svn/", "CVS.adm", "RCSLOG", "cvslog.*",
|
||||
"tags", "TAGS", ".make.state", ".nse_depinfo",
|
||||
"*~", "#*", ".#*", ", *", "*.old", "*.bak", "*.BAK", "*.orig",
|
||||
"*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
|
||||
"core", NULL};
|
||||
|
||||
static char default_cvsignore[] =
|
||||
/* These default ignored items come from the CVS manual. */
|
||||
"RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS"
|
||||
" .make.state .nse_depinfo *~ #* .#* ,* _$* *$"
|
||||
" *.old *.bak *.BAK *.orig *.rej .del-*"
|
||||
" *.a *.olb *.o *.obj *.so *.exe"
|
||||
" *.Z *.elc *.ln core"
|
||||
/* The rest we added to suit ourself. */
|
||||
" .svn/";
|
||||
|
||||
void add_cvs_excludes(void)
|
||||
{
|
||||
char fname[MAXPATHLEN];
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
for (i=0; cvs_ignore_list[i]; i++)
|
||||
add_exclude(&exclude_list, cvs_ignore_list[i], ADD_EXCLUDE);
|
||||
add_exclude(&exclude_list, default_cvsignore,
|
||||
XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
|
||||
|
||||
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
|
||||
snprintf(fname,sizeof(fname), "%s/.cvsignore",p);
|
||||
add_exclude_file(&exclude_list,fname,MISSING_OK,ADD_EXCLUDE);
|
||||
if ((p = getenv("HOME"))
|
||||
&& pathjoin(fname, sizeof fname, p, ".cvsignore") < sizeof fname) {
|
||||
add_exclude_file(&exclude_list, fname,
|
||||
XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
|
||||
}
|
||||
|
||||
add_exclude_line(&exclude_list, getenv("CVSIGNORE"), ADD_EXCLUDE);
|
||||
add_exclude(&exclude_list, getenv("CVSIGNORE"),
|
||||
XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
|
||||
}
|
||||
|
||||
126
fileio.c
126
fileio.c
@@ -1,30 +1,31 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
File IO utilities used in rsync
|
||||
File IO utilities used in rsync
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
extern int sparse_files;
|
||||
|
||||
static char last_byte;
|
||||
static int last_sparse;
|
||||
extern int sparse_files;
|
||||
|
||||
int sparse_end(int f)
|
||||
{
|
||||
@@ -42,8 +43,8 @@ static int write_sparse(int f,char *buf,size_t len)
|
||||
size_t l1=0, l2=0;
|
||||
int ret;
|
||||
|
||||
for (l1=0;l1<len && buf[l1]==0;l1++) ;
|
||||
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
|
||||
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
|
||||
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
|
||||
|
||||
last_byte = buf[len-1];
|
||||
|
||||
@@ -51,24 +52,47 @@ static int write_sparse(int f,char *buf,size_t len)
|
||||
last_sparse=1;
|
||||
|
||||
if (l1 > 0) {
|
||||
do_lseek(f,l1,SEEK_CUR);
|
||||
do_lseek(f,l1,SEEK_CUR);
|
||||
}
|
||||
|
||||
if (l1 == len)
|
||||
if (l1 == len)
|
||||
return len;
|
||||
|
||||
ret = write(f, buf + l1, len - (l1+l2));
|
||||
if (ret == -1 || ret == 0)
|
||||
return ret;
|
||||
else if (ret != (int) (len - (l1+l2)))
|
||||
else if (ret != (int) (len - (l1+l2)))
|
||||
return (l1+ret);
|
||||
|
||||
if (l2 > 0)
|
||||
do_lseek(f,l2,SEEK_CUR);
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static char *wf_writeBuf;
|
||||
static size_t wf_writeBufSize;
|
||||
static size_t wf_writeBufCnt;
|
||||
|
||||
int flush_write_file(int f)
|
||||
{
|
||||
int ret = 0;
|
||||
char *bp = wf_writeBuf;
|
||||
|
||||
while (wf_writeBufCnt > 0) {
|
||||
if ((ret = write(f, bp, wf_writeBufCnt)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return ret;
|
||||
}
|
||||
wf_writeBufCnt -= ret;
|
||||
bp += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write_file does not allow incomplete writes. It loops internally
|
||||
* until len bytes are written or errno is set.
|
||||
@@ -77,16 +101,34 @@ int write_file(int f,char *buf,size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (len>0) {
|
||||
while (len > 0) {
|
||||
int r1;
|
||||
if (sparse_files) {
|
||||
int len1 = MIN(len, SPARSE_WRITE_SIZE);
|
||||
r1 = write_sparse(f, buf, len1);
|
||||
} else {
|
||||
r1 = write(f, buf, len);
|
||||
if (!wf_writeBuf) {
|
||||
wf_writeBufSize = WRITE_SIZE * 8;
|
||||
wf_writeBufCnt = 0;
|
||||
wf_writeBuf = new_array(char, wf_writeBufSize);
|
||||
if (!wf_writeBuf)
|
||||
out_of_memory("write_file");
|
||||
}
|
||||
r1 = MIN(len, wf_writeBufSize - wf_writeBufCnt);
|
||||
if (r1) {
|
||||
memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
|
||||
wf_writeBufCnt += r1;
|
||||
}
|
||||
if (wf_writeBufCnt == wf_writeBufSize) {
|
||||
if (flush_write_file(f) < 0)
|
||||
return -1;
|
||||
if (!r1 && len)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (r1 <= 0) {
|
||||
if (ret > 0) return ret;
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
return r1;
|
||||
}
|
||||
len -= r1;
|
||||
@@ -97,29 +139,30 @@ int write_file(int f,char *buf,size_t len)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* this provides functionality somewhat similar to mmap() but using
|
||||
read(). It gives sliding window access to a file. mmap() is not
|
||||
used because of the possibility of another program (such as a
|
||||
mailer) truncating the file thus giving us a SIGBUS */
|
||||
struct map_struct *map_file(int fd,OFF_T len)
|
||||
/* This provides functionality somewhat similar to mmap() but using read().
|
||||
* It gives sliding window access to a file. mmap() is not used because of
|
||||
* the possibility of another program (such as a mailer) truncating the
|
||||
* file thus giving us a SIGBUS. */
|
||||
struct map_struct *map_file(int fd, OFF_T len, OFF_T map_size,
|
||||
size_t block_size)
|
||||
{
|
||||
struct map_struct *map;
|
||||
map = new(struct map_struct);
|
||||
if (!map) out_of_memory("map_file");
|
||||
|
||||
if (!(map = new(struct map_struct)))
|
||||
out_of_memory("map_file");
|
||||
|
||||
if (block_size && (map_size % block_size))
|
||||
map_size += block_size - (map_size % block_size);
|
||||
|
||||
memset(map, 0, sizeof map[0]);
|
||||
map->fd = fd;
|
||||
map->file_size = len;
|
||||
map->p = NULL;
|
||||
map->p_size = 0;
|
||||
map->p_offset = 0;
|
||||
map->p_fd_offset = 0;
|
||||
map->p_len = 0;
|
||||
map->status = 0;
|
||||
map->def_window_size = map_size;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/* slide the read window in the file */
|
||||
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
{
|
||||
@@ -127,9 +170,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
OFF_T window_start, read_start;
|
||||
int window_size, read_size, read_offset;
|
||||
|
||||
if (len == 0) {
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can't go beyond the end of file */
|
||||
if (len > (map->file_size - offset)) {
|
||||
@@ -137,20 +179,14 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
}
|
||||
|
||||
/* in most cases the region will already be available */
|
||||
if (offset >= map->p_offset &&
|
||||
if (offset >= map->p_offset &&
|
||||
offset+len <= map->p_offset+map->p_len) {
|
||||
return (map->p + (offset - map->p_offset));
|
||||
}
|
||||
|
||||
|
||||
/* nope, we are going to have to do a read. Work out our desired window */
|
||||
if (offset > 2*CHUNK_SIZE) {
|
||||
window_start = offset - 2*CHUNK_SIZE;
|
||||
window_start &= ~((OFF_T)(CHUNK_SIZE-1)); /* assumes power of 2 */
|
||||
} else {
|
||||
window_start = 0;
|
||||
}
|
||||
window_size = MAX_MAP_SIZE;
|
||||
window_start = offset;
|
||||
window_size = map->def_window_size;
|
||||
if (window_start + window_size > map->file_size) {
|
||||
window_size = map->file_size - window_start;
|
||||
}
|
||||
@@ -161,7 +197,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
/* make sure we have allocated enough memory for the window */
|
||||
if (window_size > map->p_size) {
|
||||
map->p = realloc_array(map->p, char, window_size);
|
||||
if (!map->p) out_of_memory("map_ptr");
|
||||
if (!map->p)
|
||||
out_of_memory("map_ptr");
|
||||
map->p_size = window_size;
|
||||
}
|
||||
|
||||
@@ -206,8 +243,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
|
||||
map->p_offset = window_start;
|
||||
map->p_len = window_size;
|
||||
|
||||
return map->p + (offset - map->p_offset);
|
||||
|
||||
return map->p + (offset - map->p_offset);
|
||||
}
|
||||
|
||||
|
||||
@@ -220,9 +257,8 @@ int unmap_file(struct map_struct *map)
|
||||
map->p = NULL;
|
||||
}
|
||||
ret = map->status;
|
||||
memset(map, 0, sizeof(*map));
|
||||
memset(map, 0, sizeof map[0]);
|
||||
free(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
490
generator.c
490
generator.c
@@ -26,43 +26,54 @@
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int relative_paths;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_links;
|
||||
extern int am_root;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int update_only;
|
||||
extern int opt_ignore_existing;
|
||||
extern int inplace;
|
||||
extern int make_backups;
|
||||
extern int csum_length;
|
||||
extern int ignore_times;
|
||||
extern int size_only;
|
||||
extern int io_timeout;
|
||||
extern int protocol_version;
|
||||
extern int always_checksum;
|
||||
extern int modify_window;
|
||||
extern char *partial_dir;
|
||||
extern char *compare_dest;
|
||||
extern int link_dest;
|
||||
extern int whole_file;
|
||||
extern int local_server;
|
||||
extern int list_only;
|
||||
extern int read_batch;
|
||||
extern int only_existing;
|
||||
extern int orig_umask;
|
||||
extern int safe_symlinks;
|
||||
extern unsigned int block_size;
|
||||
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
|
||||
|
||||
/* choose whether to skip a particular file */
|
||||
static int skip_file(char *fname,
|
||||
struct file_struct *file, STRUCT_STAT *st)
|
||||
static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
|
||||
{
|
||||
if (st->st_size != file->length) {
|
||||
if (st->st_size != file->length)
|
||||
return 0;
|
||||
}
|
||||
if (link_dest) {
|
||||
extern int preserve_perms;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
|
||||
if(preserve_perms
|
||||
&& (st->st_mode & ~_S_IFMT) != (file->mode & ~_S_IFMT))
|
||||
if (preserve_perms
|
||||
&& (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
|
||||
return 0;
|
||||
|
||||
if (preserve_uid && st->st_uid != file->uid)
|
||||
if (am_root && preserve_uid && st->st_uid != file->uid)
|
||||
return 0;
|
||||
|
||||
if (preserve_gid && st->st_gid != file->gid)
|
||||
if (preserve_gid && file->gid != GID_NONE
|
||||
&& st->st_gid != file->gid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -70,44 +81,29 @@ static int skip_file(char *fname,
|
||||
of the file time to determine whether to sync */
|
||||
if (always_checksum && S_ISREG(st->st_mode)) {
|
||||
char sum[MD4_SUM_LENGTH];
|
||||
char fnamecmpdest[MAXPATHLEN];
|
||||
|
||||
if (compare_dest != NULL) {
|
||||
if (access(fname, 0) != 0) {
|
||||
snprintf(fnamecmpdest,MAXPATHLEN,"%s/%s",
|
||||
compare_dest,fname);
|
||||
fname = fnamecmpdest;
|
||||
}
|
||||
}
|
||||
file_checksum(fname,sum,st->st_size);
|
||||
if (protocol_version < 21) {
|
||||
return (memcmp(sum,file->sum,2) == 0);
|
||||
} else {
|
||||
return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
|
||||
}
|
||||
return memcmp(sum, file->u.sum, protocol_version < 21 ? 2
|
||||
: MD4_SUM_LENGTH) == 0;
|
||||
}
|
||||
|
||||
if (size_only) {
|
||||
if (size_only)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ignore_times) {
|
||||
if (ignore_times)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (cmp_modtime(st->st_mtime,file->modtime) == 0);
|
||||
return cmp_modtime(st->st_mtime, file->modtime) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NULL sum_struct means we have no checksums
|
||||
* NULL sum_struct means we have no checksums
|
||||
*/
|
||||
|
||||
void write_sum_head(int f, struct sum_struct *sum)
|
||||
{
|
||||
static struct sum_struct null_sum;
|
||||
|
||||
if (sum == (struct sum_struct *)NULL)
|
||||
if (sum == NULL)
|
||||
sum = &null_sum;
|
||||
|
||||
write_int(f, sum->count);
|
||||
@@ -117,11 +113,11 @@ void write_sum_head(int f, struct sum_struct *sum)
|
||||
write_int(f, sum->remainder);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* set (initialize) the size entries in the per-file sum_struct
|
||||
* calulating dynamic block ans checksum sizes.
|
||||
* calculating dynamic block and checksum sizes.
|
||||
*
|
||||
* This is only called from generate_and_send_sums() but is a seperate
|
||||
* This is only called from generate_and_send_sums() but is a separate
|
||||
* function to encapsulate the logic.
|
||||
*
|
||||
* The block size is a rounded square root of file length.
|
||||
@@ -135,10 +131,10 @@ void write_sum_head(int f, struct sum_struct *sum)
|
||||
* This might be made one of several selectable heuristics.
|
||||
*/
|
||||
|
||||
static void sum_sizes_sqroot_baarda(struct sum_struct *sum, uint64 len)
|
||||
static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
|
||||
{
|
||||
extern int block_size;
|
||||
int blength, s2length, b;
|
||||
unsigned int blength;
|
||||
int s2length;
|
||||
uint32 c;
|
||||
uint64 l;
|
||||
|
||||
@@ -167,7 +163,7 @@ static void sum_sizes_sqroot_baarda(struct sum_struct *sum, uint64 len)
|
||||
} else if (csum_length == SUM_LENGTH) {
|
||||
s2length = SUM_LENGTH;
|
||||
} else {
|
||||
b = BLOCKSUM_BIAS;
|
||||
int b = BLOCKSUM_BIAS;
|
||||
l = len;
|
||||
while (l >>= 1) {
|
||||
b += 2;
|
||||
@@ -192,116 +188,122 @@ static void sum_sizes_sqroot_baarda(struct sum_struct *sum, uint64 len)
|
||||
sum->remainder = (len % blength);
|
||||
|
||||
if (sum->count && verbose > 2) {
|
||||
rprintf(FINFO, "count=%ld rem=%ld blength=%ld s2length=%ld flength=%.0f\n",
|
||||
(long) sum->count, (long) sum->remainder,
|
||||
(long) sum->blength, (long) sum->s2length,
|
||||
(double) sum->flength);
|
||||
rprintf(FINFO, "count=%.0f rem=%u blength=%u s2length=%d flength=%.0f\n",
|
||||
(double)sum->count, sum->remainder, sum->blength,
|
||||
sum->s2length, (double)sum->flength);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perhaps we want to just send an empty checksum set for this file,
|
||||
* which will force the whole thing to be literally transferred.
|
||||
*
|
||||
* When do we do this? If the user's explicitly said they
|
||||
* want the whole thing, or if { they haven't explicitly
|
||||
* requested a delta, and it's local but not batch mode.}
|
||||
*
|
||||
* Whew. */
|
||||
static BOOL disable_deltas_p(void)
|
||||
{
|
||||
extern int whole_file;
|
||||
extern int local_server;
|
||||
extern int write_batch;
|
||||
|
||||
if (whole_file > 0)
|
||||
return True;
|
||||
if (whole_file == 0 || write_batch)
|
||||
return False;
|
||||
return local_server;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate and send a stream of signatures/checksums that describe a buffer
|
||||
*
|
||||
* Generate approximately one checksum every block_len bytes.
|
||||
*/
|
||||
static void generate_and_send_sums(struct map_struct *buf, OFF_T len, int f_out)
|
||||
static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
{
|
||||
size_t i;
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
OFF_T offset = 0;
|
||||
|
||||
sum_sizes_sqroot_baarda(&sum, len);
|
||||
sum_sizes_sqroot(&sum, len);
|
||||
|
||||
if (len > 0)
|
||||
mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength);
|
||||
else
|
||||
mapbuf = NULL;
|
||||
|
||||
write_sum_head(f_out, &sum);
|
||||
|
||||
for (i = 0; i < sum.count; i++) {
|
||||
int n1 = MIN(len, sum.blength);
|
||||
char *map = map_ptr(buf, offset, n1);
|
||||
unsigned int n1 = MIN(len, sum.blength);
|
||||
char *map = map_ptr(mapbuf, offset, n1);
|
||||
uint32 sum1 = get_checksum1(map, n1);
|
||||
char sum2[SUM_LENGTH];
|
||||
|
||||
if (f_copy >= 0)
|
||||
full_write(f_copy, map, n1);
|
||||
|
||||
get_checksum2(map, n1, sum2);
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%ld] offset=%.0f len=%d sum1=%08lx\n",
|
||||
(long)i,(double)offset,n1,(unsigned long)sum1);
|
||||
"chunk[%.0f] offset=%.0f len=%u sum1=%08lx\n",
|
||||
(double)i, (double)offset, n1,
|
||||
(unsigned long)sum1);
|
||||
}
|
||||
write_int(f_out, sum1);
|
||||
write_buf(f_out, sum2, sum.s2length);
|
||||
len -= n1;
|
||||
offset += n1;
|
||||
}
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Acts on file number @p i from @p flist, whose name is @p fname.
|
||||
*
|
||||
* First fixes up permissions, then generates checksums for the file.
|
||||
*
|
||||
* @note This comment was added later by mbp who was trying to work it
|
||||
* out. It might be wrong.
|
||||
**/
|
||||
void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
|
||||
*/
|
||||
static void recv_generator(char *fname, struct file_struct *file, int i,
|
||||
int f_out)
|
||||
{
|
||||
int fd;
|
||||
STRUCT_STAT st;
|
||||
struct map_struct *buf;
|
||||
int statret;
|
||||
struct file_struct *file = flist->files[i];
|
||||
char *fnamecmp;
|
||||
int fd, f_copy;
|
||||
STRUCT_STAT st, partial_st;
|
||||
struct file_struct *back_file;
|
||||
int statret, stat_errno;
|
||||
char *fnamecmp, *partialptr, *backupptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
extern char *compare_dest;
|
||||
extern int list_only;
|
||||
extern int preserve_perms;
|
||||
extern int only_existing;
|
||||
extern int orig_umask;
|
||||
|
||||
if (list_only) return;
|
||||
if (list_only)
|
||||
return;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
|
||||
rprintf(FINFO, "recv_generator(%s,%d)\n", safe_fname(fname), i);
|
||||
|
||||
statret = link_stat(fname,&st);
|
||||
|
||||
if (only_existing && statret == -1 && errno == ENOENT) {
|
||||
/* we only want to update existing files */
|
||||
if (verbose > 1) rprintf(FINFO, "not creating new file \"%s\"\n",fname);
|
||||
if (server_exclude_list.head
|
||||
&& check_exclude(&server_exclude_list, fname,
|
||||
S_ISDIR(file->mode)) < 0) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "skipping server-excluded file \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (statret == 0 &&
|
||||
!preserve_perms &&
|
||||
(S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
|
||||
if (dry_run > 1) {
|
||||
statret = -1;
|
||||
stat_errno = ENOENT;
|
||||
} else {
|
||||
statret = link_stat(fname, &st,
|
||||
keep_dirlinks && S_ISDIR(file->mode));
|
||||
stat_errno = errno;
|
||||
}
|
||||
|
||||
if (only_existing && statret == -1 && stat_errno == ENOENT) {
|
||||
/* we only want to update existing files */
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "not creating new file \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (statret == 0 && !preserve_perms
|
||||
&& S_ISDIR(st.st_mode) == S_ISDIR(file->mode)) {
|
||||
/* if the file exists already and we aren't perserving
|
||||
* permissions then act as though the remote end sent
|
||||
* us the file permissions we already have */
|
||||
file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
|
||||
file->mode = (file->mode & ~CHMOD_BITS)
|
||||
| (st.st_mode & CHMOD_BITS);
|
||||
}
|
||||
|
||||
if (S_ISDIR(file->mode)) {
|
||||
@@ -311,28 +313,31 @@ void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
|
||||
* we need to delete it. If it doesn't exist, then
|
||||
* recursively create it. */
|
||||
|
||||
if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
|
||||
if (dry_run)
|
||||
return; /* TODO: causes inaccuracies -- fix */
|
||||
if (statret == 0 && !S_ISDIR(st.st_mode)) {
|
||||
if (robust_unlink(fname) != 0) {
|
||||
rprintf(FERROR,
|
||||
"recv_generator: unlink %s to make room for directory: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"recv_generator: unlink %s to make room for directory",
|
||||
full_fname(fname));
|
||||
return;
|
||||
}
|
||||
statret = -1;
|
||||
}
|
||||
if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
|
||||
if (!(relative_paths && errno==ENOENT &&
|
||||
create_directory_path(fname, orig_umask)==0 &&
|
||||
do_mkdir(fname,file->mode)==0)) {
|
||||
rprintf(FERROR, "recv_generator: mkdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (!(relative_paths && errno == ENOENT
|
||||
&& create_directory_path(fname, orig_umask) == 0
|
||||
&& do_mkdir(fname, file->mode) == 0)) {
|
||||
rsyserr(FERROR, errno,
|
||||
"recv_generator: mkdir %s failed",
|
||||
full_fname(fname));
|
||||
}
|
||||
}
|
||||
/* f_out is set to -1 when doing final directory
|
||||
permission and modification time repair */
|
||||
if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1))
|
||||
rprintf(FINFO,"%s/\n",fname);
|
||||
/* f_out is set to -1 when doing final directory-permission
|
||||
* and modification-time repair. */
|
||||
if (set_perms(fname, file, statret ? NULL : &st, 0)
|
||||
&& verbose && f_out != -1)
|
||||
rprintf(FINFO, "%s/\n", safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -340,12 +345,11 @@ void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
|
||||
#if SUPPORT_LINKS
|
||||
char lnk[MAXPATHLEN];
|
||||
int l;
|
||||
extern int safe_symlinks;
|
||||
|
||||
if (safe_symlinks && unsafe_symlink(file->link, fname)) {
|
||||
if (safe_symlinks && unsafe_symlink(file->u.link, fname)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "ignoring unsafe symlink %s -> \"%s\"\n",
|
||||
full_fname(fname), file->link);
|
||||
full_fname(fname), file->u.link);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -356,8 +360,9 @@ void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
|
||||
/* A link already pointing to the
|
||||
* right place -- no further action
|
||||
* required. */
|
||||
if (strcmp(lnk,file->link) == 0) {
|
||||
set_perms(fname,file,&st,1);
|
||||
if (strcmp(lnk,file->u.link) == 0) {
|
||||
set_perms(fname, file, &st,
|
||||
PERMS_REPORT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -366,13 +371,14 @@ void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
|
||||
* in place. */
|
||||
delete_file(fname);
|
||||
}
|
||||
if (do_symlink(file->link,fname) != 0) {
|
||||
rprintf(FERROR, "symlink %s -> \"%s\" failed: %s\n",
|
||||
full_fname(fname), file->link, strerror(errno));
|
||||
if (do_symlink(file->u.link,fname) != 0) {
|
||||
rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
|
||||
full_fname(fname), safe_fname(file->u.link));
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
if (verbose) {
|
||||
rprintf(FINFO,"%s -> %s\n", fname,file->link);
|
||||
rprintf(FINFO, "%s -> %s\n", safe_fname(fname),
|
||||
safe_fname(file->u.link));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -383,161 +389,212 @@ void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
|
||||
if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
|
||||
if (statret != 0 ||
|
||||
st.st_mode != file->mode ||
|
||||
(DEV64_T)st.st_rdev != file->rdev) {
|
||||
st.st_rdev != file->u.rdev) {
|
||||
delete_file(fname);
|
||||
if (verbose > 2)
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
|
||||
fname,(int)file->mode,(int)file->rdev);
|
||||
if (do_mknod(fname,file->mode,file->rdev) != 0) {
|
||||
rprintf(FERROR, "mknod %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
safe_fname(fname),
|
||||
(int)file->mode, (int)file->u.rdev);
|
||||
}
|
||||
if (do_mknod(fname,file->mode,file->u.rdev) != 0) {
|
||||
rsyserr(FERROR, errno, "mknod %s failed",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
if (verbose)
|
||||
rprintf(FINFO,"%s\n",fname);
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "%s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set_perms(fname,file,&st,1);
|
||||
set_perms(fname, file, &st, PERMS_REPORT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (preserve_hard_links && check_hard_link(file)) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "recv_generator: \"%s\" is a hard link\n",f_name(file));
|
||||
if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
|
||||
rprintf(FINFO, "skipping non-regular file \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
fnamecmp = fname;
|
||||
|
||||
if ((statret == -1) && (compare_dest != NULL)) {
|
||||
if (statret == -1 && compare_dest != NULL) {
|
||||
/* try the file at compare_dest instead */
|
||||
int saveerrno = errno;
|
||||
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
|
||||
statret = link_stat(fnamecmpbuf,&st);
|
||||
if (!S_ISREG(st.st_mode))
|
||||
statret = -1;
|
||||
if (statret == -1)
|
||||
errno = saveerrno;
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
|
||||
if (link_stat(fnamecmpbuf, &st, 0) == 0
|
||||
&& S_ISREG(st.st_mode)) {
|
||||
#if HAVE_LINK
|
||||
else if (link_dest && !dry_run) {
|
||||
if (do_link(fnamecmpbuf, fname) != 0) {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"link %s => %s : %s\n",
|
||||
fnamecmpbuf,
|
||||
fname,
|
||||
strerror(errno));
|
||||
}
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
if (link_dest && !dry_run) {
|
||||
if (do_link(fnamecmpbuf, fname) < 0) {
|
||||
if (verbose) {
|
||||
rsyserr(FINFO, errno,
|
||||
"link %s => %s",
|
||||
fnamecmpbuf,
|
||||
safe_fname(fname));
|
||||
}
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
else
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fnamecmp = fnamecmpbuf;
|
||||
statret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (statret == 0 && !S_ISREG(st.st_mode)) {
|
||||
if (delete_file(fname) != 0)
|
||||
return;
|
||||
statret = -1;
|
||||
stat_errno = ENOENT;
|
||||
}
|
||||
|
||||
if (partial_dir && (partialptr = partial_dir_fname(fname))
|
||||
&& link_stat(partialptr, &partial_st, 0) == 0
|
||||
&& S_ISREG(partial_st.st_mode)) {
|
||||
if (statret == -1)
|
||||
goto prepare_to_open;
|
||||
} else
|
||||
partialptr = NULL;
|
||||
|
||||
if (statret == -1) {
|
||||
if (errno == ENOENT) {
|
||||
write_int(f_out,i);
|
||||
if (!dry_run) write_sum_head(f_out, NULL);
|
||||
} else if (verbose > 1) {
|
||||
rprintf(FERROR,
|
||||
"recv_generator: failed to open %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
if (delete_file(fname) != 0) {
|
||||
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
|
||||
return;
|
||||
if (stat_errno == ENOENT) {
|
||||
write_int(f_out,i);
|
||||
if (!dry_run && !read_batch)
|
||||
write_sum_head(f_out, NULL);
|
||||
} else if (verbose > 1) {
|
||||
rsyserr(FERROR, stat_errno,
|
||||
"recv_generator: failed to stat %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
|
||||
/* now pretend the file didn't exist */
|
||||
write_int(f_out,i);
|
||||
if (!dry_run) write_sum_head(f_out, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt_ignore_existing && fnamecmp == fname) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"%s exists\n",fname);
|
||||
rprintf(FINFO, "%s exists\n", safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
|
||||
if (update_only && fnamecmp == fname
|
||||
&& cmp_modtime(st.st_mtime, file->modtime) > 0) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"%s is newer\n",fname);
|
||||
rprintf(FINFO, "%s is newer\n", safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (skip_file(fname, file, &st)) {
|
||||
if (skip_file(fnamecmp, file, &st)) {
|
||||
if (fnamecmp == fname)
|
||||
set_perms(fname,file,&st,1);
|
||||
set_perms(fname, file, &st, PERMS_REPORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dry_run) {
|
||||
prepare_to_open:
|
||||
if (dry_run || read_batch) {
|
||||
write_int(f_out,i);
|
||||
return;
|
||||
}
|
||||
|
||||
if (disable_deltas_p()) {
|
||||
if (whole_file > 0) {
|
||||
write_int(f_out,i);
|
||||
write_sum_head(f_out, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partialptr) {
|
||||
st = partial_st;
|
||||
fnamecmp = partialptr;
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
rprintf(FERROR, "failed to open %s, continuing: %s\n",
|
||||
full_fname(fnamecmp), strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to open %s, continuing",
|
||||
full_fname(fnamecmp));
|
||||
pretend_missing:
|
||||
/* pretend the file didn't exist */
|
||||
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
|
||||
return;
|
||||
write_int(f_out,i);
|
||||
write_sum_head(f_out, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size > 0) {
|
||||
buf = map_file(fd,st.st_size);
|
||||
if (inplace && make_backups) {
|
||||
if (!(backupptr = get_backup_name(fname))) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (!(back_file = make_file(fname, NULL, NO_EXCLUDES))) {
|
||||
close(fd);
|
||||
goto pretend_missing;
|
||||
}
|
||||
if (robust_unlink(backupptr) && errno != ENOENT) {
|
||||
rsyserr(FERROR, errno, "unlink %s",
|
||||
full_fname(backupptr));
|
||||
free(back_file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if ((f_copy = do_open(backupptr,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
|
||||
rsyserr(FERROR, errno, "open %s",
|
||||
full_fname(backupptr));
|
||||
free(back_file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
buf = NULL;
|
||||
backupptr = NULL;
|
||||
back_file = NULL;
|
||||
f_copy = -1;
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "gen mapped %s of size %.0f\n",
|
||||
safe_fname(fnamecmp), (double)st.st_size);
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "generating and sending sums for %d\n", i);
|
||||
|
||||
write_int(f_out,i);
|
||||
generate_and_send_sums(buf, st.st_size, f_out);
|
||||
generate_and_send_sums(fd, st.st_size, f_out, f_copy);
|
||||
|
||||
if (f_copy >= 0) {
|
||||
close(f_copy);
|
||||
set_perms(backupptr, back_file, NULL, 0);
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, backupptr);
|
||||
free(back_file);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (buf) unmap_file(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
|
||||
void generate_files(int f_out, struct file_list *flist, char *local_name)
|
||||
{
|
||||
int i;
|
||||
int phase=0;
|
||||
int phase = 0;
|
||||
char fbuf[MAXPATHLEN];
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"generator starting pid=%d count=%d\n",
|
||||
(int)getpid(),flist->count);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "generator starting pid=%ld count=%d\n",
|
||||
(long)getpid(), flist->count);
|
||||
}
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO,
|
||||
disable_deltas_p()
|
||||
whole_file > 0
|
||||
? "delta-transmission disabled for local transfer or --whole-file\n"
|
||||
: "delta transmission enabled\n");
|
||||
}
|
||||
@@ -549,42 +606,61 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
|
||||
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
mode_t saved_mode = file->mode;
|
||||
if (!file->basename) continue;
|
||||
struct file_struct copy;
|
||||
|
||||
if (!file->basename)
|
||||
continue;
|
||||
/* we need to ensure that any directories we create have writeable
|
||||
permissions initially so that we can create the files within
|
||||
them. This is then fixed after the files are transferred */
|
||||
if (!am_root && S_ISDIR(file->mode)) {
|
||||
file->mode |= S_IWUSR; /* user write */
|
||||
if (!am_root && S_ISDIR(file->mode) && !(file->mode & S_IWUSR)) {
|
||||
copy = *file;
|
||||
/* XXX: Could this be causing a problem on SCO? Perhaps their
|
||||
* handling of permissions is strange? */
|
||||
copy.mode |= S_IWUSR; /* user write */
|
||||
file = ©
|
||||
}
|
||||
|
||||
recv_generator(local_name?local_name:f_name(file), flist,i,f);
|
||||
|
||||
file->mode = saved_mode;
|
||||
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
|
||||
file, i, f_out);
|
||||
}
|
||||
|
||||
phase++;
|
||||
csum_length = SUM_LENGTH;
|
||||
ignore_times=1;
|
||||
ignore_times = 1;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"generate_files phase=%d\n",phase);
|
||||
|
||||
write_int(f,-1);
|
||||
write_int(f_out, -1);
|
||||
|
||||
/* files can cycle through the system more than once
|
||||
* to catch initial checksum errors */
|
||||
for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
|
||||
while ((i = get_redo_num()) != -1) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
recv_generator(local_name?local_name:f_name(file), flist,i,f);
|
||||
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
|
||||
file, i, f_out);
|
||||
}
|
||||
|
||||
phase++;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"generate_files phase=%d\n",phase);
|
||||
|
||||
write_int(f,-1);
|
||||
write_int(f_out, -1);
|
||||
|
||||
if (preserve_hard_links)
|
||||
do_hard_links();
|
||||
|
||||
/* now we need to fix any directory permissions that were
|
||||
* modified during the transfer */
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
if (!file->basename || !S_ISDIR(file->mode))
|
||||
continue;
|
||||
recv_generator(local_name ? local_name : f_name(file),
|
||||
file, i, -1);
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"generate_files finished\n");
|
||||
}
|
||||
|
||||
17
getfsdev.c
Normal file
17
getfsdev.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "rsync.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
|
||||
while (--argc > 0) {
|
||||
if (stat(*++argv, &st) < 0) {
|
||||
fprintf(stderr, "Unable to stat `%s'\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
printf("%ld/%ld\n", (long)major(st.st_dev),
|
||||
(long)minor(st.st_dev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
getgroups.c
36
getgroups.c
@@ -26,24 +26,42 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifndef NGROUPS
|
||||
/* It ought to be defined, but just in case. */
|
||||
# define NGROUPS 32
|
||||
#endif
|
||||
|
||||
int
|
||||
main(UNUSED(int argc), UNUSED(char *argv[]))
|
||||
{
|
||||
int n, i;
|
||||
gid_t list[NGROUPS];
|
||||
gid_t *list;
|
||||
gid_t gid = MY_GID();
|
||||
int gid_in_list = 0;
|
||||
|
||||
if ((n = getgroups(NGROUPS, list)) == -1) {
|
||||
#ifdef HAVE_GETGROUPS
|
||||
if ((n = getgroups(0, NULL)) < 0) {
|
||||
perror("getgroups");
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
n = 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
printf("%u ", list[i]);
|
||||
list = (gid_t*)malloc(sizeof (gid_t) * (n + 1));
|
||||
if (!list) {
|
||||
fprintf(stderr, "out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
if (n > 0)
|
||||
n = getgroups(n, list);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
printf("%lu ", (unsigned long)list[i]);
|
||||
if (list[i] == gid)
|
||||
gid_in_list = 1;
|
||||
}
|
||||
/* The default gid might not be in the list on some systems. */
|
||||
if (!gid_in_list)
|
||||
printf("%lu", (unsigned long)gid);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
|
||||
230
hlink.c
230
hlink.c
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
Copyright (C) 2002 by Martin Pool <mbp@samba.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -22,138 +22,146 @@
|
||||
|
||||
extern int dry_run;
|
||||
extern int verbose;
|
||||
extern int make_backups;
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
static int hlink_compare(struct file_struct *f1, struct file_struct *f2)
|
||||
static int hlink_compare(struct file_struct **file1, struct file_struct **file2)
|
||||
{
|
||||
if (!S_ISREG(f1->mode) && !S_ISREG(f2->mode))
|
||||
return 0;
|
||||
if (!S_ISREG(f1->mode))
|
||||
return -1;
|
||||
if (!S_ISREG(f2->mode))
|
||||
return 1;
|
||||
struct file_struct *f1 = *file1;
|
||||
struct file_struct *f2 = *file2;
|
||||
|
||||
if (f1->dev != f2->dev)
|
||||
return (int) (f1->dev > f2->dev ? 1 : -1);
|
||||
if (f1->F_DEV != f2->F_DEV)
|
||||
return (int) (f1->F_DEV > f2->F_DEV ? 1 : -1);
|
||||
|
||||
if (f1->inode != f2->inode)
|
||||
return (int) (f1->inode > f2->inode ? 1 : -1);
|
||||
if (f1->F_INODE != f2->F_INODE)
|
||||
return (int) (f1->F_INODE > f2->F_INODE ? 1 : -1);
|
||||
|
||||
return file_compare(&f1, &f2);
|
||||
return file_compare(file1, file2);
|
||||
}
|
||||
|
||||
|
||||
static struct file_struct *hlink_list;
|
||||
static struct file_struct **hlink_list;
|
||||
static int hlink_count;
|
||||
|
||||
#define LINKED(p1,p2) ((p1)->F_DEV == (p2)->F_DEV \
|
||||
&& (p1)->F_INODE == (p2)->F_INODE)
|
||||
|
||||
/* Analyze the data in the hlink_list[], remove items that aren't multiply
|
||||
* linked, and replace the dev+inode data with the hlindex+next linked list. */
|
||||
static void link_idev_data(struct file_list *flist)
|
||||
{
|
||||
struct file_struct *head;
|
||||
int from, to, start;
|
||||
|
||||
alloc_pool_t hlink_pool;
|
||||
alloc_pool_t idev_pool = flist->hlink_pool;
|
||||
|
||||
hlink_pool = pool_create(128 * 1024, sizeof (struct hlink),
|
||||
out_of_memory, POOL_INTERN);
|
||||
|
||||
for (from = to = 0; from < hlink_count; from++) {
|
||||
start = from;
|
||||
head = hlink_list[start];
|
||||
while (from < hlink_count-1
|
||||
&& LINKED(hlink_list[from], hlink_list[from+1])) {
|
||||
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
|
||||
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
|
||||
struct hlink, 1, "hlink_list");
|
||||
|
||||
hlink_list[from]->F_HLINDEX = to;
|
||||
hlink_list[from]->F_NEXT = hlink_list[from+1];
|
||||
from++;
|
||||
}
|
||||
if (from > start) {
|
||||
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
|
||||
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
|
||||
struct hlink, 1, "hlink_list");
|
||||
|
||||
hlink_list[from]->F_HLINDEX = to;
|
||||
hlink_list[from]->F_NEXT = head;
|
||||
hlink_list[from]->flags |= FLAG_HLINK_EOL;
|
||||
hlink_list[to++] = head;
|
||||
} else {
|
||||
pool_free(idev_pool, 0, head->link_u.idev);
|
||||
head->link_u.idev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!to) {
|
||||
free(hlink_list);
|
||||
hlink_list = NULL;
|
||||
pool_destroy(hlink_pool);
|
||||
hlink_pool = NULL;
|
||||
} else {
|
||||
hlink_count = to;
|
||||
if (!(hlink_list = realloc_array(hlink_list,
|
||||
struct file_struct *, hlink_count)))
|
||||
out_of_memory("init_hard_links");
|
||||
}
|
||||
flist->hlink_pool = hlink_pool;
|
||||
pool_destroy(idev_pool);
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_hard_links(struct file_list *flist)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
int i;
|
||||
|
||||
if (flist->count < 2)
|
||||
return;
|
||||
|
||||
if (hlink_list)
|
||||
free(hlink_list);
|
||||
|
||||
if (!(hlink_list = new_array(struct file_struct, flist->count)))
|
||||
if (!(hlink_list = new_array(struct file_struct *, flist->count)))
|
||||
out_of_memory("init_hard_links");
|
||||
|
||||
for (i = 0; i < flist->count; i++)
|
||||
memcpy(&hlink_list[i], flist->files[i],
|
||||
sizeof(hlink_list[0]));
|
||||
hlink_count = 0;
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
if (flist->files[i]->link_u.idev)
|
||||
hlink_list[hlink_count++] = flist->files[i];
|
||||
}
|
||||
|
||||
qsort(hlink_list, flist->count,
|
||||
sizeof(hlink_list[0]), (int (*)()) hlink_compare);
|
||||
qsort(hlink_list, hlink_count,
|
||||
sizeof hlink_list[0], (int (*)()) hlink_compare);
|
||||
|
||||
hlink_count = flist->count;
|
||||
if (!hlink_count) {
|
||||
free(hlink_list);
|
||||
hlink_list = NULL;
|
||||
} else
|
||||
link_idev_data(flist);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* check if a file should be skipped because it is the same as an
|
||||
earlier hard link */
|
||||
int check_hard_link(struct file_struct *file)
|
||||
int hard_link_check(struct file_struct *file, int skip)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
int low = 0, high = hlink_count - 1;
|
||||
int ret = 0;
|
||||
|
||||
if (!hlink_list || !S_ISREG(file->mode))
|
||||
if (!hlink_list || !file->link_u.links)
|
||||
return 0;
|
||||
|
||||
while (low != high) {
|
||||
int mid = (low + high) / 2;
|
||||
ret = hlink_compare(&hlink_list[mid], file);
|
||||
if (ret == 0) {
|
||||
low = mid;
|
||||
break;
|
||||
}
|
||||
if (ret > 0)
|
||||
high = mid;
|
||||
else
|
||||
low = mid + 1;
|
||||
}
|
||||
|
||||
/* XXX: To me this looks kind of dodgy -- why do we use [low]
|
||||
* here and [low-1] below? -- mbp */
|
||||
if (hlink_compare(&hlink_list[low], file) != 0)
|
||||
return 0;
|
||||
|
||||
if (low > 0 &&
|
||||
S_ISREG(hlink_list[low - 1].mode) &&
|
||||
file->dev == hlink_list[low - 1].dev &&
|
||||
file->inode == hlink_list[low - 1].inode) {
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "check_hard_link: \"%s\" is a hard link to file %d, \"%s\"\n",
|
||||
f_name(file), low-1, f_name(&hlink_list[low-1]));
|
||||
if (skip && !(file->flags & FLAG_HLINK_EOL))
|
||||
hlink_list[file->F_HLINDEX] = file->F_NEXT;
|
||||
if (hlink_list[file->F_HLINDEX] != file) {
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "\"%s\" is a hard link\n",
|
||||
f_name(file));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
static void hard_link_one(int i)
|
||||
static void hard_link_one(char *hlink1, char *hlink2)
|
||||
{
|
||||
STRUCT_STAT st1, st2;
|
||||
|
||||
if (link_stat(f_name(&hlink_list[i - 1]), &st1) != 0)
|
||||
return;
|
||||
|
||||
if (link_stat(f_name(&hlink_list[i]), &st2) != 0) {
|
||||
if (do_link
|
||||
(f_name(&hlink_list[i - 1]),
|
||||
f_name(&hlink_list[i])) != 0) {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "link %s => %s : %s\n",
|
||||
f_name(&hlink_list[i]),
|
||||
f_name(&hlink_list[i - 1]),
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino)
|
||||
return;
|
||||
|
||||
if (robust_unlink(f_name(&hlink_list[i])) != 0 ||
|
||||
do_link(f_name(&hlink_list[i - 1]),
|
||||
f_name(&hlink_list[i])) != 0) {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "link %s => %s : %s\n",
|
||||
f_name(&hlink_list[i]),
|
||||
f_name(&hlink_list[i - 1]),
|
||||
strerror(errno));
|
||||
return;
|
||||
if (do_link(hlink1, hlink2)) {
|
||||
if (verbose) {
|
||||
rsyserr(FINFO, errno, "link %s => %s failed",
|
||||
hlink2, hlink1);
|
||||
}
|
||||
}
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "%s => %s\n",
|
||||
f_name(&hlink_list[i]),
|
||||
f_name(&hlink_list[i - 1]));
|
||||
else if (verbose)
|
||||
rprintf(FINFO, "%s => %s\n", hlink2, hlink1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -166,18 +174,38 @@ static void hard_link_one(int i)
|
||||
void do_hard_links(void)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
struct file_struct *file, *first;
|
||||
char hlink1[MAXPATHLEN];
|
||||
char *hlink2;
|
||||
STRUCT_STAT st1, st2;
|
||||
int i;
|
||||
|
||||
if (!hlink_list)
|
||||
return;
|
||||
|
||||
for (i = 1; i < hlink_count; i++) {
|
||||
if (S_ISREG(hlink_list[i].mode) &&
|
||||
S_ISREG(hlink_list[i - 1].mode) &&
|
||||
hlink_list[i].basename && hlink_list[i - 1].basename &&
|
||||
hlink_list[i].dev == hlink_list[i - 1].dev &&
|
||||
hlink_list[i].inode == hlink_list[i - 1].inode) {
|
||||
hard_link_one(i);
|
||||
for (i = 0; i < hlink_count; i++) {
|
||||
first = file = hlink_list[i];
|
||||
if (link_stat(f_name_to(first, hlink1), &st1, 0) < 0)
|
||||
continue;
|
||||
while ((file = file->F_NEXT) != first) {
|
||||
hlink2 = f_name(file);
|
||||
if (link_stat(hlink2, &st2, 0) == 0) {
|
||||
if (st2.st_dev == st1.st_dev
|
||||
&& st2.st_ino == st1.st_ino)
|
||||
continue;
|
||||
if (make_backups) {
|
||||
if (!make_backup(hlink2))
|
||||
continue;
|
||||
} else if (robust_unlink(hlink2)) {
|
||||
if (verbose > 0) {
|
||||
rsyserr(FINFO, errno,
|
||||
"unlink %s failed",
|
||||
full_fname(hlink2));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
hard_link_one(hlink1, hlink2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,49 +1 @@
|
||||
.cvsignore
|
||||
Makefile
|
||||
a
|
||||
b
|
||||
config.cache
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
dist.tar.gz
|
||||
dummy
|
||||
rsync
|
||||
rsync-0.1
|
||||
rsync-0.1
|
||||
rsync-0.1
|
||||
rsync-0.1.tar.gz
|
||||
rsync-0.2
|
||||
rsync-0.2
|
||||
rsync-0.2.tar.gz
|
||||
rsync-0.3
|
||||
rsync-0.3
|
||||
rsync-0.3.tar.gz
|
||||
rsync-0.4
|
||||
rsync-0.4
|
||||
rsync-0.4.tar.gz
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5
|
||||
rsync-0.5.tar.gz
|
||||
rsync-0.6
|
||||
rsync-0.7
|
||||
rsync-0.7
|
||||
rsync-0.8
|
||||
rsync-0.8
|
||||
rsync-0.8
|
||||
rsync-0.8
|
||||
rsync-ERSION
|
||||
rsync.aux
|
||||
rsync.dvi
|
||||
rsync.log
|
||||
tech_report.aux
|
||||
tech_report.dvi
|
||||
tech_report.log
|
||||
tech_report.ps
|
||||
test
|
||||
|
||||
17
lib/compat.c
17
lib/compat.c
@@ -116,10 +116,12 @@
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
size_t ret = len;
|
||||
if (bufsize <= 0) return 0;
|
||||
if (len >= bufsize) len = bufsize-1;
|
||||
memcpy(d, s, len);
|
||||
d[len] = 0;
|
||||
if (bufsize > 0) {
|
||||
if (len >= bufsize)
|
||||
len = bufsize-1;
|
||||
memcpy(d, s, len);
|
||||
d[len] = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -138,10 +140,9 @@
|
||||
size_t len2 = strlen(s);
|
||||
size_t ret = len1 + len2;
|
||||
|
||||
if (len1+len2 >= bufsize) {
|
||||
len2 = bufsize - (len1+1);
|
||||
}
|
||||
if (len2 > 0) {
|
||||
if (len1 < bufsize - 1) {
|
||||
if (len2 >= bufsize - len1)
|
||||
len2 = bufsize - len1 - 1;
|
||||
memcpy(d+len1, s, len2);
|
||||
d[len1+len2] = 0;
|
||||
}
|
||||
|
||||
199
lib/pool_alloc.3
Normal file
199
lib/pool_alloc.3
Normal file
@@ -0,0 +1,199 @@
|
||||
.ds d \-\^\-
|
||||
.ds o \fR[\fP
|
||||
.ds c \fR]\fP
|
||||
.ds | \fR|\fP
|
||||
.de D
|
||||
\\.B \*d\\$1
|
||||
..
|
||||
.de DI
|
||||
\\.BI \*d\\$1 \\$2
|
||||
..
|
||||
.de DR
|
||||
\\.BR \*d\\$1 \\$2
|
||||
..
|
||||
.de Di
|
||||
\\.BI \*d\\$1 " \\$2"
|
||||
..
|
||||
.de Db
|
||||
\\.B \*d\\$1 " \\$2"
|
||||
..
|
||||
.de Df
|
||||
\\.B \*d\*ono\*c\\$1
|
||||
..
|
||||
.de See
|
||||
See \fB\\$1\fP for details.
|
||||
..
|
||||
.de SeeIn
|
||||
See \fB\\$1\fP in \fB\\$2\fP for details.
|
||||
..
|
||||
.TH POOL_ALLOC 3
|
||||
.SH NAME
|
||||
pool_alloc, pool_free, pool_talloc, pool_tfree, pool_create, pool_destroy
|
||||
\- Allocate and free memory in managed allocation pools.
|
||||
.SH SYNOPSIS
|
||||
.B #include "pool_alloc.h"
|
||||
|
||||
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char *), int \fIflags\fB);
|
||||
|
||||
\fBvoid pool_destroy(struct alloc_pool *\fIpool\fB);
|
||||
|
||||
\fBvoid *pool_alloc(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, char *\fImsg\fB);
|
||||
|
||||
\fBvoid pool_free(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid *pool_talloc(struct alloc_pool *\fIpool\fB, \fItype\fB), int \fIcount\fB, char *\fImsg\fB);
|
||||
|
||||
\fBvoid pool_tfree(struct alloc_pool *\fIpool\fB, \fItype\fB, int \fIcount\fB, void *\fIaddr\fB);
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
The pool allocation routines use
|
||||
.B malloc()
|
||||
for underlying memory management.
|
||||
What allocation pools do is cause
|
||||
memory within a given pool to be in large contigious blocks
|
||||
(called extents) that when freed will be reusable. Unlike
|
||||
.B malloc()
|
||||
the allocations are not managed individually.
|
||||
Instead each extent tracks the total free memory within the
|
||||
extent. Each extent can either be used to allocate memory
|
||||
or to manage the freeing of memory within that extent.
|
||||
When an extent has less free memory than a given
|
||||
allocation request or when the first request to free
|
||||
memory within that extent is received the extent ceases to
|
||||
be used for allocation.
|
||||
.P
|
||||
This form of memory management is suited to large numbers of small
|
||||
related allocations that are held for a while
|
||||
and then freed as a group.
|
||||
Because the
|
||||
underlying allocations are done in large contigious extents
|
||||
when an extent is freed it releases a large enough
|
||||
contigious block of memory to be useful to subsequent
|
||||
.B malloc()
|
||||
and
|
||||
.B pool_alloc()
|
||||
calls even if allocations from other pools or from
|
||||
.B malloc()
|
||||
are made between allocations from a given pool.
|
||||
.P
|
||||
.B pool_create()
|
||||
Creates an allocation pool for subsequent calls to the pool
|
||||
allocation functions.
|
||||
When an extent is created for allocations it will be
|
||||
.I size
|
||||
bytes.
|
||||
Allocations from the pool have their sizes rounded up to a
|
||||
multiple of
|
||||
.I quantum
|
||||
bytes in length.
|
||||
Specifying
|
||||
.B 0
|
||||
for
|
||||
.I quantum
|
||||
Will produce a quantum that should meet maximal allignment
|
||||
on most platforms.
|
||||
If the
|
||||
.B POOL_QALIGN
|
||||
.I flag
|
||||
is set allocations will be aligned to addresses that are a
|
||||
multiple of
|
||||
.IR quantum .
|
||||
If the
|
||||
.B POOL_CLEAR
|
||||
.I flag
|
||||
is set all allocations from the pool will be zero filled.
|
||||
.P
|
||||
.B pool_destroy()
|
||||
destroys an allocation pool and frees all memory allocated
|
||||
in that pool.
|
||||
.P
|
||||
.B pool_alloc()
|
||||
allocates
|
||||
.I size
|
||||
bytes from the specified
|
||||
.IR pool .
|
||||
If
|
||||
.I size
|
||||
is
|
||||
.B 0
|
||||
.I quantum
|
||||
bytes will be freed.
|
||||
If the requested memory cannot be allocated
|
||||
.B pool_alloc()
|
||||
will call
|
||||
.I bomb()
|
||||
function, if defined, with
|
||||
.I msg
|
||||
as it's sole argument and
|
||||
.B NULL
|
||||
will be returned.
|
||||
.P
|
||||
.B pool_free()
|
||||
frees
|
||||
.I size
|
||||
bytes pointed to by
|
||||
.I addr
|
||||
previously allocated in the specified
|
||||
.IR pool .
|
||||
The memory freed within an extent will not be reusable until
|
||||
all of the memory in that extent has been freed but
|
||||
depending on the order in which the
|
||||
allocations are freed some extents may be released for reuse
|
||||
while others are still in use.
|
||||
If
|
||||
.I size
|
||||
is
|
||||
.B 0
|
||||
.I quantum
|
||||
bytes will be freed.
|
||||
If
|
||||
.I addr
|
||||
is
|
||||
.B 0
|
||||
no memory will be freed but subsequent allocations will come
|
||||
from a new extent.
|
||||
.P
|
||||
.B pool_talloc()
|
||||
is a macro that take a
|
||||
.I type
|
||||
and
|
||||
.I count
|
||||
instead of
|
||||
.I size
|
||||
and will cast the return value to the correct type.
|
||||
.P
|
||||
.B pool_tfree
|
||||
is a macro to free memory previously allocated in the
|
||||
specified
|
||||
.IR pool .
|
||||
.SH RETURN VALUE
|
||||
.B pool_create()
|
||||
returns a pointer to
|
||||
.BR "struct alloc_pool" .
|
||||
.P
|
||||
.B pool_alloc()
|
||||
and
|
||||
.B pool_talloc()
|
||||
return pointers to the allocated memory,
|
||||
or NULL if the request fails.
|
||||
For each extent so long as no allocations are smaller than varaible
|
||||
allignment requirements this pointer will be suitably
|
||||
alligned for any kind of variable.
|
||||
The return type of
|
||||
.B pool_alloc()
|
||||
will normally require casting to the desired type but
|
||||
.B pool_talloc()
|
||||
will returns a pointer of the requested
|
||||
.IR type .
|
||||
.P
|
||||
.BR pool_free() ,
|
||||
.B pool_tfree()
|
||||
and
|
||||
.B pool_destroy()
|
||||
return no value.
|
||||
.SH SEE ALSO
|
||||
.nf
|
||||
malloc(3)
|
||||
.SH AUTHOR
|
||||
pool_alloc was created by J.W. Schultz of Pegasystems Technologies.
|
||||
.SH BUGS AND ISSUES
|
||||
304
lib/pool_alloc.c
Normal file
304
lib/pool_alloc.c
Normal file
@@ -0,0 +1,304 @@
|
||||
#include "rsync.h"
|
||||
|
||||
#define POOL_DEF_EXTENT (32 * 1024)
|
||||
|
||||
struct alloc_pool
|
||||
{
|
||||
size_t size; /* extent size */
|
||||
size_t quantum; /* allocation quantum */
|
||||
struct pool_extent *live; /* current extent for
|
||||
* allocations */
|
||||
struct pool_extent *free; /* unfreed extent list */
|
||||
void (*bomb)();
|
||||
/* function to call if
|
||||
* malloc fails */
|
||||
int flags;
|
||||
|
||||
/* statistical data */
|
||||
unsigned long e_created; /* extents created */
|
||||
unsigned long e_freed; /* extents detroyed */
|
||||
uint64 n_allocated; /* calls to alloc */
|
||||
uint64 n_freed; /* calls to free */
|
||||
uint64 b_allocated; /* cum. bytes allocated */
|
||||
uint64 b_freed; /* cum. bytes freed */
|
||||
};
|
||||
|
||||
struct pool_extent
|
||||
{
|
||||
void *start; /* starting address */
|
||||
size_t free; /* free bytecount */
|
||||
size_t bound; /* bytes bound by padding,
|
||||
* overhead and freed */
|
||||
struct pool_extent *next;
|
||||
};
|
||||
|
||||
struct align_test {
|
||||
void *foo;
|
||||
uint64 bar;
|
||||
};
|
||||
|
||||
#define MINALIGN offsetof(struct align_test, bar)
|
||||
|
||||
/* Temporarily cast a void* var into a char* var when adding an offset (to
|
||||
* keep some compilers from complaining about the pointer arithmetic). */
|
||||
#define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
|
||||
|
||||
alloc_pool_t
|
||||
pool_create(size_t size, size_t quantum,
|
||||
void (*bomb)(char *), int flags)
|
||||
{
|
||||
struct alloc_pool *pool;
|
||||
|
||||
if (!(pool = (struct alloc_pool*) malloc(sizeof (struct alloc_pool))))
|
||||
return pool;
|
||||
memset(pool, 0, sizeof (struct alloc_pool));
|
||||
|
||||
pool->size = size /* round extent size to min alignment reqs */
|
||||
? (size + MINALIGN - 1) & ~(MINALIGN - 1)
|
||||
: POOL_DEF_EXTENT;
|
||||
if (pool->flags & POOL_INTERN)
|
||||
{
|
||||
pool->size -= sizeof (struct pool_extent);
|
||||
flags |= POOL_APPEND;
|
||||
}
|
||||
pool->quantum = quantum ? quantum : MINALIGN;
|
||||
pool->bomb = bomb;
|
||||
pool->flags = flags;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
void
|
||||
pool_destroy(alloc_pool_t p)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur, *next;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
if (pool->live)
|
||||
{
|
||||
cur = pool->live;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
}
|
||||
for (cur = pool->free; cur; cur = next)
|
||||
{
|
||||
next = cur->next;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
}
|
||||
free(pool);
|
||||
}
|
||||
|
||||
void *
|
||||
pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
if (!len)
|
||||
len = pool->quantum;
|
||||
else if (pool->quantum > 1 && len % pool->quantum)
|
||||
len += pool->quantum - len % pool->quantum;
|
||||
|
||||
if (len > pool->size)
|
||||
goto bomb;
|
||||
|
||||
if (!pool->live || len > pool->live->free)
|
||||
{
|
||||
void *start;
|
||||
size_t free;
|
||||
size_t bound;
|
||||
size_t sqew;
|
||||
size_t asize;
|
||||
|
||||
if (pool->live)
|
||||
{
|
||||
pool->live->next = pool->free;
|
||||
pool->free = pool->live;
|
||||
}
|
||||
|
||||
free = pool->size;
|
||||
bound = 0;
|
||||
|
||||
asize = pool->size;
|
||||
if (pool->flags & POOL_APPEND)
|
||||
asize += sizeof (struct pool_extent);
|
||||
|
||||
if (!(start = (void *) malloc(asize)))
|
||||
goto bomb;
|
||||
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(start, 0, pool->size);
|
||||
|
||||
if (pool->flags & POOL_APPEND)
|
||||
{
|
||||
pool->live = PTR_ADD(start, free);
|
||||
}
|
||||
else if (!(pool->live = (struct pool_extent *) malloc(sizeof (struct pool_extent))))
|
||||
{
|
||||
goto bomb;
|
||||
}
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (sqew = (size_t)PTR_ADD(start, free) % pool->quantum))
|
||||
{
|
||||
bound += sqew;
|
||||
free -= sqew;
|
||||
}
|
||||
pool->live->start = start;
|
||||
pool->live->free = free;
|
||||
pool->live->bound = bound;
|
||||
pool->live->next = NULL;
|
||||
|
||||
pool->e_created++;
|
||||
}
|
||||
|
||||
pool->n_allocated++;
|
||||
pool->b_allocated += len;
|
||||
|
||||
pool->live->free -= len;
|
||||
|
||||
return PTR_ADD(pool->live->start, pool->live->free);
|
||||
|
||||
bomb:
|
||||
if (pool->bomb)
|
||||
(*pool->bomb)(bomb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur;
|
||||
struct pool_extent *prev;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
if (!len)
|
||||
len = pool->quantum;
|
||||
else if (pool->quantum > 1 && len % pool->quantum)
|
||||
len += pool->quantum - len % pool->quantum;
|
||||
|
||||
if (!addr && pool->live)
|
||||
{
|
||||
pool->live->next = pool->free;
|
||||
pool->free = pool->live;
|
||||
pool->live = NULL;
|
||||
return;
|
||||
}
|
||||
pool->n_freed++;
|
||||
pool->b_freed += len;
|
||||
|
||||
cur = pool->live;
|
||||
if (cur
|
||||
&& addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
{
|
||||
if (addr == PTR_ADD(cur->start, cur->free))
|
||||
{
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, len);
|
||||
pool->b_freed += len;
|
||||
} else {
|
||||
cur->bound += len;
|
||||
}
|
||||
if (cur->free + cur->bound >= pool->size)
|
||||
{
|
||||
size_t sqew;
|
||||
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum))
|
||||
{
|
||||
cur->bound += sqew;
|
||||
cur->free -= sqew;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next)
|
||||
{
|
||||
if (addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
break;
|
||||
}
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
if (prev)
|
||||
{
|
||||
prev->next = cur->next;
|
||||
cur->next = pool->free;
|
||||
pool->free = cur;
|
||||
}
|
||||
cur->bound += len;
|
||||
|
||||
if (cur->free + cur->bound >= pool->size)
|
||||
{
|
||||
pool->free = cur->next;
|
||||
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
pool->e_freed++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#define FDPRINT(label, value) \
|
||||
snprintf(buf, BUFSIZ, label, value), \
|
||||
write(fd, buf, strlen(buf));
|
||||
|
||||
#define FDEXTSTAT(ext) \
|
||||
snprintf(buf, BUFSIZ, " %12ld %5ld\n", \
|
||||
(long) ext->free, \
|
||||
(long) ext->bound), \
|
||||
write(fd, buf, strlen(buf))
|
||||
|
||||
void
|
||||
pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
FDPRINT(" Extent size: %12ld\n", (long) pool->size);
|
||||
FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
|
||||
FDPRINT(" Extents created: %12ld\n", pool->e_created);
|
||||
FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
|
||||
FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
|
||||
FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
|
||||
FDPRINT(" Alloc bytes: %12.0f\n", (double) pool->b_allocated);
|
||||
FDPRINT(" Free bytes: %12.0f\n", (double) pool->b_freed);
|
||||
|
||||
if (summarize)
|
||||
return;
|
||||
|
||||
if (!pool->live && !pool->free)
|
||||
return;
|
||||
|
||||
write(fd, "\n", 1);
|
||||
|
||||
if (pool->live)
|
||||
{
|
||||
FDEXTSTAT(pool->live);
|
||||
}
|
||||
strcpy(buf, " FREE BOUND\n");
|
||||
write(fd, buf, strlen(buf));
|
||||
|
||||
for (cur = pool->free; cur; cur = cur->next)
|
||||
{
|
||||
FDEXTSTAT(cur);
|
||||
}
|
||||
}
|
||||
20
lib/pool_alloc.h
Normal file
20
lib/pool_alloc.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#define POOL_CLEAR (1<<0) /* zero fill allocations */
|
||||
#define POOL_QALIGN (1<<1) /* align data to quanta */
|
||||
#define POOL_INTERN (1<<2) /* Allocate extent structures */
|
||||
#define POOL_APPEND (1<<3) /* or appended to extent data */
|
||||
|
||||
typedef void *alloc_pool_t;
|
||||
|
||||
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(char *), int flags);
|
||||
void pool_destroy(alloc_pool_t pool);
|
||||
void *pool_alloc(alloc_pool_t pool, size_t size, char *bomb);
|
||||
void pool_free(alloc_pool_t pool, size_t size, void *addr);
|
||||
|
||||
#define pool_talloc(pool, type, count, bomb) \
|
||||
((type *)pool_alloc(pool, sizeof(type) * count, bomb))
|
||||
|
||||
#define pool_tfree(pool, type, count, addr) \
|
||||
(pool_free(pool, sizeof(type) * count, addr))
|
||||
|
||||
15
loadparm.c
15
loadparm.c
@@ -101,14 +101,14 @@ typedef struct
|
||||
char *motd_file;
|
||||
char *log_file;
|
||||
char *pid_file;
|
||||
int syslog_facility;
|
||||
char *socket_options;
|
||||
int syslog_facility;
|
||||
int max_verbosity;
|
||||
} global;
|
||||
|
||||
static global Globals;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This structure describes a single service.
|
||||
*/
|
||||
@@ -119,6 +119,7 @@ typedef struct
|
||||
char *comment;
|
||||
char *lock_file;
|
||||
BOOL read_only;
|
||||
BOOL write_only;
|
||||
BOOL list;
|
||||
BOOL use_chroot;
|
||||
BOOL transfer_logging;
|
||||
@@ -151,6 +152,7 @@ static service sDefault =
|
||||
NULL, /* comment */
|
||||
DEFAULT_LOCK_FILE, /* lock file */
|
||||
True, /* read only */
|
||||
False, /* write only */
|
||||
True, /* list */
|
||||
True, /* use chroot */
|
||||
False, /* transfer logging */
|
||||
@@ -268,6 +270,7 @@ static struct parm_struct parm_table[] =
|
||||
{"socket options", P_STRING, P_GLOBAL, &Globals.socket_options,NULL, 0},
|
||||
{"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0},
|
||||
{"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0},
|
||||
{"max verbosity", P_INTEGER, P_GLOBAL, &Globals.max_verbosity, NULL, 0},
|
||||
|
||||
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
|
||||
{"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0},
|
||||
@@ -276,6 +279,7 @@ static struct parm_struct parm_table[] =
|
||||
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
|
||||
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL, 0},
|
||||
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
|
||||
{"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL, 0},
|
||||
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
|
||||
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
|
||||
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable, NULL, 0},
|
||||
@@ -304,10 +308,11 @@ Initialise the global parameter structure.
|
||||
***************************************************************************/
|
||||
static void init_globals(void)
|
||||
{
|
||||
memset(&Globals, 0, sizeof(Globals));
|
||||
memset(&Globals, 0, sizeof Globals);
|
||||
#ifdef LOG_DAEMON
|
||||
Globals.syslog_facility = LOG_DAEMON;
|
||||
#endif
|
||||
Globals.max_verbosity = 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
@@ -347,12 +352,14 @@ FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
|
||||
FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
|
||||
FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
|
||||
FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
|
||||
FN_GLOBAL_INTEGER(lp_max_verbosity, &Globals.max_verbosity)
|
||||
|
||||
FN_LOCAL_STRING(lp_name, name)
|
||||
FN_LOCAL_STRING(lp_comment, comment)
|
||||
FN_LOCAL_STRING(lp_path, path)
|
||||
FN_LOCAL_STRING(lp_lock_file, lock_file)
|
||||
FN_LOCAL_BOOL(lp_read_only, read_only)
|
||||
FN_LOCAL_BOOL(lp_write_only, write_only)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
|
||||
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
|
||||
@@ -804,7 +811,7 @@ int lp_number(char *name)
|
||||
int iService;
|
||||
|
||||
for (iService = iNumServices - 1; iService >= 0; iService--)
|
||||
if (strequal(lp_name(iService), name))
|
||||
if (strcmp(lp_name(iService), name) == 0)
|
||||
break;
|
||||
|
||||
return (iService);
|
||||
|
||||
242
log.c
242
log.c
@@ -27,13 +27,21 @@
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int quiet;
|
||||
extern int module_id;
|
||||
extern int msg_fd_out;
|
||||
extern char *auth_user;
|
||||
extern char *log_format;
|
||||
|
||||
static int log_initialised;
|
||||
static char *logfname;
|
||||
static FILE *logfile;
|
||||
static int log_error_fd = -1;
|
||||
struct stats stats;
|
||||
|
||||
int log_got_error=0;
|
||||
int log_got_error = 0;
|
||||
|
||||
struct {
|
||||
int code;
|
||||
@@ -53,7 +61,7 @@ struct {
|
||||
{ RERR_WAITCHILD , "some error returned by waitpid()" },
|
||||
{ RERR_MALLOC , "error allocating core memory buffers" },
|
||||
{ RERR_PARTIAL , "some files could not be transferred" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transfered" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transferred" },
|
||||
{ RERR_TIMEOUT , "timeout in data send/receive" },
|
||||
{ RERR_CMD_FAILED , "remote shell failed" },
|
||||
{ RERR_CMD_KILLED , "remote shell killed" },
|
||||
@@ -77,61 +85,6 @@ static char const *rerr_name(int code)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct err_list {
|
||||
struct err_list *next;
|
||||
char *buf;
|
||||
int len;
|
||||
int written; /* how many bytes we have written so far */
|
||||
};
|
||||
|
||||
static struct err_list *err_list_head;
|
||||
static struct err_list *err_list_tail;
|
||||
|
||||
/* add an error message to the pending error list */
|
||||
static void err_list_add(int code, char *buf, int len)
|
||||
{
|
||||
struct err_list *el;
|
||||
el = new(struct err_list);
|
||||
if (!el) exit_cleanup(RERR_MALLOC);
|
||||
el->next = NULL;
|
||||
el->buf = new_array(char, len+4);
|
||||
if (!el->buf) exit_cleanup(RERR_MALLOC);
|
||||
memcpy(el->buf+4, buf, len);
|
||||
SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len);
|
||||
el->len = len+4;
|
||||
el->written = 0;
|
||||
if (err_list_tail) {
|
||||
err_list_tail->next = el;
|
||||
} else {
|
||||
err_list_head = el;
|
||||
}
|
||||
err_list_tail = el;
|
||||
}
|
||||
|
||||
|
||||
/* try to push errors off the error list onto the wire */
|
||||
void err_list_push(void)
|
||||
{
|
||||
if (log_error_fd == -1) return;
|
||||
|
||||
while (err_list_head) {
|
||||
struct err_list *el = err_list_head;
|
||||
int n = write(log_error_fd, el->buf+el->written, el->len - el->written);
|
||||
/* don't check for an error if the best way of handling the error is
|
||||
* to ignore it */
|
||||
if (n == -1) break;
|
||||
if (n > 0) {
|
||||
el->written += n;
|
||||
}
|
||||
if (el->written == el->len) {
|
||||
free(el->buf);
|
||||
err_list_head = el->next;
|
||||
if (!err_list_head) err_list_tail = NULL;
|
||||
free(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void logit(int priority, char *buf)
|
||||
{
|
||||
@@ -151,7 +104,8 @@ void log_init(void)
|
||||
int options = LOG_PID;
|
||||
time_t t;
|
||||
|
||||
if (log_initialised) return;
|
||||
if (log_initialised)
|
||||
return;
|
||||
log_initialised = 1;
|
||||
|
||||
/* this looks pointless, but it is needed in order for the
|
||||
@@ -203,71 +157,54 @@ void log_close(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* setup the error file descriptor - used when we are a server
|
||||
* that is receiving files */
|
||||
void set_error_fd(int fd)
|
||||
{
|
||||
log_error_fd = fd;
|
||||
set_nonblocking(log_error_fd);
|
||||
}
|
||||
|
||||
/* this is the underlying (unformatted) rsync debugging function. Call
|
||||
* it with FINFO, FERROR or FLOG */
|
||||
void rwrite(enum logcode code, char *buf, int len)
|
||||
{
|
||||
FILE *f=NULL;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
extern int quiet;
|
||||
FILE *f = NULL;
|
||||
/* recursion can happen with certain fatal conditions */
|
||||
|
||||
if (quiet && code == FINFO) return;
|
||||
if (quiet && code == FINFO)
|
||||
return;
|
||||
|
||||
if (len < 0) exit_cleanup(RERR_MESSAGEIO);
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
buf[len] = 0;
|
||||
|
||||
if (code == FLOG) {
|
||||
if (am_daemon) logit(LOG_INFO, buf);
|
||||
if (am_server && msg_fd_out >= 0) {
|
||||
/* Pass the message to our sibling. */
|
||||
send_msg((enum msgcode)code, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first try to pass it off to our sibling */
|
||||
if (am_server && log_error_fd != -1) {
|
||||
err_list_add(code, buf, len);
|
||||
err_list_push();
|
||||
if (am_daemon) {
|
||||
static int in_block;
|
||||
char msg[2048];
|
||||
int priority = code == FERROR ? LOG_WARNING : LOG_INFO;
|
||||
|
||||
if (in_block)
|
||||
return;
|
||||
in_block = 1;
|
||||
if (!log_initialised)
|
||||
log_init();
|
||||
strlcpy(msg, buf, MIN((int)sizeof msg, len + 1));
|
||||
logit(priority, msg);
|
||||
in_block = 0;
|
||||
|
||||
if (code == FLOG || !am_server)
|
||||
return;
|
||||
} else if (code == FLOG)
|
||||
return;
|
||||
}
|
||||
|
||||
/* next, if we are a server and multiplexing is enabled,
|
||||
* pass it to the other side. */
|
||||
if (am_server && io_multiplex_write(code, buf, len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise, if in daemon mode and either we are not a server
|
||||
* (that is, we are not running --daemon over a remote shell) or
|
||||
* the log has already been initialised, log the message on this
|
||||
* side because we don't want the client to see most errors for
|
||||
* security reasons. We do want early messages when running daemon
|
||||
* mode over a remote shell to go to the remote side; those will
|
||||
* fall through to the next case.
|
||||
* Note that this is only for the time before multiplexing is enabled.
|
||||
*/
|
||||
if (am_daemon && (!am_server || log_initialised)) {
|
||||
static int depth;
|
||||
int priority = LOG_INFO;
|
||||
if (code == FERROR) priority = LOG_WARNING;
|
||||
|
||||
if (depth) return;
|
||||
|
||||
depth++;
|
||||
|
||||
log_init();
|
||||
logit(priority, buf);
|
||||
|
||||
depth--;
|
||||
return;
|
||||
if (am_server) {
|
||||
/* Pass the message to the non-server side. */
|
||||
if (io_multiplex_write((enum msgcode)code, buf, len))
|
||||
return;
|
||||
if (am_daemon) {
|
||||
/* TODO: can we send the error to the user somehow? */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (code == FERROR) {
|
||||
@@ -275,18 +212,17 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
if (code == FINFO) {
|
||||
if (am_server)
|
||||
f = stderr;
|
||||
else
|
||||
f = stdout;
|
||||
}
|
||||
if (code == FINFO)
|
||||
f = am_server ? stderr : stdout;
|
||||
|
||||
if (!f) exit_cleanup(RERR_MESSAGEIO);
|
||||
if (!f)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
|
||||
if (fwrite(buf, len, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n')
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -295,18 +231,17 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
void rprintf(enum logcode code, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int len;
|
||||
char buf[MAXPATHLEN+512];
|
||||
size_t len;
|
||||
|
||||
va_start(ap, format);
|
||||
/* Note: might return -1 */
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Deal with buffer overruns. Instead of panicking, just
|
||||
* truncate the resulting string. Note that some vsnprintf()s
|
||||
* return -1 on truncation, e.g., glibc 2.0.6 and earlier. */
|
||||
if ((size_t) len > sizeof(buf)-1 || len < 0) {
|
||||
* truncate the resulting string. (Note that configure ensures
|
||||
* that we have a vsnprintf() that doesn't ever return -1.) */
|
||||
if (len > sizeof buf - 1) {
|
||||
const char ellipsis[] = "[...]";
|
||||
|
||||
/* Reset length, and zero-terminate the end of our buffer */
|
||||
@@ -344,33 +279,23 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int len;
|
||||
size_t sys_len;
|
||||
char *sysmsg;
|
||||
char buf[MAXPATHLEN+512];
|
||||
size_t len;
|
||||
|
||||
strcpy(buf, RSYNC_NAME ": ");
|
||||
len = (sizeof RSYNC_NAME ": ") - 1;
|
||||
|
||||
va_start(ap, format);
|
||||
/* Note: might return <0 */
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* TODO: Put in RSYNC_NAME at the start. */
|
||||
|
||||
if ((size_t) len > sizeof(buf)-1)
|
||||
if (len < sizeof buf) {
|
||||
len += snprintf(buf + len, sizeof buf - len,
|
||||
": %s (%d)\n", strerror(errcode), errcode);
|
||||
}
|
||||
if (len >= sizeof buf)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
sysmsg = strerror(errcode);
|
||||
sys_len = strlen(sysmsg);
|
||||
if ((size_t) len + 3 + sys_len > sizeof(buf) - 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
strcpy(buf + len, ": ");
|
||||
len += 2;
|
||||
strcpy(buf + len, sysmsg);
|
||||
len += sys_len;
|
||||
strcpy(buf + len, "\n");
|
||||
len++;
|
||||
|
||||
rwrite(code, buf, len);
|
||||
}
|
||||
|
||||
@@ -379,7 +304,6 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
void rflush(enum logcode code)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
extern int am_daemon;
|
||||
|
||||
if (am_daemon) {
|
||||
return;
|
||||
@@ -394,7 +318,6 @@ void rflush(enum logcode code)
|
||||
}
|
||||
|
||||
if (code == FINFO) {
|
||||
extern int am_server;
|
||||
if (am_server)
|
||||
f = stderr;
|
||||
else
|
||||
@@ -413,15 +336,10 @@ static void log_formatted(enum logcode code,
|
||||
char *format, char *op, struct file_struct *file,
|
||||
struct stats *initial_stats)
|
||||
{
|
||||
extern int module_id;
|
||||
extern char *auth_user;
|
||||
char buf[1024];
|
||||
char buf2[1024];
|
||||
char *p, *s, *n;
|
||||
size_t l;
|
||||
extern struct stats stats;
|
||||
extern int am_sender;
|
||||
extern int am_daemon;
|
||||
int64 b;
|
||||
|
||||
/* We expand % codes one by one in place in buf. We don't
|
||||
@@ -429,8 +347,9 @@ static void log_formatted(enum logcode code,
|
||||
* rather keep going until we reach the nul of the format.
|
||||
* Just to make sure we don't clobber that nul and therefore
|
||||
* accidentally keep going, we zero the buffer now. */
|
||||
memset(buf, 0, sizeof buf);
|
||||
strlcpy(buf, format, sizeof(buf));
|
||||
l = strlcpy(buf, format, sizeof buf);
|
||||
if (l < sizeof buf)
|
||||
memset(buf + l, 0, sizeof buf - l);
|
||||
|
||||
for (s = &buf[0]; s && (p = strchr(s,'%')); ) {
|
||||
n = NULL;
|
||||
@@ -451,10 +370,10 @@ static void log_formatted(enum logcode code,
|
||||
break;
|
||||
case 'o': n = op; break;
|
||||
case 'f':
|
||||
snprintf(buf2, sizeof(buf2), "%s/%s",
|
||||
file->basedir?file->basedir:"",
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
file->basedir ? file->basedir : "",
|
||||
f_name(file));
|
||||
clean_fname(buf2);
|
||||
clean_fname(buf2, 0);
|
||||
n = buf2;
|
||||
if (*n == '/') n++;
|
||||
break;
|
||||
@@ -519,10 +438,6 @@ static void log_formatted(enum logcode code,
|
||||
/* log the outgoing transfer of a file */
|
||||
void log_send(struct file_struct *file, struct stats *initial_stats)
|
||||
{
|
||||
extern int module_id;
|
||||
extern int am_server;
|
||||
extern char *log_format;
|
||||
|
||||
if (lp_transfer_logging(module_id)) {
|
||||
log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats);
|
||||
} else if (log_format && !am_server) {
|
||||
@@ -533,10 +448,6 @@ void log_send(struct file_struct *file, struct stats *initial_stats)
|
||||
/* log the incoming transfer of a file */
|
||||
void log_recv(struct file_struct *file, struct stats *initial_stats)
|
||||
{
|
||||
extern int module_id;
|
||||
extern int am_server;
|
||||
extern char *log_format;
|
||||
|
||||
if (lp_transfer_logging(module_id)) {
|
||||
log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats);
|
||||
} else if (log_format && !am_server) {
|
||||
@@ -556,7 +467,6 @@ void log_recv(struct file_struct *file, struct stats *initial_stats)
|
||||
void log_exit(int code, const char *file, int line)
|
||||
{
|
||||
if (code == 0) {
|
||||
extern struct stats stats;
|
||||
rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
|
||||
(double)stats.total_written,
|
||||
(double)stats.total_read,
|
||||
|
||||
530
main.c
530
main.c
@@ -24,14 +24,45 @@
|
||||
time_t starttime = 0;
|
||||
|
||||
extern struct stats stats;
|
||||
extern char *files_from;
|
||||
extern int filesfrom_fd;
|
||||
extern char *remote_filesfrom_file;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int am_daemon;
|
||||
extern int verbose;
|
||||
extern int blocking_io;
|
||||
extern int cvs_exclude;
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
extern int delete_after;
|
||||
extern int daemon_over_rsh;
|
||||
extern int do_stats;
|
||||
extern int dry_run;
|
||||
extern int list_only;
|
||||
extern int local_server;
|
||||
extern int log_got_error;
|
||||
extern int module_id;
|
||||
extern int orig_umask;
|
||||
extern int copy_links;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int protocol_version;
|
||||
extern int recurse;
|
||||
extern int relative_paths;
|
||||
extern int rsync_port;
|
||||
extern int whole_file;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int batch_fd;
|
||||
extern int batch_gen_fd;
|
||||
extern int filesfrom_fd;
|
||||
extern pid_t cleanup_child_pid;
|
||||
extern char *files_from;
|
||||
extern char *remote_filesfrom_file;
|
||||
extern char *rsync_path;
|
||||
extern char *shell_cmd;
|
||||
extern char *batch_name;
|
||||
|
||||
|
||||
/* there's probably never more than at most 2 outstanding child processes,
|
||||
* but set it higher just in case.
|
||||
@@ -55,10 +86,10 @@ void wait_process(pid_t pid, int *status)
|
||||
|
||||
while ((waited_pid = waitpid(pid, status, WNOHANG)) == 0) {
|
||||
msleep(20);
|
||||
io_flush();
|
||||
io_flush(FULL_FLUSH);
|
||||
}
|
||||
|
||||
if ((waited_pid == -1) && (errno == ECHILD)) {
|
||||
if (waited_pid == -1 && errno == ECHILD) {
|
||||
/* status of requested child no longer available.
|
||||
* check to see if it was processed by the sigchld_handler.
|
||||
*/
|
||||
@@ -79,11 +110,20 @@ void wait_process(pid_t pid, int *status)
|
||||
*status = WEXITSTATUS(*status);
|
||||
}
|
||||
|
||||
/* This function gets called from all 3 processes. We want the client side
|
||||
* to actually output the text, but the sender is the only process that has
|
||||
* all the stats we need. So, if we're a client sender, we do the report.
|
||||
* If we're a server sender, we write the stats on the supplied fd. If
|
||||
* we're the client receiver we read the stats from the supplied fd and do
|
||||
* the report. All processes might also generate a set of debug stats, if
|
||||
* the verbose level is high enough (this is the only thing that the
|
||||
* generator process and the server receiver ever do here). */
|
||||
static void report(int f)
|
||||
{
|
||||
/* Cache two stats because the read/write code can change it. */
|
||||
int64 total_read = stats.total_read;
|
||||
int64 total_written = stats.total_written;
|
||||
time_t t = time(NULL);
|
||||
extern int do_stats;
|
||||
int send_stats;
|
||||
|
||||
if (do_stats && verbose > 1) {
|
||||
/* These come out from every process */
|
||||
@@ -91,43 +131,41 @@ static void report(int f)
|
||||
show_flist_stats();
|
||||
}
|
||||
|
||||
if (am_generator)
|
||||
return;
|
||||
|
||||
if (am_daemon) {
|
||||
log_exit(0, __FILE__, __LINE__);
|
||||
if (f == -1 || !am_sender) return;
|
||||
if (f == -1 || !am_sender)
|
||||
return;
|
||||
}
|
||||
|
||||
send_stats = verbose || protocol_version >= 20;
|
||||
if (am_server) {
|
||||
if (am_sender && send_stats) {
|
||||
int64 w;
|
||||
/* store total_written in a temporary
|
||||
* because write_longint changes it */
|
||||
w = stats.total_written;
|
||||
write_longint(f,stats.total_read);
|
||||
write_longint(f,w);
|
||||
write_longint(f,stats.total_size);
|
||||
if (am_sender) {
|
||||
write_longint(f, total_read);
|
||||
write_longint(f, total_written);
|
||||
write_longint(f, stats.total_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* this is the client */
|
||||
|
||||
if (!am_sender && send_stats) {
|
||||
int64 r;
|
||||
stats.total_written = read_longint(f);
|
||||
/* store total_read in a temporary, read_longint changes it */
|
||||
r = read_longint(f);
|
||||
if (!am_sender) {
|
||||
/* Read the first two in opposite order because the meaning of
|
||||
* read/write swaps when switching from sender to receiver. */
|
||||
total_written = read_longint(f);
|
||||
total_read = read_longint(f);
|
||||
stats.total_size = read_longint(f);
|
||||
stats.total_read = r;
|
||||
} else if (write_batch) {
|
||||
/* The --read-batch process is going to be a client
|
||||
* receiver, so we need to give it the stats. */
|
||||
write_longint(batch_fd, total_read);
|
||||
write_longint(batch_fd, total_written);
|
||||
write_longint(batch_fd, stats.total_size);
|
||||
}
|
||||
|
||||
if (do_stats) {
|
||||
if (!am_sender && !send_stats) {
|
||||
/* missing the bytes written by the generator */
|
||||
rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
|
||||
rprintf(FINFO, "Use --stats -v to show stats\n");
|
||||
return;
|
||||
}
|
||||
rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
|
||||
rprintf(FINFO,"Number of files transferred: %d\n",
|
||||
stats.num_transferred_files);
|
||||
@@ -140,20 +178,20 @@ static void report(int f)
|
||||
rprintf(FINFO,"Matched data: %.0f bytes\n",
|
||||
(double)stats.matched_data);
|
||||
rprintf(FINFO,"File list size: %d\n", stats.flist_size);
|
||||
rprintf(FINFO,"Total bytes written: %.0f\n",
|
||||
(double)stats.total_written);
|
||||
rprintf(FINFO,"Total bytes read: %.0f\n",
|
||||
(double)stats.total_read);
|
||||
rprintf(FINFO,"Total bytes sent: %.0f\n",
|
||||
(double)total_written);
|
||||
rprintf(FINFO,"Total bytes received: %.0f\n",
|
||||
(double)total_read);
|
||||
}
|
||||
|
||||
if (verbose || do_stats) {
|
||||
rprintf(FINFO,"\nwrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
|
||||
(double)stats.total_written,
|
||||
(double)stats.total_read,
|
||||
(stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
|
||||
rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
|
||||
rprintf(FINFO,
|
||||
"\nsent %.0f bytes received %.0f bytes %.2f bytes/sec\n",
|
||||
(double)total_written, (double)total_read,
|
||||
(total_written + total_read)/(0.5 + (t - starttime)));
|
||||
rprintf(FINFO, "total size is %.0f speedup is %.2f\n",
|
||||
(double)stats.total_size,
|
||||
(1.0*stats.total_size)/(stats.total_written+stats.total_read));
|
||||
(double)stats.total_size / (total_written+total_read));
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
@@ -171,16 +209,18 @@ static void show_malloc_stats(void)
|
||||
|
||||
mi = mallinfo();
|
||||
|
||||
rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
|
||||
rprintf(FINFO, "\n" RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
|
||||
getpid(),
|
||||
am_server ? "server " : "",
|
||||
am_daemon ? "daemon " : "",
|
||||
am_sender ? "sender" : "receiver");
|
||||
who_am_i());
|
||||
rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
|
||||
rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
|
||||
rprintf(FINFO, " smblks: %10d\n", mi.smblks);
|
||||
rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
|
||||
rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
|
||||
rprintf(FINFO, " allmem: %10d (bytes from sbrk + mmap)\n",
|
||||
mi.arena + mi.hblkhd);
|
||||
rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
|
||||
rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
|
||||
rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
|
||||
@@ -191,18 +231,14 @@ static void show_malloc_stats(void)
|
||||
|
||||
|
||||
/* Start the remote shell. cmd may be NULL to use the default. */
|
||||
static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
|
||||
static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
int *f_in, int *f_out)
|
||||
{
|
||||
char *args[100];
|
||||
int i,argc=0;
|
||||
int i, argc = 0;
|
||||
char *args[MAX_ARGS];
|
||||
pid_t ret;
|
||||
char *tok,*dir=NULL;
|
||||
char *tok, *dir = NULL;
|
||||
int dash_l_set = 0;
|
||||
extern int local_server;
|
||||
extern char *rsync_path;
|
||||
extern int blocking_io;
|
||||
extern int daemon_over_rsh;
|
||||
extern int read_batch;
|
||||
|
||||
if (!read_batch && !local_server) {
|
||||
char *rsh_env = getenv(RSYNC_RSH_ENV);
|
||||
@@ -214,7 +250,12 @@ static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int
|
||||
if (!cmd)
|
||||
goto oom;
|
||||
|
||||
for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
|
||||
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " ")) {
|
||||
/* Comparison leaves rooms for server_options(). */
|
||||
if (argc >= MAX_ARGS - 100) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
args[argc++] = tok;
|
||||
}
|
||||
|
||||
@@ -253,6 +294,11 @@ static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int
|
||||
}
|
||||
|
||||
server_options(args,&argc);
|
||||
|
||||
if (argc >= MAX_ARGS - 2) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
args[argc++] = ".";
|
||||
@@ -264,20 +310,32 @@ static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"cmd=");
|
||||
for (i=0;i<argc;i++)
|
||||
for (i = 0; i < argc; i++)
|
||||
rprintf(FINFO,"%s ",args[i]);
|
||||
rprintf(FINFO,"\n");
|
||||
}
|
||||
|
||||
if (local_server) {
|
||||
if (read_batch)
|
||||
create_flist_from_batch(); /* sets batch_flist */
|
||||
if (read_batch) {
|
||||
int from_gen_pipe[2];
|
||||
if (fd_pair(from_gen_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
batch_gen_fd = from_gen_pipe[0];
|
||||
*f_out = from_gen_pipe[1];
|
||||
*f_in = batch_fd;
|
||||
ret = -1; /* no child pid */
|
||||
} else if (local_server) {
|
||||
/* If the user didn't request --[no-]whole-file, force
|
||||
* it on, but only if we're not batch processing. */
|
||||
if (whole_file < 0 && !write_batch)
|
||||
whole_file = 1;
|
||||
ret = local_child(argc, args, f_in, f_out, child_main);
|
||||
} else {
|
||||
} else
|
||||
ret = piped_child(args,f_in,f_out);
|
||||
}
|
||||
|
||||
if (dir) free(dir);
|
||||
if (dir)
|
||||
free(dir);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -287,13 +345,10 @@ oom:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static char *get_local_name(struct file_list *flist,char *name)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
int e;
|
||||
extern int orig_umask;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"get_local_name count=%d %s\n",
|
||||
@@ -304,9 +359,9 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
|
||||
if (do_stat(name,&st) == 0) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (!push_dir(name, 0)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (1)\n",
|
||||
full_fname(name), strerror(errno));
|
||||
if (!push_dir(name)) {
|
||||
rsyserr(FERROR, errno, "push_dir#1 %s failed",
|
||||
full_fname(name));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
return NULL;
|
||||
@@ -322,17 +377,20 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
return name;
|
||||
|
||||
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
|
||||
rprintf(FERROR, "mkdir %s failed: %s\n",
|
||||
full_fname(name), strerror(errno));
|
||||
rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
} else {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"created directory %s\n",name);
|
||||
}
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "created directory %s\n", name);
|
||||
|
||||
if (dry_run) {
|
||||
dry_run++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!push_dir(name, 0)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (2)\n",
|
||||
full_fname(name), strerror(errno));
|
||||
if (!push_dir(name)) {
|
||||
rsyserr(FERROR, errno, "push_dir#2 %s failed",
|
||||
full_fname(name));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
@@ -340,22 +398,26 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
struct file_list *flist;
|
||||
char *dir = argv[0];
|
||||
extern int relative_paths;
|
||||
extern int recurse;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "server_sender starting pid=%ld\n",
|
||||
(long)getpid());
|
||||
}
|
||||
|
||||
if (!relative_paths && !push_dir(dir, 0)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (3)\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
if (am_daemon && lp_write_only(module_id)) {
|
||||
rprintf(FERROR, "ERROR: module is write only\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!relative_paths && !push_dir(dir)) {
|
||||
rsyserr(FERROR, errno, "push_dir#3 %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
argc--;
|
||||
@@ -365,12 +427,12 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
int l = strlen(dir);
|
||||
if (strcmp(dir,"/") == 0)
|
||||
l = 0;
|
||||
for (i=0;i<argc;i++)
|
||||
for (i = 0; i < argc; i++)
|
||||
argv[i] += l+1;
|
||||
}
|
||||
|
||||
if (argc == 0 && recurse) {
|
||||
argc=1;
|
||||
argc = 1;
|
||||
argv--;
|
||||
argv[0] = ".";
|
||||
}
|
||||
@@ -380,14 +442,17 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
io_start_buffering_in();
|
||||
io_start_buffering_out();
|
||||
|
||||
send_files(flist,f_out,f_in);
|
||||
io_flush();
|
||||
io_flush(FULL_FLUSH);
|
||||
report(f_out);
|
||||
if (protocol_version >= 24) {
|
||||
/* final goodbye message */
|
||||
read_int(f_in);
|
||||
}
|
||||
io_flush();
|
||||
read_int(f_in);
|
||||
}
|
||||
io_flush(FULL_FLUSH);
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
@@ -395,27 +460,20 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
{
|
||||
int pid;
|
||||
int status=0;
|
||||
int recv_pipe[2];
|
||||
int status = 0;
|
||||
int error_pipe[2];
|
||||
extern int preserve_hard_links;
|
||||
extern int delete_after;
|
||||
extern int recurse;
|
||||
extern int delete_mode;
|
||||
|
||||
/* The receiving side mustn't obey this, or an existing symlink that
|
||||
* points to an identical file won't be replaced by the referent. */
|
||||
copy_links = 0;
|
||||
|
||||
if (preserve_hard_links)
|
||||
init_hard_links(flist);
|
||||
|
||||
if (!delete_after) {
|
||||
/* I moved this here from recv_files() to prevent a race condition */
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
if (recurse && delete_mode && !local_name && flist->count > 0)
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_pair(recv_pipe) < 0) {
|
||||
rprintf(FERROR,"pipe failed in do_recv\n");
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
if (fd_pair(error_pipe) < 0) {
|
||||
@@ -423,52 +481,57 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
io_flush();
|
||||
io_flush(NORMAL_FLUSH);
|
||||
|
||||
if ((pid=do_fork()) == 0) {
|
||||
close(recv_pipe[0]);
|
||||
if ((pid = do_fork()) == 0) {
|
||||
close(error_pipe[0]);
|
||||
if (f_in != f_out) close(f_out);
|
||||
if (f_in != f_out)
|
||||
close(f_out);
|
||||
|
||||
/* we can't let two processes write to the socket at one time */
|
||||
io_multiplexing_close();
|
||||
close_multiplexing_out();
|
||||
|
||||
/* set place to send errors */
|
||||
set_error_fd(error_pipe[1]);
|
||||
set_msg_fd_out(error_pipe[1]);
|
||||
|
||||
recv_files(f_in,flist,local_name,recv_pipe[1]);
|
||||
io_flush();
|
||||
recv_files(f_in,flist,local_name);
|
||||
io_flush(FULL_FLUSH);
|
||||
report(f_in);
|
||||
|
||||
write_int(recv_pipe[1],1);
|
||||
close(recv_pipe[1]);
|
||||
io_flush();
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
io_flush(FULL_FLUSH);
|
||||
/* finally we go to sleep until our parent kills us
|
||||
* with a USR2 signal. We sleep for a short time as on
|
||||
* some OSes a signal won't interrupt a sleep! */
|
||||
while (msleep(20))
|
||||
;
|
||||
while (1)
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
close(recv_pipe[1]);
|
||||
am_generator = 1;
|
||||
close_multiplexing_in();
|
||||
if (write_batch)
|
||||
stop_write_batch();
|
||||
|
||||
close(error_pipe[1]);
|
||||
if (f_in != f_out) close(f_in);
|
||||
if (f_in != f_out)
|
||||
close(f_in);
|
||||
|
||||
io_start_buffering(f_out);
|
||||
io_start_buffering_out();
|
||||
|
||||
io_set_error_fd(error_pipe[0]);
|
||||
set_msg_fd_in(error_pipe[0]);
|
||||
|
||||
generate_files(f_out,flist,local_name,recv_pipe[0]);
|
||||
generate_files(f_out, flist, local_name);
|
||||
|
||||
read_int(recv_pipe[0]);
|
||||
close(recv_pipe[0]);
|
||||
get_redo_num(); /* Read final MSG_DONE and any prior messages. */
|
||||
report(-1);
|
||||
io_flush(FULL_FLUSH);
|
||||
if (protocol_version >= 24) {
|
||||
/* send a final goodbye message */
|
||||
write_int(f_out, -1);
|
||||
}
|
||||
io_flush();
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
io_set_error_fd(-1);
|
||||
set_msg_fd_in(-1);
|
||||
kill(pid, SIGUSR2);
|
||||
wait_process(pid, &status);
|
||||
return status;
|
||||
@@ -479,18 +542,15 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
{
|
||||
int status;
|
||||
struct file_list *flist;
|
||||
char *local_name=NULL;
|
||||
char *local_name = NULL;
|
||||
char *dir = NULL;
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
extern int module_id;
|
||||
extern int read_batch;
|
||||
extern struct file_list *batch_flist;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
|
||||
argc, (long)getpid());
|
||||
}
|
||||
|
||||
if (am_daemon && lp_read_only(module_id) && !am_sender) {
|
||||
if (am_daemon && lp_read_only(module_id)) {
|
||||
rprintf(FERROR,"ERROR: module is read only\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
@@ -501,13 +561,14 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
dir = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
if (!am_daemon && !push_dir(dir, 0)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (4)\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
if (!am_daemon && !push_dir(dir)) {
|
||||
rsyserr(FERROR, errno, "push_dir#4 %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
}
|
||||
|
||||
io_start_buffering_in();
|
||||
if (delete_mode && !delete_excluded)
|
||||
recv_exclude_list(f_in);
|
||||
|
||||
@@ -520,10 +581,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
if (read_batch)
|
||||
flist = batch_flist;
|
||||
else
|
||||
flist = recv_file_list(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist) {
|
||||
rprintf(FERROR,"server_recv: recv_file_list error\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
@@ -532,7 +590,8 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
if (argc > 0) {
|
||||
if (strcmp(dir,".")) {
|
||||
argv[0] += strlen(dir);
|
||||
if (argv[0][0] == '/') argv[0]++;
|
||||
if (argv[0][0] == '/')
|
||||
argv[0]++;
|
||||
}
|
||||
local_name = get_local_name(flist,argv[0]);
|
||||
}
|
||||
@@ -551,23 +610,21 @@ int child_main(int argc, char *argv[])
|
||||
|
||||
void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
extern int cvs_exclude;
|
||||
extern int read_batch;
|
||||
|
||||
setup_protocol(f_out, f_in);
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
setup_protocol(f_out, f_in);
|
||||
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_out(f_out);
|
||||
io_start_multiplex_out();
|
||||
|
||||
if (am_sender) {
|
||||
if (!read_batch) {
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
}
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
do_server_sender(f_in, f_out, argc, argv);
|
||||
} else {
|
||||
do_server_recv(f_in, f_out, argc, argv);
|
||||
@@ -585,39 +642,51 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
struct file_list *flist = NULL;
|
||||
int status = 0, status2 = 0;
|
||||
char *local_name = NULL;
|
||||
extern pid_t cleanup_child_pid;
|
||||
extern int write_batch;
|
||||
extern int read_batch;
|
||||
extern struct file_list *batch_flist;
|
||||
|
||||
cleanup_child_pid = pid;
|
||||
if (read_batch)
|
||||
flist = batch_flist;
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
if (read_batch) {
|
||||
assert(am_sender == 0);
|
||||
} else {
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
}
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
setup_protocol(f_out,f_in);
|
||||
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_in(f_in);
|
||||
if (protocol_version >= 23 && !read_batch)
|
||||
io_start_multiplex_in();
|
||||
|
||||
/* We set our stderr file handle to blocking because ssh might have
|
||||
* set it to non-blocking. This can be particularly troublesome if
|
||||
* stderr is a clone of stdout, because ssh would have set our stdout
|
||||
* to non-blocking at the same time (which can easily cause us to lose
|
||||
* output from our print statements). This kluge shouldn't cause ssh
|
||||
* any problems for how we use it. Note also that we delayed setting
|
||||
* this until after the above protocol setup so that we know for sure
|
||||
* that ssh is done twiddling its file descriptors. */
|
||||
set_blocking(STDERR_FILENO);
|
||||
|
||||
if (am_sender) {
|
||||
extern int cvs_exclude;
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
io_start_buffering_out();
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
if (delete_mode && !delete_excluded)
|
||||
send_exclude_list(f_out);
|
||||
if (remote_filesfrom_file)
|
||||
filesfrom_fd = f_in;
|
||||
if (!read_batch) /* dw -- don't write to pipe */
|
||||
|
||||
if (write_batch)
|
||||
start_write_batch(f_out);
|
||||
if (!read_batch) /* don't write to pipe */
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"file list sent\n");
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
send_files(flist,f_out,f_in);
|
||||
io_flush(FULL_FLUSH);
|
||||
if (protocol_version >= 24) {
|
||||
/* final goodbye message */
|
||||
read_int(f_in);
|
||||
@@ -625,19 +694,18 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
|
||||
io_flush();
|
||||
io_flush(FULL_FLUSH);
|
||||
wait_process(pid, &status);
|
||||
}
|
||||
report(-1);
|
||||
io_flush(FULL_FLUSH);
|
||||
exit_cleanup(status);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
extern int list_only;
|
||||
if (argc == 0)
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
if (!write_batch)
|
||||
if (!read_batch)
|
||||
send_exclude_list(f_out);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
@@ -645,6 +713,8 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
if (write_batch)
|
||||
start_write_batch(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist || flist->count == 0) {
|
||||
rprintf(FINFO, "client: nothing to do: "
|
||||
@@ -660,7 +730,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
|
||||
io_flush();
|
||||
io_flush(FULL_FLUSH);
|
||||
wait_process(pid, &status);
|
||||
}
|
||||
|
||||
@@ -700,11 +770,6 @@ static int start_client(int argc, char *argv[])
|
||||
int ret;
|
||||
pid_t pid;
|
||||
int f_in,f_out;
|
||||
extern int local_server;
|
||||
extern char *shell_cmd;
|
||||
extern int rsync_port;
|
||||
extern int daemon_over_rsh;
|
||||
extern int read_batch;
|
||||
int rc;
|
||||
|
||||
/* Don't clobber argv[] so that ps(1) can still show the right
|
||||
@@ -713,33 +778,39 @@ static int start_client(int argc, char *argv[])
|
||||
return rc;
|
||||
|
||||
/* rsync:// always uses rsync server over direct socket connection */
|
||||
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
|
||||
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0
|
||||
&& !read_batch) {
|
||||
char *host, *path;
|
||||
|
||||
host = argv[0] + strlen(URL_PREFIX);
|
||||
p = strchr(host,'/');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
path = p+1;
|
||||
} else {
|
||||
} else
|
||||
path = "";
|
||||
}
|
||||
p = strchr(host,':');
|
||||
if (*host == '[' && (p = strchr(host, ']')) != NULL) {
|
||||
host++;
|
||||
*p++ = '\0';
|
||||
if (*p != ':')
|
||||
p = NULL;
|
||||
} else
|
||||
p = strchr(host, ':');
|
||||
if (p) {
|
||||
rsync_port = atoi(p+1);
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv+1);
|
||||
}
|
||||
|
||||
if (!read_batch) {
|
||||
if (!read_batch) { /* for read_batch, NO source is specified */
|
||||
p = find_colon(argv[0]);
|
||||
if (p) {
|
||||
if (p) { /* source is remote */
|
||||
if (remote_filesfrom_file
|
||||
&& remote_filesfrom_file != files_from + 1
|
||||
&& strncmp(files_from, argv[0], p-argv[0]+1) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not transfer hostname\n");
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (p[1] == ':') { /* double colon */
|
||||
@@ -752,7 +823,7 @@ static int start_client(int argc, char *argv[])
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
if (argc < 1) { /* destination required */
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
@@ -761,9 +832,8 @@ static int start_client(int argc, char *argv[])
|
||||
*p = 0;
|
||||
shell_machine = argv[0];
|
||||
shell_path = p+1;
|
||||
argc--;
|
||||
argv++;
|
||||
} else {
|
||||
} else { /* source is local */
|
||||
am_sender = 1;
|
||||
|
||||
/* rsync:// destination uses rsync server over direct socket */
|
||||
@@ -773,32 +843,37 @@ static int start_client(int argc, char *argv[])
|
||||
host = argv[argc-1] + strlen(URL_PREFIX);
|
||||
p = strchr(host,'/');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
path = p+1;
|
||||
} else {
|
||||
} else
|
||||
path = "";
|
||||
}
|
||||
p = strchr(host,':');
|
||||
if (*host == '[' && (p = strchr(host, ']')) != NULL) {
|
||||
host++;
|
||||
*p++ = '\0';
|
||||
if (*p != ':')
|
||||
p = NULL;
|
||||
} else
|
||||
p = strchr(host, ':');
|
||||
if (p) {
|
||||
rsync_port = atoi(p+1);
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv);
|
||||
}
|
||||
|
||||
p = find_colon(argv[argc-1]);
|
||||
p = find_colon(argv[argc-1]); /* look in dest arg */
|
||||
if (p && remote_filesfrom_file
|
||||
&& remote_filesfrom_file != files_from + 1
|
||||
&& strncmp(files_from, argv[argc-1], p-argv[argc-1]+1) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not transfer hostname\n");
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (!p) {
|
||||
if (!p) { /* no colon found, so src & dest are local */
|
||||
local_server = 1;
|
||||
if (remote_filesfrom_file) {
|
||||
rprintf(FERROR,
|
||||
"--files-from is remote but transfer is local\n");
|
||||
"--files-from cannot be remote when the transfer is local\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
} else if (p[1] == ':') { /* double colon */
|
||||
@@ -824,16 +899,19 @@ static int start_client(int argc, char *argv[])
|
||||
shell_machine = argv[argc-1];
|
||||
shell_path = p+1;
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
} else {
|
||||
am_sender = 1;
|
||||
argc--;
|
||||
} else { /* read_batch */
|
||||
local_server = 1;
|
||||
shell_path = argv[argc-1];
|
||||
if (find_colon(shell_path)) {
|
||||
rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (shell_machine) {
|
||||
p = strchr(shell_machine,'@');
|
||||
p = strrchr(shell_machine,'@');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
shell_user = shell_machine;
|
||||
@@ -849,13 +927,14 @@ static int start_client(int argc, char *argv[])
|
||||
shell_path?shell_path:"");
|
||||
}
|
||||
|
||||
/* for remote source, only single dest arg can remain ... */
|
||||
if (!am_sender && argc > 1) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (argc == 0 && !am_sender) {
|
||||
extern int list_only;
|
||||
/* ... or no dest at all */
|
||||
if (!am_sender && argc == 0) {
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
@@ -888,7 +967,6 @@ static RETSIGTYPE sigusr1_handler(UNUSED(int val))
|
||||
|
||||
static RETSIGTYPE sigusr2_handler(UNUSED(int val))
|
||||
{
|
||||
extern int log_got_error;
|
||||
if (log_got_error) _exit(RERR_PARTIAL);
|
||||
_exit(0);
|
||||
}
|
||||
@@ -971,16 +1049,9 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
extern int am_root;
|
||||
extern int orig_umask;
|
||||
extern int dry_run;
|
||||
int ret;
|
||||
extern int write_batch;
|
||||
int orig_argc;
|
||||
char **orig_argv;
|
||||
|
||||
orig_argc = argc;
|
||||
orig_argv = argv;
|
||||
int orig_argc = argc;
|
||||
char **orig_argv = argv;
|
||||
|
||||
signal(SIGUSR1, sigusr1_handler);
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
@@ -993,7 +1064,7 @@ int main(int argc,char *argv[])
|
||||
#endif /* def MAINTAINER_MODE */
|
||||
|
||||
starttime = time(NULL);
|
||||
am_root = (getuid() == 0);
|
||||
am_root = (MY_UID() == 0);
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
|
||||
@@ -1025,10 +1096,28 @@ int main(int argc,char *argv[])
|
||||
* (implemented by forking "pwd" and reading its output) doesn't
|
||||
* work when there are other child processes. Also, on all systems
|
||||
* that implement getcwd that way "pwd" can't be found after chroot. */
|
||||
push_dir(NULL,0);
|
||||
push_dir(NULL);
|
||||
|
||||
if (write_batch && !am_server) {
|
||||
write_batch_argvs_file(orig_argc, orig_argv);
|
||||
init_flist();
|
||||
|
||||
if (write_batch || read_batch) {
|
||||
if (write_batch)
|
||||
write_batch_shell_file(orig_argc, orig_argv, argc);
|
||||
|
||||
if (read_batch && strcmp(batch_name, "-") == 0)
|
||||
batch_fd = STDIN_FILENO;
|
||||
else {
|
||||
batch_fd = do_open(batch_name,
|
||||
write_batch ? O_WRONLY | O_CREAT | O_TRUNC
|
||||
: O_RDONLY, S_IRUSR | S_IWUSR);
|
||||
}
|
||||
if (batch_fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
batch_name);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (read_batch)
|
||||
read_stream_flags(batch_fd);
|
||||
}
|
||||
|
||||
if (am_daemon && !am_server)
|
||||
@@ -1042,13 +1131,6 @@ int main(int argc,char *argv[])
|
||||
if (dry_run)
|
||||
verbose = MAX(verbose,1);
|
||||
|
||||
#ifndef SUPPORT_LINKS
|
||||
if (!am_server && preserve_links) {
|
||||
rprintf(FERROR,"ERROR: symbolic links not supported\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (am_server) {
|
||||
set_nonblocking(STDIN_FILENO);
|
||||
set_nonblocking(STDOUT_FILENO);
|
||||
|
||||
164
match.c
164
match.c
@@ -22,11 +22,14 @@
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
extern int make_backups;
|
||||
|
||||
typedef unsigned short tag;
|
||||
|
||||
#define TABLESIZE (1<<16)
|
||||
#define NULL_TAG (-1)
|
||||
#define NULL_TAG ((size_t)-1)
|
||||
|
||||
static int false_alarms;
|
||||
static int tag_hits;
|
||||
@@ -41,12 +44,12 @@ extern struct stats stats;
|
||||
|
||||
struct target {
|
||||
tag t;
|
||||
int i;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
static struct target *targets;
|
||||
|
||||
static int *tag_table;
|
||||
static size_t *tag_table;
|
||||
|
||||
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
|
||||
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
|
||||
@@ -59,16 +62,16 @@ static int compare_targets(struct target *t1,struct target *t2)
|
||||
|
||||
static void build_hash_table(struct sum_struct *s)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
if (!tag_table)
|
||||
tag_table = new_array(int, TABLESIZE);
|
||||
tag_table = new_array(size_t, TABLESIZE);
|
||||
|
||||
targets = new_array(struct target, s->count);
|
||||
if (!tag_table || !targets)
|
||||
out_of_memory("build_hash_table");
|
||||
|
||||
for (i = 0; i < (int)s->count; i++) {
|
||||
for (i = 0; i < s->count; i++) {
|
||||
targets[i].i = i;
|
||||
targets[i].t = gettag(s->sums[i].sum1);
|
||||
}
|
||||
@@ -78,7 +81,7 @@ static void build_hash_table(struct sum_struct *s)
|
||||
for (i = 0; i < TABLESIZE; i++)
|
||||
tag_table[i] = NULL_TAG;
|
||||
|
||||
for (i = s->count-1; i >= 0; i--)
|
||||
for (i = s->count; i-- > 0; )
|
||||
tag_table[targets[i].t] = i;
|
||||
}
|
||||
|
||||
@@ -105,7 +108,7 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
OFF_T j;
|
||||
|
||||
if (verbose > 2 && i >= 0)
|
||||
rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%d n=%.0f\n",
|
||||
rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%u n=%.0f\n",
|
||||
(double)offset,(double)last_match,i,s->sums[i].len,(double)n);
|
||||
|
||||
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
|
||||
@@ -130,72 +133,85 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
if (buf && do_progress) {
|
||||
show_progress(last_match, buf->file_size);
|
||||
|
||||
if (i == -1) end_progress(buf->file_size);
|
||||
if (i == -1)
|
||||
end_progress(buf->file_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hash_search(int f,struct sum_struct *s,
|
||||
struct map_struct *buf,OFF_T len)
|
||||
struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
OFF_T offset, end;
|
||||
int j,k, last_i;
|
||||
OFF_T offset, end, backup;
|
||||
unsigned int k;
|
||||
size_t want_i;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
schar *map;
|
||||
|
||||
/* last_i is used to encourage adjacent matches, allowing the RLL coding of the
|
||||
output to work more efficiently */
|
||||
last_i = -1;
|
||||
/* want_i is used to encourage adjacent matches, allowing the RLL
|
||||
* coding of the output to work more efficiently. */
|
||||
want_i = 0;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"hash search b=%ld len=%.0f\n",
|
||||
(long) s->blength, (double)len);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"hash search b=%u len=%.0f\n",
|
||||
s->blength, (double)len);
|
||||
}
|
||||
|
||||
k = MIN(len, (OFF_T)s->blength);
|
||||
k = MIN(len, s->blength);
|
||||
|
||||
map = (schar *)map_ptr(buf,0,k);
|
||||
map = (schar *)map_ptr(buf, 0, k);
|
||||
|
||||
sum = get_checksum1((char *)map, k);
|
||||
s1 = sum & 0xFFFF;
|
||||
s2 = sum >> 16;
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
|
||||
rprintf(FINFO, "sum=%.8x k=%u\n", sum, k);
|
||||
|
||||
offset = 0;
|
||||
|
||||
end = len + 1 - s->sums[s->count-1].len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "hash search s->blength=%ld len=%.0f count=%ld\n",
|
||||
(long) s->blength, (double) len, (long) s->count);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "hash search s->blength=%u len=%.0f count=%.0f\n",
|
||||
s->blength, (double)len, (double)s->count);
|
||||
}
|
||||
|
||||
do {
|
||||
tag t = gettag2(s1,s2);
|
||||
int done_csum2 = 0;
|
||||
size_t j = tag_table[t];
|
||||
|
||||
j = tag_table[t];
|
||||
if (verbose > 4)
|
||||
rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum);
|
||||
|
||||
if (j == NULL_TAG) {
|
||||
if (j == NULL_TAG)
|
||||
goto null_tag;
|
||||
}
|
||||
|
||||
sum = (s1 & 0xffff) | (s2 << 16);
|
||||
tag_hits++;
|
||||
for (; j < (int) s->count && targets[j].t == t; j++) {
|
||||
int l, i = targets[j].i;
|
||||
do {
|
||||
unsigned int l;
|
||||
size_t i = targets[j].i;
|
||||
|
||||
if (sum != s->sums[i].sum1) continue;
|
||||
if (sum != s->sums[i].sum1)
|
||||
continue;
|
||||
|
||||
/* also make sure the two blocks are the same length */
|
||||
l = MIN((OFF_T)s->blength, len-offset);
|
||||
if (l != s->sums[i].len) continue;
|
||||
if (l != s->sums[i].len)
|
||||
continue;
|
||||
|
||||
/* inplace: ensure chunk's offset is either >= our
|
||||
* offset or that the data didn't move. */
|
||||
if (inplace && !make_backups && s->sums[i].offset < offset
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
|
||||
continue;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"potential match at %.0f target=%d %d sum=%08x\n",
|
||||
(double)offset,j,i,sum);
|
||||
rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
|
||||
(double)offset,(double)j,(double)i,sum);
|
||||
|
||||
if (!done_csum2) {
|
||||
map = (schar *)map_ptr(buf,offset,l);
|
||||
@@ -208,46 +224,73 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we've found a match, but now check to see
|
||||
* if last_i can hint at a better match */
|
||||
for (j++; j < (int) s->count && targets[j].t == t; j++) {
|
||||
int i2 = targets[j].i;
|
||||
if (i2 == last_i + 1) {
|
||||
if (sum != s->sums[i2].sum1) break;
|
||||
if (memcmp(sum2,s->sums[i2].sum2,s->s2length) != 0) break;
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = i2;
|
||||
break;
|
||||
}
|
||||
/* If inplace is enabled, the best possible match is
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the following want_i optimization. */
|
||||
if (inplace && !make_backups) {
|
||||
do {
|
||||
size_t i2 = targets[j].i;
|
||||
if (s->sums[i2].offset != offset)
|
||||
continue;
|
||||
if (i2 != i) {
|
||||
if (sum != s->sums[i2].sum1)
|
||||
break;
|
||||
if (memcmp(sum2, s->sums[i2].sum2,
|
||||
s->s2length) != 0)
|
||||
break;
|
||||
i = i2;
|
||||
}
|
||||
/* This chunk was at the same offset on
|
||||
* both the sender and the receiver. */
|
||||
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
|
||||
goto set_want_i;
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
}
|
||||
|
||||
last_i = i;
|
||||
/* we've found a match, but now check to see
|
||||
* if want_i can hint at a better match. */
|
||||
if (i != want_i && want_i < s->count
|
||||
&& (!inplace || make_backups || s->sums[want_i].offset >= offset
|
||||
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
|
||||
&& sum == s->sums[want_i].sum1
|
||||
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = want_i;
|
||||
}
|
||||
set_want_i:
|
||||
want_i = i + 1;
|
||||
|
||||
matched(f,s,buf,offset,i);
|
||||
offset += s->sums[i].len - 1;
|
||||
k = MIN((OFF_T)s->blength, len-offset);
|
||||
map = (schar *)map_ptr(buf,offset,k);
|
||||
k = MIN(s->blength, len-offset);
|
||||
map = (schar *)map_ptr(buf, offset, k);
|
||||
sum = get_checksum1((char *)map, k);
|
||||
s1 = sum & 0xFFFF;
|
||||
s2 = sum >> 16;
|
||||
matches++;
|
||||
break;
|
||||
}
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
|
||||
null_tag:
|
||||
backup = offset - last_match;
|
||||
/* We sometimes read 1 byte prior to last_match... */
|
||||
if (backup < 0)
|
||||
backup = 0;
|
||||
|
||||
/* Trim off the first byte from the checksum */
|
||||
map = (schar *)map_ptr(buf,offset,k+1);
|
||||
more = offset + k < len;
|
||||
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
|
||||
+ backup;
|
||||
s1 -= map[0] + CHAR_OFFSET;
|
||||
s2 -= k * (map[0]+CHAR_OFFSET);
|
||||
|
||||
/* Add on the next byte (if there is one) to the checksum */
|
||||
if (k < (len-offset)) {
|
||||
s1 += (map[k]+CHAR_OFFSET);
|
||||
if (more) {
|
||||
s1 += map[k] + CHAR_OFFSET;
|
||||
s2 += s1;
|
||||
} else {
|
||||
} else
|
||||
--k;
|
||||
}
|
||||
|
||||
/* By matching early we avoid re-reading the
|
||||
data 3 times in the case where a token
|
||||
@@ -255,9 +298,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
match. The 3 reads are caused by the
|
||||
running match, the checksum update and the
|
||||
literal send. */
|
||||
if (offset > last_match
|
||||
&& offset-last_match >= CHUNK_SIZE+s->blength
|
||||
&& end-offset > CHUNK_SIZE) {
|
||||
if (backup >= CHUNK_SIZE + s->blength
|
||||
&& end - offset > CHUNK_SIZE) {
|
||||
matched(f,s,buf,offset - s->blength, -2);
|
||||
}
|
||||
} while (++offset < end);
|
||||
@@ -284,7 +326,6 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
char file_sum[MD4_SUM_LENGTH];
|
||||
extern int write_batch; /* dw */
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
@@ -292,7 +333,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
sum_init();
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (len > 0 && s->count>0) {
|
||||
build_hash_table(s);
|
||||
@@ -315,12 +356,13 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
}
|
||||
|
||||
sum_end(file_sum);
|
||||
/* If we had a read error, send a bad checksum. */
|
||||
if (buf && buf->status != 0)
|
||||
file_sum[0]++;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f,file_sum,MD4_SUM_LENGTH);
|
||||
if (write_batch) /* dw */
|
||||
write_batch_delta_file(file_sum, MD4_SUM_LENGTH);
|
||||
|
||||
if (targets) {
|
||||
free(targets);
|
||||
|
||||
@@ -58,7 +58,7 @@ BEGIN {
|
||||
next;
|
||||
}
|
||||
|
||||
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
|
||||
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time|^const/ {
|
||||
next;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: 2.6.0pre1
|
||||
Version: 2.6.3
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.6.0pre1.tar.gz
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-%{version}.tar.gz
|
||||
URL: http://samba.anu.edu.au/rsync/
|
||||
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
|
||||
BuildRoot: /tmp/rsync
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: PVERSION
|
||||
Release: PRELEASE
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-PVERSION.tar.gz
|
||||
URL: http://samba.anu.edu.au/rsync/
|
||||
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
|
||||
BuildRoot: /tmp/rsync
|
||||
|
||||
%description
|
||||
rsync is a replacement for rcp that has many more features.
|
||||
|
||||
rsync uses the "rsync algorithm" which provides a very fast method for
|
||||
bringing remote files into sync. It does this by sending just the
|
||||
differences in the files across the link, without requiring that both
|
||||
sets of files are present at one of the ends of the link beforehand.
|
||||
|
||||
A technical report describing the rsync algorithm is included with
|
||||
this package.
|
||||
|
||||
%changelog
|
||||
* Thu Jan 30 2003 Horst von Brand <vonbrand@inf.utfsm.cl>
|
||||
Fixed "Sept" date in %changelog here
|
||||
Use %{_mandir} to point to manpages
|
||||
Support for compressed manpages (* at end catches them in %files)
|
||||
Add doc/README-SGML and doc/rsync.sgml to %doc
|
||||
|
||||
* Mon Sep 11 2000 John H Terpstra <jht@turbolinux.com>
|
||||
Changed target paths to be Linux Standards Base compliant
|
||||
|
||||
* Mon Jan 25 1999 Stefan Hornburg <racke@linuxia.de>
|
||||
quoted RPM_OPT_FLAGS for the sake of robustness
|
||||
|
||||
* Mon May 18 1998 Andrew Tridgell <tridge@samba.anu.edu.au>
|
||||
reworked for auto-building when I release rsync (tridge@samba.anu.edu.au)
|
||||
|
||||
* Sat May 16 1998 John H Terpstra <jht@aquasoft.com.au>
|
||||
Upgraded to Rsync 2.0.6
|
||||
-new feature anonymous rsync
|
||||
|
||||
* Mon Apr 6 1998 Douglas N. Arnold <dna@math.psu.edu>
|
||||
|
||||
Upgrade to rsync version 1.7.2.
|
||||
|
||||
* Sun Mar 1 1998 Douglas N. Arnold <dna@math.psu.edu>
|
||||
|
||||
Built 1.6.9-1 based on the 1.6.3-2 spec file of John A. Martin.
|
||||
Changes from 1.6.3-2 packaging: added latex and dvips commands
|
||||
to create tech_report.ps.
|
||||
|
||||
* Mon Aug 25 1997 John A. Martin <jam@jamux.com>
|
||||
|
||||
Built 1.6.3-2 after finding no rsync-1.6.3-1.src.rpm although there
|
||||
was an ftp://ftp.redhat.com/pub/contrib/alpha/rsync-1.6.3-1.alpha.rpm
|
||||
showing no packager nor signature but giving
|
||||
"Source RPM: rsync-1.6.3-1.src.rpm".
|
||||
|
||||
Changes from 1.6.2-1 packaging: added '$RPM_OPT_FLAGS' to make, strip
|
||||
to '%build', removed '%prefix'.
|
||||
|
||||
* Thu Apr 10 1997 Michael De La Rue <miked@ed.ac.uk>
|
||||
|
||||
rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the
|
||||
previous package(s).)
|
||||
|
||||
%prep
|
||||
%setup
|
||||
|
||||
%build
|
||||
./configure --prefix=/usr --mandir=%{_mandir}
|
||||
make CFLAGS="$RPM_OPT_FLAGS"
|
||||
strip rsync
|
||||
|
||||
%install
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/bin
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man{1,5}
|
||||
install -m755 rsync $RPM_BUILD_ROOT/usr/bin
|
||||
install -m644 rsync.1 $RPM_BUILD_ROOT/%{_mandir}/man1
|
||||
install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%attr(-,root,root) /usr/bin/rsync
|
||||
%attr(-,root,root) %{_mandir}/man1/rsync.1*
|
||||
%attr(-,root,root) %{_mandir}/man5/rsyncd.conf.5*
|
||||
%attr(-,root,root) %doc tech_report.tex
|
||||
%attr(-,root,root) %doc README
|
||||
%attr(-,root,root) %doc COPYING
|
||||
%attr(-,root,root) %doc doc/README-SGML doc/rsync.sgml
|
||||
4
params.c
4
params.c
@@ -491,8 +491,8 @@ static FILE *OpenConfFile( char *FileName )
|
||||
OpenedFile = fopen( FileName, "r" );
|
||||
if( NULL == OpenedFile )
|
||||
{
|
||||
rprintf(FERROR,"rsync: unable to open configuration file \"%s\": %s\n",
|
||||
FileName, strerror(errno));
|
||||
rsyserr(FERROR, errno, "rsync: unable to open configuration file \"%s\"",
|
||||
FileName);
|
||||
}
|
||||
|
||||
return( OpenedFile );
|
||||
|
||||
79
pipe.c
79
pipe.c
@@ -1,19 +1,19 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
*
|
||||
* Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -21,11 +21,18 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int blocking_io;
|
||||
extern int orig_umask;
|
||||
extern int write_batch;
|
||||
extern int filesfrom_fd;
|
||||
|
||||
/**
|
||||
* Create a child connected to use on stdin/stdout.
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
* Note that in the child STDIN is set to blocking and STDOUT
|
||||
* is set to non-blocking. This is necessary as rsh relies on stdin being blocking
|
||||
* and ssh relies on stdout being non-blocking
|
||||
@@ -39,32 +46,28 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
extern int blocking_io;
|
||||
|
||||
|
||||
if (verbose >= 2) {
|
||||
print_child_argv(command);
|
||||
}
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
|
||||
rprintf(FERROR, "pipe: %s\n", strerror(errno));
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rprintf(FERROR, "fork: %s\n", strerror(errno));
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
extern int orig_umask;
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rprintf(FERROR, "Failed to dup/close : %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
@@ -76,13 +79,12 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
if (blocking_io > 0)
|
||||
set_blocking(STDOUT_FILENO);
|
||||
execvp(command[0], command);
|
||||
rprintf(FERROR, "Failed to exec %s : %s\n",
|
||||
command[0], strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
|
||||
rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
@@ -92,33 +94,42 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
return pid;
|
||||
}
|
||||
|
||||
pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
/* This function forks a child which calls child_main(). First,
|
||||
* however, it has to establish communication paths to and from the
|
||||
* newborn child. It creates two socket pairs -- one for writing to
|
||||
* the child (from the parent) and one for reading from the child
|
||||
* (writing to the parent). Since that's four socket ends, each
|
||||
* process has to close the two ends it doesn't need. The remaining
|
||||
* two socket ends are retained for reading and writing. In the
|
||||
* child, the STDIN and STDOUT file descriptors refer to these
|
||||
* sockets. In the parent, the function arguments f_in and f_out are
|
||||
* set to refer to these sockets. */
|
||||
pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
int (*child_main)(int, char*[]))
|
||||
{
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
extern int read_batch;
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int filesfrom_fd;
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 ||
|
||||
fd_pair(from_child_pipe) < 0) {
|
||||
rprintf(FERROR,"pipe: %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rprintf(FERROR,"fork: %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
am_sender = read_batch ? 0 : !am_sender;
|
||||
am_server = 1;
|
||||
am_sender = !am_sender;
|
||||
am_server = 1;
|
||||
|
||||
/* The server side never writes the batch, even if it
|
||||
* is local (it makes the logic easier elsewhere). */
|
||||
write_batch = 0;
|
||||
|
||||
if (!am_sender)
|
||||
filesfrom_fd = -1;
|
||||
@@ -127,11 +138,13 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO)
|
||||
close(from_child_pipe[1]);
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
@@ -140,12 +153,12 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 ||
|
||||
close(to_child_pipe[0]) < 0) {
|
||||
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
*f_in = from_child_pipe[0];
|
||||
*f_out = to_child_pipe[1];
|
||||
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,3 @@ config.h
|
||||
config.log
|
||||
config.status
|
||||
dummy
|
||||
rsync
|
||||
zlib/dummy
|
||||
|
||||
@@ -907,10 +907,10 @@ int poptGetNextOpt(poptContext con)
|
||||
#ifndef DBL_EPSILON
|
||||
#define DBL_EPSILON 2.2204460492503131e-16
|
||||
#endif
|
||||
#define _ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
|
||||
if ((_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
|
||||
#define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
|
||||
if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
|
||||
return POPT_ERROR_OVERFLOW;
|
||||
if ((FLT_MIN - _ABS(aDouble)) > DBL_EPSILON)
|
||||
if ((FLT_MIN - MY_ABS(aDouble)) > DBL_EPSILON)
|
||||
return POPT_ERROR_OVERFLOW;
|
||||
*((float *) opt->arg) = aDouble;
|
||||
}
|
||||
@@ -1055,7 +1055,7 @@ poptContext poptFreeContext(poptContext con)
|
||||
}
|
||||
|
||||
int poptAddAlias(poptContext con, struct poptAlias alias,
|
||||
/*@unused@*/ int flags)
|
||||
/*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
poptItem item = (poptItem) alloca(sizeof(*item));
|
||||
memset(item, 0, sizeof(*item));
|
||||
|
||||
@@ -363,7 +363,7 @@ int poptDupArgv(int argc, /*@null@*/ const char **argv,
|
||||
* @retval argcPtr address of returned no. of arguments
|
||||
* @retval argvPtr address of returned argument array
|
||||
*/
|
||||
int poptParseArgvString(const char * s,
|
||||
int poptParseArgvString(const unsigned char * s,
|
||||
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
|
||||
/*@modifies *argcPtr, *argvPtr @*/;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "poptint.h"
|
||||
|
||||
/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
|
||||
static void configLine(poptContext con, char * line)
|
||||
static void configLine(poptContext con, unsigned char * line)
|
||||
/*@modifies con @*/
|
||||
{
|
||||
/*@-type@*/
|
||||
@@ -92,9 +92,9 @@ static void configLine(poptContext con, char * line)
|
||||
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
{
|
||||
const char * file, * chptr, * end;
|
||||
char * buf;
|
||||
/*@dependent@*/ char * dst;
|
||||
const unsigned char * file, * chptr, * end;
|
||||
unsigned char * buf;
|
||||
/*@dependent@*/ unsigned char * dst;
|
||||
int fd, rc;
|
||||
off_t fileLength;
|
||||
|
||||
@@ -159,7 +159,8 @@ int poptReadConfigFile(poptContext con, const char * fn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) {
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
|
||||
{
|
||||
char * fn, * home;
|
||||
int rc;
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
* @param key option(s)
|
||||
*/
|
||||
static void displayArgs(poptContext con,
|
||||
/*@unused@*/ enum poptCallbackReason foo,
|
||||
/*@unused@*/ UNUSED(enum poptCallbackReason foo),
|
||||
struct poptOption * key,
|
||||
/*@unused@*/ const char * arg, /*@unused@*/ void * data)
|
||||
/*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data))
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem@*/
|
||||
{
|
||||
@@ -63,7 +63,7 @@ struct poptOption poptHelpOptions[] = {
|
||||
/**
|
||||
* @param table option(s)
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *const
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
/*@*/
|
||||
{
|
||||
@@ -81,7 +81,7 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *const
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getArgDescrip(const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: wazzup? */
|
||||
/*@null@*/ const char * translation_domain)
|
||||
@@ -191,11 +191,11 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
{
|
||||
int indentLength = maxLeftCol + 5;
|
||||
int lineLength = 79 - indentLength;
|
||||
const char * help = D_(translation_domain, opt->descrip);
|
||||
const unsigned char * help = D_(translation_domain, opt->descrip);
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
int helpLength;
|
||||
char * defs = NULL;
|
||||
char * left;
|
||||
unsigned char * defs = NULL;
|
||||
unsigned char * left;
|
||||
int nb = maxLeftCol + 1;
|
||||
|
||||
/* Make sure there's more than enough room in target buffer. */
|
||||
@@ -314,7 +314,7 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
|
||||
helpLength = strlen(help);
|
||||
while (helpLength > lineLength) {
|
||||
const char * ch;
|
||||
const unsigned char * ch;
|
||||
char format[10];
|
||||
|
||||
ch = help + lineLength - 1;
|
||||
@@ -475,7 +475,7 @@ static int showHelpIntro(poptContext con, FILE * fp)
|
||||
return len;
|
||||
}
|
||||
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
int leftColWidth;
|
||||
|
||||
@@ -634,7 +634,7 @@ static int showShortOptions(const struct poptOption * opt, FILE * fp,
|
||||
return strlen(s) + 4;
|
||||
}
|
||||
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
int cursor;
|
||||
|
||||
|
||||
@@ -51,10 +51,10 @@ int poptDupArgv(int argc, const char **argv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
|
||||
int poptParseArgvString(const unsigned char * s, int * argcPtr, const char *** argvPtr)
|
||||
{
|
||||
const char * src;
|
||||
char quote = '\0';
|
||||
const unsigned char * src;
|
||||
unsigned char quote = '\0';
|
||||
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
|
||||
const char ** argv = malloc(sizeof(*argv) * argvAlloced);
|
||||
int argc = 0;
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__GNUC__) || defined(APPLE)
|
||||
/* Apparently the OS X port of gcc gags on __attribute__.
|
||||
*
|
||||
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
|
||||
#define __attribute__(x)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __NeXT
|
||||
/* access macros are not declared in non posix mode in unistd.h -
|
||||
don't try to use posix on NeXTstep 3.3 ! */
|
||||
@@ -69,5 +77,6 @@ char *alloca ();
|
||||
#define xstrdup(_str) strdup(_str)
|
||||
#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
|
||||
#include "popt.h"
|
||||
|
||||
113
progress.c
113
progress.c
@@ -21,14 +21,23 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
static OFF_T last_ofs;
|
||||
static struct timeval print_time;
|
||||
static struct timeval start_time;
|
||||
static OFF_T start_ofs;
|
||||
extern struct stats stats;
|
||||
extern int am_server;
|
||||
|
||||
#define PROGRESS_HISTORY_SECS 5
|
||||
|
||||
struct progress_history {
|
||||
struct timeval time;
|
||||
OFF_T ofs;
|
||||
};
|
||||
|
||||
static struct progress_history ph_start;
|
||||
static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
|
||||
static int newest_hpos, oldest_hpos;
|
||||
|
||||
static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
|
||||
{
|
||||
return (t2->tv_sec - t1->tv_sec) * 1000
|
||||
return (t2->tv_sec - t1->tv_sec) * 1000L
|
||||
+ (t2->tv_usec - t1->tv_usec) / 1000;
|
||||
}
|
||||
|
||||
@@ -43,19 +52,29 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
|
||||
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
int is_last)
|
||||
{
|
||||
int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
|
||||
unsigned long diff = msdiff(&start_time, now);
|
||||
double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
|
||||
char eol[256];
|
||||
const char *units;
|
||||
/* If we've finished transferring this file, show the time taken;
|
||||
* otherwise show expected time to complete. That's kind of
|
||||
* inconsistent, but people can probably cope. Hopefully we'll
|
||||
* get more consistent and complete progress reporting soon. --
|
||||
* mbp */
|
||||
double remain = is_last ? (double) diff / 1000.0
|
||||
: rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
|
||||
int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
|
||||
unsigned long diff;
|
||||
double rate, remain;
|
||||
int remain_h, remain_m, remain_s;
|
||||
|
||||
if (is_last) {
|
||||
/* Compute stats based on the starting info. */
|
||||
diff = msdiff(&ph_start.time, now);
|
||||
if (!diff)
|
||||
diff = 1;
|
||||
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
|
||||
/* Switch to total time taken for our last update. */
|
||||
remain = (double) diff / 1000.0;
|
||||
} else {
|
||||
/* Compute stats based on recent progress. */
|
||||
diff = msdiff(&ph_list[oldest_hpos].time, now);
|
||||
rate = diff ? (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
|
||||
/ diff / 1024.0 : 0;
|
||||
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
|
||||
}
|
||||
|
||||
if (rate > 1024*1024) {
|
||||
rate /= 1024.0 * 1024.0;
|
||||
units = "GB/s";
|
||||
@@ -70,50 +89,66 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
remain_m = (int) (remain / 60.0) % 60;
|
||||
remain_h = (int) (remain / 3600.0);
|
||||
|
||||
if (is_last) {
|
||||
snprintf(eol, sizeof eol, " (%d, %.1f%% of %d)\n",
|
||||
stats.num_transferred_files,
|
||||
(float)((stats.current_file_index+1) * 100)
|
||||
/ stats.num_files,
|
||||
stats.num_files);
|
||||
} else
|
||||
strcpy(eol, "\r");
|
||||
rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
|
||||
(double) ofs, pct, rate, units,
|
||||
remain_h, remain_m, remain_s,
|
||||
is_last ? "\n" : "\r");
|
||||
remain_h, remain_m, remain_s, eol);
|
||||
}
|
||||
|
||||
void end_progress(OFF_T size)
|
||||
{
|
||||
extern int am_server;
|
||||
|
||||
if (!am_server) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
rprint_progress(size, size, &now, True);
|
||||
}
|
||||
last_ofs = 0;
|
||||
start_ofs = 0;
|
||||
print_time.tv_sec = print_time.tv_usec = 0;
|
||||
start_time.tv_sec = start_time.tv_usec = 0;
|
||||
memset(&ph_start, 0, sizeof ph_start);
|
||||
}
|
||||
|
||||
void show_progress(OFF_T ofs, OFF_T size)
|
||||
{
|
||||
extern int am_server;
|
||||
struct timeval now;
|
||||
|
||||
if (!start_time.tv_sec) {
|
||||
gettimeofday(&now, NULL);
|
||||
start_time.tv_sec = now.tv_sec;
|
||||
start_time.tv_usec = now.tv_usec;
|
||||
start_ofs = ofs;
|
||||
if (am_server)
|
||||
return;
|
||||
if (am_server)
|
||||
return;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
if (!ph_start.time.tv_sec) {
|
||||
int i;
|
||||
|
||||
/* Try to guess the real starting time when the sender started
|
||||
* to send us data by using the time we last received some data
|
||||
* in the last file (if it was recent enough). */
|
||||
if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) {
|
||||
ph_start.time = ph_list[newest_hpos].time;
|
||||
ph_start.ofs = 0;
|
||||
} else {
|
||||
ph_start.time.tv_sec = now.tv_sec;
|
||||
ph_start.time.tv_usec = now.tv_usec;
|
||||
ph_start.ofs = ofs;
|
||||
}
|
||||
|
||||
for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
|
||||
ph_list[i] = ph_start;
|
||||
}
|
||||
else {
|
||||
if (am_server)
|
||||
if (msdiff(&ph_list[newest_hpos].time, &now) < 1000)
|
||||
return;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
newest_hpos = oldest_hpos;
|
||||
oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
|
||||
ph_list[newest_hpos].time.tv_sec = now.tv_sec;
|
||||
ph_list[newest_hpos].time.tv_usec = now.tv_usec;
|
||||
ph_list[newest_hpos].ofs = ofs;
|
||||
}
|
||||
|
||||
if (ofs > last_ofs + 1000 && msdiff(&print_time, &now) > 250) {
|
||||
rprint_progress(ofs, size, &now, False);
|
||||
last_ofs = ofs;
|
||||
print_time.tv_sec = now.tv_sec;
|
||||
print_time.tv_usec = now.tv_usec;
|
||||
}
|
||||
rprint_progress(ofs, size, &now, False);
|
||||
}
|
||||
|
||||
503
receiver.c
503
receiver.c
@@ -22,84 +22,57 @@
|
||||
|
||||
extern int verbose;
|
||||
extern int recurse;
|
||||
extern int delete_mode;
|
||||
extern int protocol_version;
|
||||
extern int delete_after;
|
||||
extern int max_delete;
|
||||
extern int csum_length;
|
||||
extern struct stats stats;
|
||||
extern int dry_run;
|
||||
extern int read_batch;
|
||||
extern int batch_gen_fd;
|
||||
extern int am_server;
|
||||
extern int relative_paths;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int cvs_exclude;
|
||||
extern int io_error;
|
||||
extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *compare_dest;
|
||||
extern int make_backups;
|
||||
extern int do_progress;
|
||||
extern char *backup_dir;
|
||||
extern char *backup_suffix;
|
||||
extern int backup_suffix_len;
|
||||
extern int cleanup_got_literal;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int orig_umask;
|
||||
extern int keep_partial;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
|
||||
static struct delete_list {
|
||||
DEV64_T dev;
|
||||
INO64_T inode;
|
||||
} *delete_list;
|
||||
static int dlist_len, dlist_alloc_len;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
|
||||
/* yuck! This function wouldn't have been necessary if I had the sorting
|
||||
* algorithm right. Unfortunately fixing the sorting algorithm would introduce
|
||||
* a backward incompatibility as file list indexes are sent over the link.
|
||||
*/
|
||||
static int delete_already_done(struct file_list *flist,int j)
|
||||
{
|
||||
int i;
|
||||
STRUCT_STAT st;
|
||||
|
||||
if (link_stat(f_name(flist->files[j]), &st)) return 1;
|
||||
|
||||
for (i = 0; i < dlist_len; i++) {
|
||||
if (st.st_ino == delete_list[i].inode &&
|
||||
(DEV64_T)st.st_dev == delete_list[i].dev)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_delete_entry(struct file_struct *file)
|
||||
{
|
||||
if (dlist_len == dlist_alloc_len) {
|
||||
dlist_alloc_len += 1024;
|
||||
delete_list = realloc_array(delete_list, struct delete_list,
|
||||
dlist_alloc_len);
|
||||
if (!delete_list) out_of_memory("add_delete_entry");
|
||||
}
|
||||
|
||||
delete_list[dlist_len].dev = file->dev;
|
||||
delete_list[dlist_len].inode = file->inode;
|
||||
dlist_len++;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"added %s to delete list\n", f_name(file));
|
||||
}
|
||||
|
||||
static void delete_one(char *fn, int is_dir)
|
||||
{
|
||||
if (!is_dir) {
|
||||
if (robust_unlink(fn) != 0) {
|
||||
rprintf(FERROR, "delete_one: unlink %s failed: %s\n",
|
||||
full_fname(fn), strerror(errno));
|
||||
} else if (verbose) {
|
||||
rprintf(FINFO, "deleting %s\n", fn);
|
||||
}
|
||||
rsyserr(FERROR, errno, "delete_one: unlink %s failed",
|
||||
full_fname(fn));
|
||||
} else if (verbose)
|
||||
rprintf(FINFO, "deleting %s\n", safe_fname(fn));
|
||||
} else {
|
||||
if (do_rmdir(fn) != 0) {
|
||||
if (errno != ENOTEMPTY && errno != EEXIST) {
|
||||
rprintf(FERROR, "delete_one: rmdir %s failed: %s\n",
|
||||
full_fname(fn), strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"delete_one: rmdir %s failed",
|
||||
full_fname(fn));
|
||||
}
|
||||
} else if (verbose) {
|
||||
rprintf(FINFO, "deleting directory %s\n", fn);
|
||||
rprintf(FINFO, "deleting directory %s\n",
|
||||
safe_fname(fn));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,17 +85,13 @@ static int is_backup_file(char *fn)
|
||||
}
|
||||
|
||||
|
||||
/* this deletes any files on the receiving side that are not present
|
||||
* on the sending side. For version 1.6.4 I have changed the behaviour
|
||||
* to match more closely what most people seem to expect of this option */
|
||||
/* This deletes any files on the receiving side that are not present
|
||||
* on the sending side. */
|
||||
void delete_files(struct file_list *flist)
|
||||
{
|
||||
struct file_list *local_file_list;
|
||||
int i, j;
|
||||
char *name;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int max_delete;
|
||||
char *argv[1], fbuf[MAXPATHLEN];
|
||||
static int deletion_count;
|
||||
|
||||
if (cvs_exclude)
|
||||
@@ -133,35 +102,32 @@ void delete_files(struct file_list *flist)
|
||||
return;
|
||||
}
|
||||
|
||||
for (j=0;j<flist->count;j++) {
|
||||
if (!S_ISDIR(flist->files[j]->mode) ||
|
||||
!(flist->files[j]->flags & FLAG_DELETE)) continue;
|
||||
|
||||
if (protocol_version < 19 &&
|
||||
delete_already_done(flist, j)) continue;
|
||||
|
||||
name = strdup(f_name(flist->files[j]));
|
||||
|
||||
if (!(local_file_list = send_file_list(-1,1,&name))) {
|
||||
free(name);
|
||||
for (j = 0; j < flist->count; j++) {
|
||||
if (!(flist->files[j]->flags & FLAG_TOP_DIR)
|
||||
|| !S_ISDIR(flist->files[j]->mode))
|
||||
continue;
|
||||
|
||||
argv[0] = f_name_to(flist->files[j], fbuf);
|
||||
|
||||
if (!(local_file_list = send_file_list(-1, 1, argv)))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"deleting in %s\n", name);
|
||||
rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
|
||||
|
||||
for (i=local_file_list->count-1;i>=0;i--) {
|
||||
if (max_delete && deletion_count > max_delete) break;
|
||||
if (!local_file_list->files[i]->basename) continue;
|
||||
if (protocol_version < 19 &&
|
||||
S_ISDIR(local_file_list->files[i]->mode))
|
||||
add_delete_entry(local_file_list->files[i]);
|
||||
if (-1 == flist_find(flist,local_file_list->files[i])) {
|
||||
for (i = local_file_list->count-1; i >= 0; i--) {
|
||||
if (max_delete && deletion_count > max_delete)
|
||||
break;
|
||||
if (!local_file_list->files[i]->basename)
|
||||
continue;
|
||||
if (flist_find(flist,local_file_list->files[i]) < 0) {
|
||||
char *f = f_name(local_file_list->files[i]);
|
||||
if (make_backups && (backup_dir || !is_backup_file(f))) {
|
||||
(void) make_backup(f);
|
||||
if (verbose)
|
||||
rprintf(FINFO, "deleting %s\n", f);
|
||||
make_backup(f);
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "deleting %s\n",
|
||||
safe_fname(f));
|
||||
}
|
||||
} else {
|
||||
int mode = local_file_list->files[i]->mode;
|
||||
delete_one(f, S_ISDIR(mode) != 0);
|
||||
@@ -170,7 +136,6 @@ void delete_files(struct file_list *flist)
|
||||
}
|
||||
}
|
||||
flist_free(local_file_list);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,8 +168,8 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
int maxname;
|
||||
|
||||
if (tmpdir) {
|
||||
strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2);
|
||||
length = strlen(fnametmp);
|
||||
/* Note: this can't overflow, so the return value is safe */
|
||||
length = strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2);
|
||||
fnametmp[length++] = '/';
|
||||
fnametmp[length] = '\0'; /* always NULL terminated */
|
||||
}
|
||||
@@ -216,9 +181,8 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
/* copy up to and including the slash */
|
||||
strlcpy(fnametmp, fname, length + 1);
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
f = fname;
|
||||
}
|
||||
fnametmp[length++] = '.';
|
||||
fnametmp[length] = '\0'; /* always NULL terminated */
|
||||
|
||||
@@ -237,30 +201,39 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
}
|
||||
|
||||
|
||||
static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
OFF_T total_size)
|
||||
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
char *fname, int fd, OFF_T total_size)
|
||||
{
|
||||
int i;
|
||||
static char file_sum1[MD4_SUM_LENGTH];
|
||||
static char file_sum2[MD4_SUM_LENGTH];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
unsigned int len;
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
static char file_sum1[MD4_SUM_LENGTH];
|
||||
static char file_sum2[MD4_SUM_LENGTH];
|
||||
char *map=NULL;
|
||||
int i;
|
||||
char *map = NULL;
|
||||
|
||||
read_sum_head(f_in, &sum);
|
||||
|
||||
sum_init();
|
||||
if (fd_r >= 0 && size_r > 0) {
|
||||
OFF_T map_size = MAX(sum.blength * 2, 16*1024);
|
||||
mapbuf = map_file(fd_r, size_r, map_size, sum.blength);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "recv mapped %s of size %.0f\n",
|
||||
safe_fname(fname_r), (double)size_r);
|
||||
}
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
|
||||
for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) {
|
||||
sum_init(checksum_seed);
|
||||
|
||||
while ((i = recv_token(f_in, &data)) != 0) {
|
||||
if (do_progress)
|
||||
show_progress(offset, total_size);
|
||||
|
||||
if (i > 0) {
|
||||
extern int cleanup_got_literal;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"data recv %d at %.0f\n",
|
||||
i,(double)offset);
|
||||
@@ -271,11 +244,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
|
||||
sum_update(data,i);
|
||||
|
||||
if (fd != -1 && write_file(fd,data,i) != i) {
|
||||
rprintf(FERROR, "write failed on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (fd != -1 && write_file(fd,data,i) != i)
|
||||
goto report_write_error;
|
||||
offset += i;
|
||||
continue;
|
||||
}
|
||||
@@ -283,7 +253,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
i = -(i+1);
|
||||
offset2 = i*(OFF_T)sum.blength;
|
||||
len = sum.blength;
|
||||
if (i == (int) sum.count-1 && sum.remainder != 0)
|
||||
if (i == (int)sum.count-1 && sum.remainder != 0)
|
||||
len = sum.remainder;
|
||||
|
||||
stats.matched_data += len;
|
||||
@@ -292,69 +262,94 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
|
||||
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
|
||||
i,len,(double)offset2,(double)offset);
|
||||
|
||||
if (buf) {
|
||||
map = map_ptr(buf,offset2,len);
|
||||
if (mapbuf) {
|
||||
map = map_ptr(mapbuf,offset2,len);
|
||||
|
||||
see_token(map, len);
|
||||
sum_update(map,len);
|
||||
}
|
||||
|
||||
if (fd != -1 && write_file(fd,map,len) != (int) len) {
|
||||
rprintf(FERROR, "write failed on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
if (inplace) {
|
||||
if (offset == offset2 && fd != -1) {
|
||||
if (flush_write_file(fd) < 0)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
if (do_lseek(fd, len, SEEK_CUR) != offset) {
|
||||
rsyserr(FERROR, errno,
|
||||
"lseek failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fd != -1 && write_file(fd, map, len) != (int)len)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
flush_write_file(fd);
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (inplace && fd != -1)
|
||||
ftruncate(fd, offset);
|
||||
#endif
|
||||
|
||||
if (do_progress)
|
||||
end_progress(total_size);
|
||||
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
|
||||
rprintf(FERROR, "write failed on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
report_write_error:
|
||||
rsyserr(FERROR, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
sum_end(file_sum1);
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
|
||||
if (verbose > 2) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"got file_sum\n");
|
||||
}
|
||||
if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
|
||||
if (fd != -1 && memcmp(file_sum1, file_sum2, MD4_SUM_LENGTH) != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void discard_receive_data(int f_in, OFF_T length)
|
||||
{
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* main routine for receiver process.
|
||||
*
|
||||
* Receiver process runs on the same host as the generator process. */
|
||||
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
{
|
||||
int next_gen_i = -1;
|
||||
int fd1,fd2;
|
||||
STRUCT_STAT st;
|
||||
char *fname;
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char template[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnamecmp;
|
||||
char *fnamecmp, *partialptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
struct map_struct *buf;
|
||||
int i;
|
||||
struct file_struct *file;
|
||||
int phase=0;
|
||||
int recv_ok;
|
||||
extern struct stats stats;
|
||||
extern int preserve_perms;
|
||||
extern int delete_after;
|
||||
extern int orig_umask;
|
||||
struct stats initial_stats;
|
||||
int save_make_backups = make_backups;
|
||||
int i, recv_ok, phase = 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
|
||||
|
||||
if (flist->hlink_pool) {
|
||||
pool_destroy(flist->hlink_pool);
|
||||
flist->hlink_pool = NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
@@ -362,15 +357,23 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
if (phase==0) {
|
||||
phase++;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files phase=%d\n",phase);
|
||||
write_int(f_gen,-1);
|
||||
continue;
|
||||
if (read_batch) {
|
||||
if (next_gen_i != flist->count)
|
||||
while (read_int(batch_gen_fd) != -1) {}
|
||||
next_gen_i = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
if (phase)
|
||||
break;
|
||||
|
||||
phase = 1;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files phase=%d\n", phase);
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
if (keep_partial)
|
||||
make_backups = 0; /* prevents double backup */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= flist->count) {
|
||||
@@ -380,43 +383,82 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
}
|
||||
|
||||
file = flist->files[i];
|
||||
fname = f_name(file);
|
||||
|
||||
stats.current_file_index = i;
|
||||
stats.num_transferred_files++;
|
||||
stats.total_transferred_size += file->length;
|
||||
cleanup_got_literal = 0;
|
||||
|
||||
if (local_name)
|
||||
fname = local_name;
|
||||
else
|
||||
fname = f_name_to(file, fbuf);
|
||||
|
||||
if (dry_run) {
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
}
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname));
|
||||
continue;
|
||||
}
|
||||
|
||||
initial_stats = stats;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files(%s)\n",fname);
|
||||
rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
|
||||
|
||||
fnamecmp = fname;
|
||||
if (read_batch) {
|
||||
while (i > next_gen_i) {
|
||||
next_gen_i = read_int(batch_gen_fd);
|
||||
if (next_gen_i == -1)
|
||||
next_gen_i = flist->count;
|
||||
}
|
||||
if (i < next_gen_i) {
|
||||
rprintf(FINFO, "skipping update for \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
discard_receive_data(f_in, file->length);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_exclude_list.head
|
||||
&& check_exclude(&server_exclude_list, fname,
|
||||
S_ISDIR(file->mode)) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (partial_dir) {
|
||||
if ((partialptr = partial_dir_fname(fname)) != NULL)
|
||||
fnamecmp = partialptr;
|
||||
else
|
||||
fnamecmp = fname;
|
||||
} else
|
||||
fnamecmp = partialptr = fname;
|
||||
|
||||
if (inplace && make_backups) {
|
||||
if (!(fnamecmp = get_backup_name(fname)))
|
||||
fnamecmp = partialptr;
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if ((fd1 == -1) && (compare_dest != NULL)) {
|
||||
if (fd1 == -1 && fnamecmp != fname) {
|
||||
fnamecmp = fname;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 == -1 && compare_dest != NULL) {
|
||||
/* try the file at compare_dest instead */
|
||||
snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
|
||||
compare_dest,fname);
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
compare_dest, fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
|
||||
rprintf(FERROR, "fstat %s failed: %s\n",
|
||||
full_fname(fnamecmp), strerror(errno));
|
||||
receive_data(f_in,NULL,-1,NULL,file->length);
|
||||
rsyserr(FERROR, errno, "fstat %s failed",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
@@ -429,7 +471,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
*/
|
||||
rprintf(FERROR,"recv_files: %s is a directory\n",
|
||||
full_fname(fnamecmp));
|
||||
receive_data(f_in, NULL, -1, NULL, file->length);
|
||||
discard_receive_data(f_in, file->length);
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
@@ -437,7 +479,6 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
|
||||
close(fd1);
|
||||
fd1 = -1;
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !preserve_perms) {
|
||||
@@ -447,103 +488,127 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
file->mode = st.st_mode;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && st.st_size > 0) {
|
||||
buf = map_file(fd1,st.st_size);
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
|
||||
/* We now check to see if we are writing file "inplace" */
|
||||
if (inplace) {
|
||||
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0);
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "open %s failed",
|
||||
full_fname(fname));
|
||||
discard_receive_data(f_in, file->length);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
buf = NULL;
|
||||
}
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
discard_receive_data(f_in, file->length);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
if (buf) unmap_file(buf);
|
||||
if (fd1 != -1) close(fd1);
|
||||
continue;
|
||||
}
|
||||
strlcpy(template, fnametmp, sizeof template);
|
||||
|
||||
strlcpy(template, fnametmp, sizeof(template));
|
||||
|
||||
/* we initially set the perms without the
|
||||
* setuid/setgid bits to ensure that there is no race
|
||||
* condition. They are then correctly updated after
|
||||
* the lchown. Thanks to snabb@epipe.fi for pointing
|
||||
* this out. We also set it initially without group
|
||||
* access because of a similar race condition. */
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
|
||||
/* in most cases parent directories will already exist
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT &&
|
||||
create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof(fnametmp));
|
||||
/* we initially set the perms without the
|
||||
* setuid/setgid bits to ensure that there is no race
|
||||
* condition. They are then correctly updated after
|
||||
* the lchown. Thanks to snabb@epipe.fi for pointing
|
||||
* this out. We also set it initially without group
|
||||
* access because of a similar race condition. */
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rprintf(FERROR, "mkstemp %s failed: %s\n",
|
||||
full_fname(fnametmp), strerror(errno));
|
||||
receive_data(f_in,buf,-1,NULL,file->length);
|
||||
if (buf) unmap_file(buf);
|
||||
if (fd1 != -1) close(fd1);
|
||||
continue;
|
||||
|
||||
/* in most cases parent directories will already exist
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT
|
||||
&& create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof fnametmp);
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "mkstemp %s failed",
|
||||
full_fname(fnametmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (partialptr)
|
||||
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
|
||||
}
|
||||
|
||||
cleanup_set(fnametmp, fname, file, buf, fd1, fd2);
|
||||
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
}
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname));
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in,buf,fd2,fname,file->length);
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
fname, fd2, file->length);
|
||||
|
||||
log_recv(file, &initial_stats);
|
||||
|
||||
if (buf) unmap_file(buf);
|
||||
if (fd1 != -1) {
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (close(fd2) < 0) {
|
||||
rsyserr(FERROR, errno, "close failed on %s",
|
||||
full_fname(fnametmp));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
close(fd2);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
|
||||
if (recv_ok || inplace)
|
||||
finish_transfer(fname, fnametmp, file, recv_ok);
|
||||
else if (keep_partial && partialptr
|
||||
&& handle_partial_dir(partialptr, PDIR_CREATE))
|
||||
finish_transfer(partialptr, fnametmp, file, 0);
|
||||
else {
|
||||
partialptr = NULL;
|
||||
do_unlink(fnametmp);
|
||||
}
|
||||
|
||||
finish_transfer(fname, fnametmp, file);
|
||||
if (partialptr != fname && fnamecmp == partialptr && recv_ok) {
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
|
||||
cleanup_disable();
|
||||
|
||||
if (!recv_ok) {
|
||||
if (csum_length == SUM_LENGTH) {
|
||||
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
|
||||
write_int(f_gen,i);
|
||||
int msgtype = csum_length == SUM_LENGTH || read_batch ?
|
||||
FERROR : FINFO;
|
||||
if (msgtype == FERROR || verbose) {
|
||||
char *errstr, *redostr, *keptstr;
|
||||
if (!(keep_partial && partialptr) && !inplace)
|
||||
keptstr = "discarded";
|
||||
else if (partial_dir)
|
||||
keptstr = "put into partial-dir";
|
||||
else
|
||||
keptstr = "retained";
|
||||
if (msgtype == FERROR) {
|
||||
errstr = "ERROR";
|
||||
redostr = "";
|
||||
} else {
|
||||
errstr = "WARNING";
|
||||
redostr = " (will try again)";
|
||||
}
|
||||
rprintf(msgtype,
|
||||
"%s: %s failed verification -- update %s%s.\n",
|
||||
errstr, safe_fname(fname),
|
||||
keptstr, redostr);
|
||||
}
|
||||
if (csum_length != SUM_LENGTH) {
|
||||
char buf[4];
|
||||
SIVAL(buf, 0, i);
|
||||
send_msg(MSG_REDO, buf, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
|
||||
if (delete_after) {
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
if (preserve_hard_links)
|
||||
do_hard_links();
|
||||
|
||||
/* now we need to fix any directory permissions that were
|
||||
* modified during the transfer */
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
file = flist->files[i];
|
||||
if (!file->basename || !S_ISDIR(file->mode)) continue;
|
||||
recv_generator(local_name?local_name:f_name(file),flist,i,-1);
|
||||
}
|
||||
if (delete_after && recurse && !local_name && flist->count > 0)
|
||||
delete_files(flist);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files finished\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
210
rsync.c
210
rsync.c
@@ -26,10 +26,16 @@ extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int preserve_times;
|
||||
extern int am_root;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_perms;
|
||||
extern int force_delete;
|
||||
extern int recurse;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern char *backup_dir;
|
||||
extern int inplace;
|
||||
|
||||
|
||||
/*
|
||||
@@ -51,59 +57,57 @@ int delete_file(char *fname)
|
||||
DIR *d;
|
||||
struct dirent *di;
|
||||
char buf[MAXPATHLEN];
|
||||
extern int force_delete;
|
||||
STRUCT_STAT st;
|
||||
int ret;
|
||||
extern int recurse;
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
ret = do_lstat(fname, &st);
|
||||
#else
|
||||
ret = do_stat(fname, &st);
|
||||
#endif
|
||||
if (ret) {
|
||||
if (ret)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
if (robust_unlink(fname) == 0 || errno == ENOENT) return 0;
|
||||
rprintf(FERROR, "delete_file: unlink %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (robust_unlink(fname) == 0 || errno == ENOENT)
|
||||
return 0;
|
||||
rsyserr(FERROR, errno, "delete_file: unlink %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
|
||||
if (!force_delete || !recurse ||
|
||||
(errno != ENOTEMPTY && errno != EEXIST)) {
|
||||
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (do_rmdir(fname) == 0 || errno == ENOENT)
|
||||
return 0;
|
||||
if (!force_delete || !recurse
|
||||
|| (errno != ENOTEMPTY && errno != EEXIST)) {
|
||||
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now we do a recsursive delete on the directory ... */
|
||||
d = opendir(fname);
|
||||
if (!d) {
|
||||
rprintf(FERROR, "delete_file: opendir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (!(d = opendir(fname))) {
|
||||
rsyserr(FERROR, errno, "delete_file: opendir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
|
||||
char *dname = d_name(di);
|
||||
if (strcmp(dname,".") == 0
|
||||
|| strcmp(dname,"..") == 0)
|
||||
if (dname[0] == '.' && (dname[1] == '\0'
|
||||
|| (dname[1] == '.' && dname[2] == '\0')))
|
||||
continue;
|
||||
snprintf(buf, sizeof(buf), "%s/%s", fname, dname);
|
||||
pathjoin(buf, sizeof buf, fname, dname);
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"deleting %s\n", buf);
|
||||
rprintf(FINFO, "deleting %s\n", safe_fname(buf));
|
||||
if (delete_file(buf) != 0) {
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (errno) {
|
||||
rprintf(FERROR, "delete_file: readdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: readdir %s failed",
|
||||
full_fname(fname));
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
@@ -111,103 +115,81 @@ int delete_file(char *fname)
|
||||
closedir(d);
|
||||
|
||||
if (do_rmdir(fname) != 0) {
|
||||
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_in_group(gid_t gid)
|
||||
{
|
||||
#ifdef GETGROUPS_T
|
||||
static gid_t last_in = (gid_t) -2, last_out;
|
||||
static int ngroups = -2;
|
||||
static GETGROUPS_T *gidset;
|
||||
int n;
|
||||
|
||||
if (gid == last_in)
|
||||
return last_out;
|
||||
if (ngroups < -1) {
|
||||
/* treat failure (-1) as if not member of any group */
|
||||
ngroups = getgroups(0, 0);
|
||||
if (ngroups > 0) {
|
||||
gidset = new_array(GETGROUPS_T, ngroups);
|
||||
ngroups = getgroups(ngroups, gidset);
|
||||
}
|
||||
}
|
||||
|
||||
last_in = gid;
|
||||
last_out = 0;
|
||||
for (n = 0; n < ngroups; n++) {
|
||||
if (gidset[n] == gid) {
|
||||
last_out = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return last_out;
|
||||
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
int report)
|
||||
int flags)
|
||||
{
|
||||
int updated = 0;
|
||||
STRUCT_STAT st2;
|
||||
int change_uid, change_gid;
|
||||
|
||||
if (dry_run) return 0;
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
if (!st) {
|
||||
if (link_stat(fname,&st2) != 0) {
|
||||
rprintf(FERROR, "stat %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (link_stat(fname, &st2, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
st = &st2;
|
||||
}
|
||||
|
||||
if (preserve_times && !S_ISLNK(st->st_mode) &&
|
||||
cmp_modtime(st->st_mtime, file->modtime) != 0) {
|
||||
if (!preserve_times || S_ISLNK(st->st_mode)
|
||||
|| (make_backups && !backup_dir && S_ISDIR(st->st_mode)))
|
||||
flags |= PERMS_SKIP_MTIME;
|
||||
if (!(flags & PERMS_SKIP_MTIME)
|
||||
&& cmp_modtime(st->st_mtime, file->modtime) != 0) {
|
||||
/* don't complain about not setting times on directories
|
||||
because some filesystems can't do it */
|
||||
* because some filesystems can't do it */
|
||||
if (set_modtime(fname,file->modtime) != 0 &&
|
||||
!S_ISDIR(st->st_mode)) {
|
||||
rprintf(FERROR, "failed to set times on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to set times on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
} else {
|
||||
updated = 1;
|
||||
}
|
||||
updated = 1;
|
||||
}
|
||||
|
||||
change_uid = am_root && preserve_uid && st->st_uid != file->uid;
|
||||
change_gid = preserve_gid && file->gid != (gid_t) -1 && \
|
||||
st->st_gid != file->gid;
|
||||
if (change_gid && !am_root) {
|
||||
/* enforce bsd-style group semantics: non-root can only
|
||||
change to groups that the user is a member of */
|
||||
change_gid = is_in_group(file->gid);
|
||||
}
|
||||
change_gid = preserve_gid && file->gid != GID_NONE
|
||||
&& st->st_gid != file->gid;
|
||||
if (change_uid || change_gid) {
|
||||
if (verbose > 2) {
|
||||
if (change_uid) {
|
||||
rprintf(FINFO,
|
||||
"set uid of %s from %ld to %ld\n",
|
||||
fname, (long)st->st_uid, (long)file->uid);
|
||||
}
|
||||
if (change_gid) {
|
||||
rprintf(FINFO,
|
||||
"set gid of %s from %ld to %ld\n",
|
||||
fname, (long)st->st_gid, (long)file->gid);
|
||||
}
|
||||
}
|
||||
if (do_lchown(fname,
|
||||
change_uid?file->uid:st->st_uid,
|
||||
change_gid?file->gid:st->st_gid) != 0) {
|
||||
change_uid ? file->uid : st->st_uid,
|
||||
change_gid ? file->gid : st->st_gid) != 0) {
|
||||
/* shouldn't have attempted to change uid or gid
|
||||
unless have the privilege */
|
||||
rprintf(FERROR, "chown %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
* unless have the privilege */
|
||||
rsyserr(FERROR, errno, "%s %s failed",
|
||||
change_uid ? "chown" : "chgrp",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
/* a lchown had been done - we have to re-stat if the
|
||||
destination had the setuid or setgid bits set due
|
||||
to the side effect of the chown call */
|
||||
* destination had the setuid or setgid bits set due
|
||||
* to the side effect of the chown call */
|
||||
if (st->st_mode & (S_ISUID | S_ISGID)) {
|
||||
link_stat(fname, st);
|
||||
link_stat(fname, st,
|
||||
keep_dirlinks && S_ISDIR(st->st_mode));
|
||||
}
|
||||
updated = 1;
|
||||
}
|
||||
@@ -217,15 +199,15 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
|
||||
updated = 1;
|
||||
if (do_chmod(fname,(file->mode & CHMOD_BITS)) != 0) {
|
||||
rprintf(FERROR, "failed to set permissions on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to set permissions on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (verbose > 1 && report) {
|
||||
if (verbose > 1 && flags & PERMS_REPORT) {
|
||||
if (updated)
|
||||
rprintf(FINFO,"%s\n",fname);
|
||||
else
|
||||
@@ -252,29 +234,43 @@ void sig_int(void)
|
||||
|
||||
/* finish off a file transfer, renaming the file and setting the permissions
|
||||
and ownership */
|
||||
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
|
||||
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
|
||||
int ok_to_set_time)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inplace) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "finishing %s\n", fname);
|
||||
goto do_set_perms;
|
||||
}
|
||||
|
||||
if (make_backups && !make_backup(fname))
|
||||
return;
|
||||
|
||||
/* Change permissions before putting the file into place. */
|
||||
set_perms(fnametmp, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
|
||||
|
||||
/* move tmp file over real file */
|
||||
if (robust_rename(fnametmp,fname) != 0) {
|
||||
if (errno == EXDEV) {
|
||||
/* rename failed on cross-filesystem link.
|
||||
Copy the file instead. */
|
||||
if (copy_file(fnametmp,fname, file->mode & INITACCESSPERMS)) {
|
||||
rprintf(FERROR, "copy %s -> \"%s\": %s\n",
|
||||
full_fname(fnametmp), fname,
|
||||
strerror(errno));
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
}
|
||||
} else {
|
||||
rprintf(FERROR,"rename %s -> \"%s\": %s\n",
|
||||
full_fname(fnametmp), fname, strerror(errno));
|
||||
}
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
|
||||
ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR, errno, "%s %s -> \"%s\"",
|
||||
ret == -2 ? "copy" : "rename",
|
||||
full_fname(fnametmp), fname);
|
||||
do_unlink(fnametmp);
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
return;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* The file was moved into place (not copied), so it's done. */
|
||||
return;
|
||||
}
|
||||
do_set_perms:
|
||||
set_perms(fname, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
{
|
||||
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
|
||||
}
|
||||
|
||||
220
rsync.h
220
rsync.h
@@ -27,7 +27,7 @@
|
||||
#define RSYNC_RSH_IO_ENV "RSYNC_RSH_IO"
|
||||
|
||||
#define RSYNC_NAME "rsync"
|
||||
#define RSYNCD_SYSCONF "/etc/rsyncd.conf"
|
||||
/* RSYNCD_SYSCONF is now set in config.h */
|
||||
#define RSYNCD_USERCONF "rsyncd.conf"
|
||||
|
||||
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
|
||||
@@ -39,19 +39,30 @@
|
||||
incompatible with older versions :-( */
|
||||
#define CHAR_OFFSET 0
|
||||
|
||||
/* These flags are only used during the flist transfer. */
|
||||
|
||||
#define FLAG_DELETE (1<<0)
|
||||
#define SAME_MODE (1<<1)
|
||||
#define SAME_RDEV (1<<2)
|
||||
#define SAME_UID (1<<3)
|
||||
#define SAME_GID (1<<4)
|
||||
#define SAME_DIR (1<<5)
|
||||
#define SAME_NAME SAME_DIR
|
||||
#define LONG_NAME (1<<6)
|
||||
#define SAME_TIME (1<<7)
|
||||
#define XMIT_TOP_DIR (1<<0)
|
||||
#define XMIT_SAME_MODE (1<<1)
|
||||
#define XMIT_EXTENDED_FLAGS (1<<2)
|
||||
#define XMIT_SAME_RDEV_pre28 XMIT_EXTENDED_FLAGS /* Only in protocols < 28 */
|
||||
#define XMIT_SAME_UID (1<<3)
|
||||
#define XMIT_SAME_GID (1<<4)
|
||||
#define XMIT_SAME_NAME (1<<5)
|
||||
#define XMIT_LONG_NAME (1<<6)
|
||||
#define XMIT_SAME_TIME (1<<7)
|
||||
#define XMIT_SAME_RDEV_MAJOR (1<<8)
|
||||
#define XMIT_HAS_IDEV_DATA (1<<9)
|
||||
#define XMIT_SAME_DEV (1<<10)
|
||||
#define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
|
||||
|
||||
/* These flags are used in the live flist data. */
|
||||
|
||||
#define FLAG_TOP_DIR (1<<0)
|
||||
#define FLAG_HLINK_EOL (1<<1) /* generator only */
|
||||
#define FLAG_MOUNT_POINT (1<<2) /* sender only */
|
||||
|
||||
/* update this if you make incompatible changes */
|
||||
#define PROTOCOL_VERSION 27
|
||||
#define PROTOCOL_VERSION 28
|
||||
|
||||
/* We refuse to interoperate with versions that are not in this range.
|
||||
* Note that we assume we'll work with later versions: the onus is on
|
||||
@@ -70,8 +81,8 @@
|
||||
* unlikely to begin by sending a byte between MIN_PROTOCL_VERSION and
|
||||
* MAX_PROTOCOL_VERSION. */
|
||||
|
||||
#define MIN_PROTOCOL_VERSION 17
|
||||
#define OLD_PROTOCOL_VERSION 20
|
||||
#define MIN_PROTOCOL_VERSION 20
|
||||
#define OLD_PROTOCOL_VERSION 25
|
||||
#define MAX_PROTOCOL_VERSION 40
|
||||
|
||||
#define RSYNC_PORT 873
|
||||
@@ -93,16 +104,34 @@
|
||||
#define SERVER_EXCLUDES 1
|
||||
#define ALL_EXCLUDES 2
|
||||
|
||||
#define MISSING_OK 0
|
||||
#define MISSING_FATAL 1
|
||||
#define XFLG_FATAL_ERRORS (1<<0)
|
||||
#define XFLG_DEF_INCLUDE (1<<1)
|
||||
#define XFLG_WORDS_ONLY (1<<2)
|
||||
#define XFLG_WORD_SPLIT (1<<3)
|
||||
#define XFLG_DIRECTORY (1<<4)
|
||||
|
||||
#define ADD_INCLUDE 1
|
||||
#define ADD_EXCLUDE 0
|
||||
#define PERMS_REPORT (1<<0)
|
||||
#define PERMS_SKIP_MTIME (1<<1)
|
||||
|
||||
/* Log values. I *think* what these mean is: FLOG goes to the server
|
||||
* logfile; FERROR and FINFO try to end up on the client, with
|
||||
* different levels of filtering. */
|
||||
enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
|
||||
#define FULL_FLUSH 1
|
||||
#define NORMAL_FLUSH 0
|
||||
|
||||
#define PDIR_CREATE 1
|
||||
#define PDIR_DELETE 0
|
||||
|
||||
|
||||
/* Log-message categories. FLOG is only used on the daemon side to
|
||||
* output messages to the log file. */
|
||||
enum logcode { FERROR=1, FINFO=2, FLOG=3 };
|
||||
|
||||
/* Messages types that are sent over the message channel. The logcode
|
||||
* values must all be present here with identical numbers. */
|
||||
enum msgcode {
|
||||
MSG_DONE=5, /* current phase is done */
|
||||
MSG_REDO=4, /* reprocess indicated flist index */
|
||||
MSG_ERROR=FERROR, MSG_INFO=FINFO, MSG_LOG=FLOG, /* remote logging */
|
||||
MSG_DATA=0 /* raw data on the multiplexed stream */
|
||||
};
|
||||
|
||||
#include "errcode.h"
|
||||
|
||||
@@ -224,12 +253,19 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#elif MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_COMPAT_H
|
||||
#include <compat.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "lib/pool_alloc.h"
|
||||
|
||||
#define BOOL int
|
||||
|
||||
@@ -280,7 +316,7 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
|
||||
#else
|
||||
/* As long as it gets... */
|
||||
#define int64 off_t
|
||||
#define NO_INT64
|
||||
#define INT64_IS_OFF_T
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_LONG == 8)
|
||||
@@ -316,17 +352,14 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
|
||||
* device numbers will be truncated. But it's a kind of silly thing
|
||||
* to do anyhow.
|
||||
*
|
||||
* FIXME: In future, we should probable split the device number into
|
||||
* major/minor, and transfer the two parts as 32-bit ints. That gives
|
||||
* you somewhat more of a chance that they'll come from a big machine
|
||||
* to a little one in a useful way.
|
||||
*
|
||||
* FIXME: Really we need an unsigned type, and we perhaps ought to
|
||||
* cope with platforms on which this is an unsigned int or even a
|
||||
* struct. Later.
|
||||
* FIXME: I don't think the code in flist.c has ever worked on a system
|
||||
* where dev_t is a struct.
|
||||
*/
|
||||
#define INO64_T uint64
|
||||
#define DEV64_T uint64
|
||||
|
||||
struct idev {
|
||||
uint64 inode;
|
||||
uint64 dev;
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
@@ -362,69 +395,98 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 };
|
||||
#define IN_LOOPBACKNET 127
|
||||
#endif
|
||||
|
||||
#define GID_NONE ((gid_t)-1)
|
||||
|
||||
#define HL_CHECK_MASTER 0
|
||||
#define HL_SKIP 1
|
||||
|
||||
struct hlink {
|
||||
int hlindex;
|
||||
struct file_struct *next;
|
||||
};
|
||||
|
||||
#define F_DEV link_u.idev->dev
|
||||
#define F_INODE link_u.idev->inode
|
||||
|
||||
#define F_HLINDEX link_u.links->hlindex
|
||||
#define F_NEXT link_u.links->next
|
||||
|
||||
struct file_struct {
|
||||
unsigned flags;
|
||||
time_t modtime;
|
||||
union {
|
||||
dev_t rdev; /* The device number, if this is a device */
|
||||
char *sum; /* Only a normal file can have a checksum */
|
||||
char *link; /* Points to symlink string, if a symlink */
|
||||
} u;
|
||||
OFF_T length;
|
||||
mode_t mode;
|
||||
|
||||
INO64_T inode;
|
||||
/** Device this file lives upon */
|
||||
DEV64_T dev;
|
||||
|
||||
/** If this is a device node, the device number. */
|
||||
DEV64_T rdev;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char *basename;
|
||||
char *dirname;
|
||||
char *basedir;
|
||||
char *link;
|
||||
char *sum;
|
||||
union {
|
||||
struct idev *idev;
|
||||
struct hlink *links;
|
||||
} link_u;
|
||||
time_t modtime;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
uchar flags; /* this item MUST remain last */
|
||||
};
|
||||
|
||||
/*
|
||||
* Start the flist array at FLIST_START entries and grow it
|
||||
* by doubling until FLIST_LINEAR then grow by FLIST_LINEAR
|
||||
*/
|
||||
#define FLIST_START (32 * 1024)
|
||||
#define FLIST_LINEAR (FLIST_START * 512)
|
||||
|
||||
#define ARENA_SIZE (32 * 1024)
|
||||
/*
|
||||
* Extent size for allocation pools A minimum size of 128KB
|
||||
* is needed to mmap them so that freeing will release the
|
||||
* space to the OS.
|
||||
*
|
||||
* Larger sizes reduce leftover fragments and speed free calls
|
||||
* (when they happen) Smaller sizes increase the chance of
|
||||
* freed allocations freeing whole extents.
|
||||
*/
|
||||
#define FILE_EXTENT (256 * 1024)
|
||||
#define HLINK_EXTENT (128 * 1024)
|
||||
|
||||
struct string_area {
|
||||
char *base;
|
||||
char *end;
|
||||
char *current;
|
||||
struct string_area *next;
|
||||
};
|
||||
#define WITH_HLINK 1
|
||||
#define WITHOUT_HLINK 0
|
||||
|
||||
struct file_list {
|
||||
int count;
|
||||
int malloced;
|
||||
alloc_pool_t file_pool;
|
||||
alloc_pool_t hlink_pool;
|
||||
struct file_struct **files;
|
||||
struct string_area *string_area;
|
||||
};
|
||||
|
||||
#define SUMFLG_SAME_OFFSET (1<<0)
|
||||
|
||||
struct sum_buf {
|
||||
OFF_T offset; /**< offset in file of this chunk */
|
||||
int len; /**< length of chunk of file */
|
||||
int i; /**< index of this chunk */
|
||||
unsigned int len; /**< length of chunk of file */
|
||||
uint32 sum1; /**< simple checksum */
|
||||
short flags; /**< flag bits */
|
||||
char sum2[SUM_LENGTH]; /**< checksum */
|
||||
};
|
||||
|
||||
struct sum_struct {
|
||||
OFF_T flength; /**< total file length */
|
||||
size_t count; /**< how many chunks */
|
||||
size_t remainder; /**< flength % block_length */
|
||||
size_t blength; /**< block_length */
|
||||
size_t s2length; /**< sum2_length */
|
||||
unsigned int blength; /**< block_length */
|
||||
unsigned int remainder; /**< flength % block_length */
|
||||
int s2length; /**< sum2_length */
|
||||
struct sum_buf *sums; /**< points to info for each chunk */
|
||||
};
|
||||
|
||||
struct map_struct {
|
||||
char *p; /* Window pointer */
|
||||
int fd; /* File Descriptor */
|
||||
int p_size; /* Window size at allocation */
|
||||
int p_len; /* Window size after fill */
|
||||
/* p_size and p_len could be
|
||||
* consolodated by using a local
|
||||
* variable in map_ptr() */
|
||||
int p_size; /* Largest window size we allocated */
|
||||
int p_len; /* Latest (rounded) window size */
|
||||
int def_window_size; /* Default window size */
|
||||
int status; /* first errno from read errors */
|
||||
OFF_T file_size; /* File size (from stat) */
|
||||
OFF_T p_offset; /* Window start */
|
||||
@@ -435,14 +497,22 @@ struct map_struct {
|
||||
#define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */
|
||||
#define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with '**' */
|
||||
#define MATCHFLG_ABS_PATH (1<<3) /* path-match on absolute path */
|
||||
#define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
|
||||
#define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */
|
||||
#define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */
|
||||
struct exclude_struct {
|
||||
struct exclude_struct *next;
|
||||
char *pattern;
|
||||
int match_flags;
|
||||
int include;
|
||||
int directory;
|
||||
unsigned int match_flags;
|
||||
int slash_cnt;
|
||||
};
|
||||
|
||||
struct exclude_list_struct {
|
||||
struct exclude_struct *head;
|
||||
struct exclude_struct *tail;
|
||||
char *debug_type;
|
||||
};
|
||||
|
||||
struct stats {
|
||||
int64 total_size;
|
||||
int64 total_transferred_size;
|
||||
@@ -453,6 +523,7 @@ struct stats {
|
||||
int flist_size;
|
||||
int num_files;
|
||||
int num_transferred_files;
|
||||
int current_file_index;
|
||||
};
|
||||
|
||||
|
||||
@@ -535,6 +606,10 @@ extern int errno;
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0400
|
||||
#endif
|
||||
|
||||
#ifndef S_IWUSR
|
||||
#define S_IWUSR 0200
|
||||
#endif
|
||||
@@ -667,6 +742,17 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
|
||||
|
||||
#define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__)
|
||||
|
||||
#ifdef HAVE_GETEUID
|
||||
#define MY_UID() geteuid()
|
||||
#else
|
||||
#define MY_UID() getuid()
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETEGID
|
||||
#define MY_GID() getegid()
|
||||
#else
|
||||
#define MY_GID() getgid()
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
|
||||
|
||||
115
rsyncd.conf.yo
115
rsyncd.conf.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(26 Jan 2003)()()
|
||||
manpage(rsyncd.conf)(5)(30 Sep 2004)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync server)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -93,7 +93,7 @@ useful on systems (such as AIX) where syslog() doesn't work for
|
||||
chrooted programs.
|
||||
|
||||
dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
|
||||
its process id to that file.
|
||||
its process ID to that file.
|
||||
|
||||
dit(bf(syslog facility)) The "syslog facility" option allows you to
|
||||
specify the syslog facility name to use when logging messages from the
|
||||
@@ -134,12 +134,31 @@ dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
|
||||
to the "path" before starting the file transfer with the client. This has
|
||||
the advantage of extra protection against possible implementation security
|
||||
holes, but it has the disadvantages of requiring super-user privileges,
|
||||
of not being able to follow symbolic links outside of the new root path
|
||||
when reading, and of implying the --numeric-ids option because /etc/passwd
|
||||
becomes inaccessible. When "use chroot" is false, for security reasons
|
||||
of not being able to follow symbolic links that are either absolute or outside
|
||||
of the new root path, and of complicating the preservation of usernames and groups
|
||||
(see below). When "use chroot" is false, for security reasons,
|
||||
symlinks may only be relative paths pointing to other files within the root
|
||||
path, and leading slashes are removed from absolute paths. The default for
|
||||
"use chroot" is true.
|
||||
path, and leading slashes are removed from most absolute paths (options
|
||||
such as --backup-dir, --compare-dest, etc. interpret an absolute path as
|
||||
rooted in the module's "path" dir, just as if chroot was specified).
|
||||
The default for "use chroot" is true.
|
||||
|
||||
In order to preserve usernames and groupnames, rsync needs to be able to
|
||||
use the standard library functions for looking up names and IDs (i.e.
|
||||
getpwuid(), getgrgid(), getpwname(), and getgrnam()). This means a
|
||||
process in the chroot namespace will need to have access to the resources
|
||||
used by these library functions (traditionally /etc/passwd and
|
||||
/etc/group). If these resources are not available, rsync will only be
|
||||
able to copy the IDs, just as if the --numeric-ids option had been
|
||||
specified.
|
||||
|
||||
Note that you are free to setup user/group information in the chroot area
|
||||
differently from your normal system. For example, you could abbreviate
|
||||
the list of users and groups. Also, you can protect this information from
|
||||
being downloaded/uploaded by adding an exclude rule to the rsync.conf file
|
||||
(e.g. "exclude = /etc/"). Note that having the exclusion affect uploads
|
||||
is a relatively new feature in rsync, so make sure your server is running
|
||||
at least 2.6.3 to effect this.
|
||||
|
||||
dit(bf(max connections)) The "max connections" option allows you to
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
@@ -159,40 +178,40 @@ attempted uploads will fail. If "read only" is false then uploads will
|
||||
be possible if file permissions on the server allow them. The default
|
||||
is for all modules to be read only.
|
||||
|
||||
dit(bf(write only)) The "write only" option determines whether clients
|
||||
will be able to download files or not. If "write only" is true then any
|
||||
attempted downloads will fail. If "write only" is false then downloads
|
||||
will be possible if file permissions on the server allow them. The
|
||||
default is for this option to be disabled.
|
||||
|
||||
dit(bf(list)) The "list" option determines if this module should be
|
||||
listed when the client asks for a listing of available modules. By
|
||||
setting this to false you can create hidden modules. The default is
|
||||
for modules to be listable.
|
||||
|
||||
dit(bf(uid)) The "uid" option specifies the user name or user id that
|
||||
dit(bf(uid)) The "uid" option specifies the user name or user ID that
|
||||
file transfers to and from that module should take place as when the daemon
|
||||
was run as root. In combination with the "gid" option this determines what
|
||||
file permissions are available. The default is uid -2, which is normally
|
||||
the user "nobody".
|
||||
|
||||
dit(bf(gid)) The "gid" option specifies the group name or group id that
|
||||
dit(bf(gid)) The "gid" option specifies the group name or group ID that
|
||||
file transfers to and from that module should take place as when the daemon
|
||||
was run as root. This complements the "uid" option. The default is gid -2,
|
||||
which is normally the group "nobody".
|
||||
|
||||
dit(bf(exclude)) The "exclude" option allows you to specify a space
|
||||
separated list of patterns to add to the exclude list.
|
||||
This is only superficially equivalent
|
||||
to the client specifying these patterns with the --exclude option.
|
||||
Only one "exclude" option may be specified, but
|
||||
you can use "-" and "+" before patterns to specify exclude/include.
|
||||
dit(bf(exclude)) The "exclude" option allows you to specify a
|
||||
space-separated list of patterns that the server will not allow to be read
|
||||
or written. This is only superficially equivalent to the client
|
||||
specifying these patterns with the --exclude option. Only one "exclude"
|
||||
option may be specified, but you can use "-" and "+" before patterns to
|
||||
specify exclude/include.
|
||||
|
||||
Because this exclude list is not passed to the client it only applies on
|
||||
the server: that is, it excludes files received by a client when receiving
|
||||
from a server and files deleted on a server when sending to a server, but
|
||||
it doesn't exclude files sent from a client when sending to a server or
|
||||
files deleted on a client when receiving from a server.
|
||||
|
||||
Note that this option is not designed with strong security in
|
||||
mind, it is quite possible that a client may find a way to bypass this
|
||||
exclude list. If you want to absolutely ensure that certain files
|
||||
cannot be accessed then use the uid/gid options in combination with
|
||||
file permissions.
|
||||
it doesn't exclude files from being deleted on a client when receiving
|
||||
from a server.
|
||||
|
||||
dit(bf(exclude from)) The "exclude from" option specifies a filename
|
||||
on the server that contains exclude patterns, one per line.
|
||||
@@ -200,14 +219,14 @@ This is only superficially equivalent
|
||||
to the client specifying the --exclude-from option with an equivalent file.
|
||||
See the "exclude" option above.
|
||||
|
||||
dit(bf(include)) The "include" option allows you to specify a space
|
||||
separated list of patterns which rsync should not exclude. This is
|
||||
only superficially equivalent to the client specifying these patterns
|
||||
with the --include option because it applies only on the server.
|
||||
This is useful as it
|
||||
allows you to build up quite complex exclude/include rules. Only one
|
||||
"include" option may be specified, but you can use "+" and "-" before
|
||||
patterns to switch include/exclude. See the "exclude" option above.
|
||||
dit(bf(include)) The "include" option allows you to specify a
|
||||
space-separated list of patterns which rsync should not exclude. This is
|
||||
only superficially equivalent to the client specifying these patterns with
|
||||
the --include option because it applies only on the server. This is
|
||||
useful as it allows you to build up quite complex exclude/include rules.
|
||||
Only one "include" option may be specified, but you can use "+" and "-"
|
||||
before patterns to switch include/exclude. See the "exclude" option
|
||||
above.
|
||||
|
||||
dit(bf(include from)) The "include from" option specifies a filename
|
||||
on the server that contains include patterns, one per line. This is
|
||||
@@ -216,7 +235,7 @@ only superficially equivalent to the client specifying the
|
||||
See the "exclude" option above.
|
||||
|
||||
dit(bf(auth users)) The "auth users" option specifies a comma and
|
||||
space separated list of usernames that will be allowed to connect to
|
||||
space-separated list of usernames that will be allowed to connect to
|
||||
this module. The usernames do not need to exist on the local
|
||||
system. The usernames may also contain shell wildcard characters. If
|
||||
"auth users" is set then the client will be challenged to supply a
|
||||
@@ -229,7 +248,7 @@ connect without a password (this is called "anonymous rsync").
|
||||
See also the bf(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL
|
||||
PROGRAM) section in rsync(1) for information on how handle an
|
||||
rsyncd.conf-level username that differs from the remote-shell-level
|
||||
username when using a remote shell to connect to a rsync server.
|
||||
username when using a remote shell to connect to an rsync server.
|
||||
|
||||
dit(bf(secrets file)) The "secrets file" option specifies the name of
|
||||
a file that contains the username:password pairs used for
|
||||
@@ -247,7 +266,7 @@ by "other"; see "strict modes".
|
||||
|
||||
dit(bf(strict modes)) The "strict modes" option determines whether or not
|
||||
the permissions on the secrets file will be checked. If "strict modes" is
|
||||
true, then the secrets file must not be readable by any user id other
|
||||
true, then the secrets file must not be readable by any user ID other
|
||||
than the one that the rsync daemon is running under. If "strict modes" is
|
||||
false, the check is not performed. The default is true. This option
|
||||
was added to accommodate rsync running on the Windows operating system.
|
||||
@@ -306,10 +325,10 @@ rejected. See the "hosts allow" option for more information.
|
||||
The default is no "hosts deny" option, which means all hosts can connect.
|
||||
|
||||
dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to
|
||||
ignore IO errors on the server when deciding whether to run the delete
|
||||
ignore I/O errors on the server when deciding whether to run the delete
|
||||
phase of the transfer. Normally rsync skips the --delete step if any
|
||||
IO errors have occurred in order to prevent disasterous deletion due
|
||||
to a temporary resource shortage or other IO error. In some cases this
|
||||
I/O errors have occurred in order to prevent disasterous deletion due
|
||||
to a temporary resource shortage or other I/O error. In some cases this
|
||||
test is counter productive so you can use this option to turn off this
|
||||
behaviour.
|
||||
|
||||
@@ -334,7 +353,7 @@ itemize(
|
||||
it() %h for the remote host name
|
||||
it() %a for the remote IP address
|
||||
it() %l for the length of the file in bytes
|
||||
it() %p for the process id of this rsync session
|
||||
it() %p for the process ID of this rsync session
|
||||
it() %o for the operation, which is either "send" or "recv"
|
||||
it() %f for the filename
|
||||
it() %P for the module path
|
||||
@@ -353,16 +372,22 @@ A perl script called rsyncstats to summarize this format is included
|
||||
in the rsync source code distribution.
|
||||
|
||||
dit(bf(timeout)) The "timeout" option allows you to override the
|
||||
clients choice for IO timeout for this module. Using this option you
|
||||
clients choice for I/O timeout for this module. Using this option you
|
||||
can ensure that rsync won't wait on a dead client forever. The timeout
|
||||
is specified in seconds. A value of zero means no timeout and is the
|
||||
default. A good choice for anonymous rsync servers may be 600 (giving
|
||||
a 10 minute timeout).
|
||||
|
||||
dit(bf(refuse options)) The "refuse options" option allows you to
|
||||
specify a space separated list of rsync command line options that will
|
||||
be refused by your rsync server. The full names of the options must be
|
||||
used (i.e., you must use "checksum" not "c" to disable checksumming).
|
||||
specify a space-separated list of rsync command line options that will
|
||||
be refused by your rsync server.
|
||||
You may specify the full option name, its one-letter abbreviation, or a
|
||||
wild-card string that matches multiple options.
|
||||
For example, this would refuse --checksum (-c) and all the options that
|
||||
start with "delete":
|
||||
|
||||
quote(refuse options = c delete*)
|
||||
|
||||
When an option is refused, the server prints an error message and exits.
|
||||
To prevent all compression, you can use "dont compress = *" (see below)
|
||||
instead of "refuse options = compress" to avoid returning an error to a
|
||||
@@ -374,7 +399,7 @@ during transfer. Compression is expensive in terms of CPU usage so it
|
||||
is usually good to not try to compress files that won't compress well,
|
||||
such as already compressed files.
|
||||
|
||||
The "dont compress" option takes a space separated list of
|
||||
The "dont compress" option takes a space-separated list of
|
||||
case-insensitive wildcard patterns. Any source filename matching one
|
||||
of the patterns will not be compressed during transfer.
|
||||
|
||||
@@ -415,7 +440,7 @@ where command would be
|
||||
quote(rsync --server --daemon .)
|
||||
|
||||
NOTE: rsync's argument parsing expects the trailing ".", so make sure
|
||||
that it's there. If you want to use a rsyncd.conf(5)-style
|
||||
that it's there. If you want to use an rsyncd.conf(5)-style
|
||||
configuration file other than the default, you can added a
|
||||
--config option to the em(command):
|
||||
|
||||
@@ -494,7 +519,7 @@ Please report bugs! The rsync bug tracking system is online at
|
||||
url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
This man page is current for version 2.0 of rsync
|
||||
This man page is current for version 2.x of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ echo "$0 running in `pwd`"
|
||||
echo " rsync_bin=$rsync_bin"
|
||||
echo " srcdir=$srcdir"
|
||||
|
||||
testuser=`whoami || echo UNKNOWN`
|
||||
testuser=`id -un || whoami || echo UNKNOWN`
|
||||
|
||||
echo " testuser=$testuser"
|
||||
echo " os=`uname -a`"
|
||||
@@ -220,6 +220,11 @@ do
|
||||
echo "----- $testbase log follows"
|
||||
cat "$scratchdir/test.log"
|
||||
echo "----- $testbase log ends"
|
||||
if [ -f "$scratchdir/rsyncd.log" ]; then
|
||||
echo "----- $testbase rsyncd.log follows"
|
||||
cat "$scratchdir/rsyncd.log"
|
||||
echo "----- $testbase rsyncd.log ends"
|
||||
fi
|
||||
fi
|
||||
|
||||
case $result in
|
||||
|
||||
261
sender.c
261
sender.c
@@ -25,6 +25,10 @@ extern struct stats stats;
|
||||
extern int io_error;
|
||||
extern int dry_run;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int protocol_version;
|
||||
extern int make_backups;
|
||||
extern struct stats stats;
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,12 +38,8 @@ extern int am_server;
|
||||
* and transmits them to the receiver. The sender process runs on the
|
||||
* machine holding the source files.
|
||||
**/
|
||||
|
||||
|
||||
void read_sum_head(int f, struct sum_struct *sum)
|
||||
{
|
||||
extern int protocol_version;
|
||||
|
||||
sum->count = read_int(f);
|
||||
sum->blength = read_int(f);
|
||||
if (protocol_version < 27) {
|
||||
@@ -47,8 +47,8 @@ void read_sum_head(int f, struct sum_struct *sum)
|
||||
} else {
|
||||
sum->s2length = read_int(f);
|
||||
if (sum->s2length > MD4_SUM_LENGTH) {
|
||||
rprintf(FERROR, "Invalid checksum length %d\n",
|
||||
sum->s2length);
|
||||
rprintf(FERROR, "Invalid checksum length %ld\n",
|
||||
(long)sum->s2length);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
@@ -64,41 +64,43 @@ static struct sum_struct *receive_sums(int f)
|
||||
int i;
|
||||
OFF_T offset = 0;
|
||||
|
||||
s = new(struct sum_struct);
|
||||
if (!s) out_of_memory("receive_sums");
|
||||
if (!(s = new(struct sum_struct)))
|
||||
out_of_memory("receive_sums");
|
||||
|
||||
read_sum_head(f, s);
|
||||
|
||||
s->sums = NULL;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "count=%ld n=%ld rem=%ld\n",
|
||||
(long) s->count, (long) s->blength,
|
||||
(long) s->remainder);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "count=%ld n=%u rem=%u\n",
|
||||
(long)s->count, s->blength, s->remainder);
|
||||
}
|
||||
|
||||
if (s->count == 0)
|
||||
return(s);
|
||||
|
||||
s->sums = new_array(struct sum_buf, s->count);
|
||||
if (!s->sums) out_of_memory("receive_sums");
|
||||
if (!(s->sums = new_array(struct sum_buf, s->count)))
|
||||
out_of_memory("receive_sums");
|
||||
|
||||
for (i = 0; i < (int) s->count; i++) {
|
||||
for (i = 0; i < (int)s->count; i++) {
|
||||
s->sums[i].sum1 = read_int(f);
|
||||
read_buf(f, s->sums[i].sum2, s->s2length);
|
||||
|
||||
s->sums[i].offset = offset;
|
||||
s->sums[i].i = i;
|
||||
s->sums[i].flags = 0;
|
||||
|
||||
if (i == (int) s->count-1 && s->remainder != 0) {
|
||||
if (i == (int)s->count-1 && s->remainder != 0)
|
||||
s->sums[i].len = s->remainder;
|
||||
} else {
|
||||
else
|
||||
s->sums[i].len = s->blength;
|
||||
}
|
||||
offset += s->sums[i].len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
i, s->sums[i].len, (double)s->sums[i].offset, s->sums[i].sum1);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
i, s->sums[i].len, (double)s->sums[i].offset,
|
||||
s->sums[i].sum1);
|
||||
}
|
||||
}
|
||||
|
||||
s->flength = offset;
|
||||
@@ -112,27 +114,21 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
{
|
||||
int fd = -1;
|
||||
struct sum_struct *s;
|
||||
struct map_struct *buf = NULL;
|
||||
struct map_struct *mbuf = NULL;
|
||||
STRUCT_STAT st;
|
||||
char fname[MAXPATHLEN];
|
||||
char *fname2, fname[MAXPATHLEN];
|
||||
int i;
|
||||
struct file_struct *file;
|
||||
int phase = 0;
|
||||
extern struct stats stats;
|
||||
struct stats initial_stats;
|
||||
extern int write_batch; /* dw */
|
||||
extern int read_batch; /* dw */
|
||||
int checksums_match; /* dw */
|
||||
int buff_len; /* dw */
|
||||
char buff[CHUNK_SIZE]; /* dw */
|
||||
int j; /* dw */
|
||||
int done; /* dw */
|
||||
int save_make_backups = make_backups;
|
||||
int j;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files starting\n");
|
||||
|
||||
while (1) {
|
||||
int offset = 0;
|
||||
unsigned int offset;
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
@@ -142,6 +138,9 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
write_int(f_out, -1);
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files phase=%d\n", phase);
|
||||
/* For inplace: redo phase turns off the backup
|
||||
* flag so that we do a regular inplace send. */
|
||||
make_backups = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -155,157 +154,111 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
|
||||
file = flist->files[i];
|
||||
|
||||
stats.current_file_index = i;
|
||||
stats.num_transferred_files++;
|
||||
stats.total_transferred_size += file->length;
|
||||
|
||||
fname[0] = 0;
|
||||
if (file->basedir) {
|
||||
strlcpy(fname, file->basedir, MAXPATHLEN);
|
||||
if (strlen(fname) == MAXPATHLEN-1) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "send_files failed on long-named directory %s\n",
|
||||
full_fname(fname));
|
||||
return;
|
||||
}
|
||||
strlcat(fname, "/", MAXPATHLEN);
|
||||
offset = strlen(file->basedir)+1;
|
||||
}
|
||||
strlcat(fname, f_name(file), MAXPATHLEN);
|
||||
/* N.B. We're sure that this fits, so offset is OK. */
|
||||
offset = strlcpy(fname, file->basedir, sizeof fname);
|
||||
if (!offset || fname[offset-1] != '/')
|
||||
fname[offset++] = '/';
|
||||
} else
|
||||
offset = 0;
|
||||
fname2 = f_name_to(file, fname + offset);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
|
||||
|
||||
if (dry_run) {
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname+offset);
|
||||
}
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname2));
|
||||
write_int(f_out, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
initial_stats = stats;
|
||||
|
||||
s = receive_sums(f_in);
|
||||
if (!s) {
|
||||
if (!(s = receive_sums(f_in))) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "receive_sums failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (write_batch)
|
||||
write_batch_csum_info(&i, flist->count, s);
|
||||
|
||||
if (!read_batch) {
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(FINFO, "file has vanished: %s\n",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "send_files failed to open %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
}
|
||||
free_sums(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* map the local file */
|
||||
if (do_fstat(fd, &st) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "fstat failed: %s\n", strerror(errno));
|
||||
free_sums(s);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size > 0) {
|
||||
buf = map_file(fd, st.st_size);
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
enum logcode c = am_daemon
|
||||
&& protocol_version < 28 ? FERROR
|
||||
: FINFO;
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(c, "file has vanished: %s\n",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
buf = NULL;
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, errno,
|
||||
"send_files failed to open %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
|
||||
fname, (double)st.st_size);
|
||||
|
||||
write_int(f_out, i);
|
||||
|
||||
if (write_batch)
|
||||
write_batch_delta_file((char *)&i, sizeof(i));
|
||||
|
||||
write_sum_head(f_out, s);
|
||||
free_sums(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose > 2 && !read_batch)
|
||||
rprintf(FINFO, "calling match_sums %s\n", fname);
|
||||
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname+offset);
|
||||
/* map the local file */
|
||||
if (do_fstat(fd, &st) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, errno, "fstat failed");
|
||||
free_sums(s);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size) {
|
||||
OFF_T map_size = MAX(s->blength * 3, MAX_MAP_SIZE);
|
||||
mbuf = map_file(fd, st.st_size, map_size, s->blength);
|
||||
} else
|
||||
mbuf = NULL;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
|
||||
safe_fname(fname), (double)st.st_size);
|
||||
}
|
||||
|
||||
write_int(f_out, i);
|
||||
write_sum_head(f_out, s);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "calling match_sums %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname2));
|
||||
|
||||
set_compression(fname);
|
||||
|
||||
if (read_batch) { /* dw */
|
||||
/* read checksums originally computed on sender side */
|
||||
read_batch_csum_info(i, s, &checksums_match);
|
||||
if (checksums_match) {
|
||||
read_batch_delta_file( (char *) &j, sizeof(int) );
|
||||
if (j != i) { /* if flist index entries don't match*/
|
||||
rprintf(FINFO, "index mismatch in send_files\n");
|
||||
rprintf(FINFO, "read index = %d flist ndx = %d\n", j, i);
|
||||
close_batch_delta_file();
|
||||
close_batch_csums_file();
|
||||
exit_cleanup(1);
|
||||
} else {
|
||||
write_int(f_out, j);
|
||||
write_sum_head(f_out, s);
|
||||
done = 0;
|
||||
while (!done) {
|
||||
read_batch_delta_file( (char *) &buff_len, sizeof(int) );
|
||||
write_int(f_out, buff_len);
|
||||
if (buff_len == 0) {
|
||||
done = 1;
|
||||
} else {
|
||||
if (buff_len > 0) {
|
||||
read_batch_delta_file(buff, buff_len);
|
||||
write_buf(f_out, buff, buff_len);
|
||||
}
|
||||
}
|
||||
} /* end while */
|
||||
read_batch_delta_file( buff, MD4_SUM_LENGTH);
|
||||
write_buf(f_out, buff, MD4_SUM_LENGTH);
|
||||
match_sums(f_out, s, mbuf, st.st_size);
|
||||
log_send(file, &initial_stats);
|
||||
|
||||
} /* j=i */
|
||||
} else { /* not checksum match */
|
||||
rprintf (FINFO, "readbatch & checksums don't match\n");
|
||||
rprintf (FINFO, "filename=%s is being skipped\n", fname);
|
||||
continue;
|
||||
if (mbuf) {
|
||||
j = unmap_file(mbuf);
|
||||
if (j) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, j,
|
||||
"read errors mapping %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
} else {
|
||||
match_sums(f_out, s, buf, st.st_size);
|
||||
log_send(file, &initial_stats);
|
||||
}
|
||||
|
||||
if (!read_batch) { /* dw */
|
||||
if (buf) {
|
||||
j = unmap_file(buf);
|
||||
if (j) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR,
|
||||
"read errors mapping %s: (%d) %s\n",
|
||||
full_fname(fname), j, strerror(j));
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
free_sums(s);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "sender finished %s\n", fname);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "sender finished %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send files finished\n");
|
||||
@@ -313,14 +266,4 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
match_report();
|
||||
|
||||
write_int(f_out, -1);
|
||||
if (write_batch || read_batch) { /* dw */
|
||||
close_batch_csums_file();
|
||||
close_batch_delta_file();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
485
socket.c
485
socket.c
@@ -1,20 +1,20 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
|
||||
rsync -- fast file replication program
|
||||
|
||||
|
||||
Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
|
||||
Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/**
|
||||
* @file socket.c
|
||||
*
|
||||
*
|
||||
* Socket functions used in rsync.
|
||||
*
|
||||
* This file is now converted to use the new-style getaddrinfo()
|
||||
@@ -33,27 +33,51 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
|
||||
/**
|
||||
* Establish a proxy connection on an open socket to a web proxy by
|
||||
* using the HTTP CONNECT method.
|
||||
* using the CONNECT method. If proxy_user and proxy_pass are not NULL,
|
||||
* they are used to authenticate to the proxy using the "Basic"
|
||||
* proxy-authorization protocol
|
||||
**/
|
||||
static int establish_proxy_connection(int fd, char *host, int port)
|
||||
static int establish_proxy_connection(int fd, char *host, int port,
|
||||
char *proxy_user, char *proxy_pass)
|
||||
{
|
||||
char buffer[1024];
|
||||
char *cp;
|
||||
char *cp, buffer[1024];
|
||||
char *authhdr, authbuf[1024];
|
||||
int len;
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
|
||||
if (write(fd, buffer, strlen(buffer)) != (int) strlen(buffer)) {
|
||||
rprintf(FERROR, "failed to write to proxy: %s\n",
|
||||
strerror(errno));
|
||||
if (proxy_user && proxy_pass) {
|
||||
stringjoin(buffer, sizeof buffer,
|
||||
proxy_user, ":", proxy_pass, NULL);
|
||||
len = strlen(buffer);
|
||||
|
||||
if ((len*8 + 5) / 6 >= (int)sizeof authbuf) {
|
||||
rprintf(FERROR,
|
||||
"authentication information is too long\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
base64_encode(buffer, len, authbuf);
|
||||
authhdr = "\r\nProxy-Authorization: Basic ";
|
||||
} else {
|
||||
*authbuf = '\0';
|
||||
authhdr = "";
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n",
|
||||
host, port, authhdr, authbuf);
|
||||
len = strlen(buffer);
|
||||
if (write(fd, buffer, len) != len) {
|
||||
rsyserr(FERROR, errno, "failed to write to proxy");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
|
||||
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
|
||||
if (read(fd, cp, 1) != 1) {
|
||||
rprintf(FERROR, "failed to read from proxy: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to read from proxy");
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
@@ -70,8 +94,7 @@ static int establish_proxy_connection(int fd, char *host, int port)
|
||||
buffer);
|
||||
return -1;
|
||||
}
|
||||
for (cp = &buffer[5]; isdigit(* (unsigned char *) cp) || (*cp == '.'); cp++)
|
||||
;
|
||||
for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {}
|
||||
while (*cp == ' ')
|
||||
cp++;
|
||||
if (*cp != '2') {
|
||||
@@ -81,19 +104,18 @@ static int establish_proxy_connection(int fd, char *host, int port)
|
||||
}
|
||||
/* throw away the rest of the HTTP header */
|
||||
while (1) {
|
||||
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
|
||||
cp++) {
|
||||
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
|
||||
if (read(fd, cp, 1) != 1) {
|
||||
rprintf(FERROR, "failed to read from proxy: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to read from proxy");
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
break;
|
||||
}
|
||||
if ((cp > buffer) && (*cp == '\n'))
|
||||
if (cp > buffer && *cp == '\n')
|
||||
cp--;
|
||||
if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
|
||||
if (cp == buffer && (*cp == '\n' || *cp == '\r'))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@@ -104,14 +126,13 @@ static int establish_proxy_connection(int fd, char *host, int port)
|
||||
* Try to set the local address for a newly-created socket. Return -1
|
||||
* if this fails.
|
||||
**/
|
||||
int try_bind_local(int s,
|
||||
int ai_family, int ai_socktype,
|
||||
int try_bind_local(int s, int ai_family, int ai_socktype,
|
||||
const char *bind_address)
|
||||
{
|
||||
int error;
|
||||
struct addrinfo bhints, *bres_all, *r;
|
||||
|
||||
memset(&bhints, 0, sizeof(bhints));
|
||||
memset(&bhints, 0, sizeof bhints);
|
||||
bhints.ai_family = ai_family;
|
||||
bhints.ai_socktype = ai_socktype;
|
||||
bhints.ai_flags = AI_PASSIVE;
|
||||
@@ -160,42 +181,59 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
{
|
||||
int type = SOCK_STREAM;
|
||||
int error;
|
||||
int s;
|
||||
int error, s;
|
||||
struct addrinfo hints, *res0, *res;
|
||||
char portbuf[10];
|
||||
char *h;
|
||||
char *h, *cp;
|
||||
int proxied = 0;
|
||||
char buffer[1024];
|
||||
char *cp;
|
||||
char *proxy_user = NULL, *proxy_pass = NULL;
|
||||
|
||||
/* if we have a RSYNC_PROXY env variable then redirect our
|
||||
* connetcion via a web proxy at the given address. The format
|
||||
* is hostname:port */
|
||||
* connetcion via a web proxy at the given address. */
|
||||
h = getenv("RSYNC_PROXY");
|
||||
proxied = (h != NULL) && (*h != '\0');
|
||||
proxied = h != NULL && *h != '\0';
|
||||
|
||||
if (proxied) {
|
||||
strlcpy(buffer, h, sizeof(buffer));
|
||||
cp = strchr(buffer, ':');
|
||||
if (cp == NULL) {
|
||||
strlcpy(buffer, h, sizeof buffer);
|
||||
|
||||
/* Is the USER:PASS@ prefix present? */
|
||||
if ((cp = strchr(buffer, '@')) != NULL) {
|
||||
*cp++ = '\0';
|
||||
/* The remainder is the HOST:PORT part. */
|
||||
h = cp;
|
||||
|
||||
if ((cp = strchr(buffer, ':')) == NULL) {
|
||||
rprintf(FERROR,
|
||||
"invalid proxy specification: should be USER:PASS@HOST:PORT\n");
|
||||
return -1;
|
||||
}
|
||||
*cp++ = '\0';
|
||||
|
||||
proxy_user = buffer;
|
||||
proxy_pass = cp;
|
||||
} else {
|
||||
/* The whole buffer is the HOST:PORT part. */
|
||||
h = buffer;
|
||||
}
|
||||
|
||||
if ((cp = strchr(h, ':')) == NULL) {
|
||||
rprintf(FERROR,
|
||||
"invalid proxy specification: should be HOST:PORT\n");
|
||||
return -1;
|
||||
}
|
||||
*cp++ = '\0';
|
||||
strcpy(portbuf, cp);
|
||||
h = buffer;
|
||||
strlcpy(portbuf, cp, sizeof portbuf);
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "connection via http proxy %s port %s\n",
|
||||
h, portbuf);
|
||||
}
|
||||
} else {
|
||||
snprintf(portbuf, sizeof(portbuf), "%d", port);
|
||||
snprintf(portbuf, sizeof portbuf, "%d", port);
|
||||
h = host;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = af_hint;
|
||||
hints.ai_socktype = type;
|
||||
error = getaddrinfo(h, portbuf, &hints, &res0);
|
||||
@@ -215,31 +253,30 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
if (s < 0)
|
||||
continue;
|
||||
|
||||
if (bind_address)
|
||||
if (try_bind_local(s, res->ai_family, type,
|
||||
bind_address) == -1) {
|
||||
close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bind_address
|
||||
&& try_bind_local(s, res->ai_family, type,
|
||||
bind_address) == -1) {
|
||||
close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
if (proxied &&
|
||||
establish_proxy_connection(s, host, port) != 0) {
|
||||
if (proxied
|
||||
&& establish_proxy_connection(s, host, port,
|
||||
proxy_user, proxy_pass) != 0) {
|
||||
close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
if (s < 0) {
|
||||
rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
|
||||
h, strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to connect to %s", h);
|
||||
return -1;
|
||||
}
|
||||
return s;
|
||||
@@ -258,93 +295,111 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
*
|
||||
* @param bind_address Local address to use. Normally NULL to get the stack default.
|
||||
**/
|
||||
int open_socket_out_wrapped (char *host,
|
||||
int port,
|
||||
const char *bind_address,
|
||||
int af_hint)
|
||||
int open_socket_out_wrapped(char *host, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
{
|
||||
char *prog;
|
||||
char *prog = getenv("RSYNC_CONNECT_PROG");
|
||||
|
||||
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
|
||||
return sock_exec (prog);
|
||||
else
|
||||
return open_socket_out (host, port, bind_address,
|
||||
af_hint);
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
|
||||
prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
|
||||
host, port);
|
||||
}
|
||||
if (prog)
|
||||
return sock_exec(prog);
|
||||
return open_socket_out(host, port, bind_address, af_hint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Open a socket of the specified type, port and address for incoming data
|
||||
* Open one or more sockets for incoming data using the specified type,
|
||||
* port, and address.
|
||||
*
|
||||
* The getaddrinfo() call may return several address results, e.g. for
|
||||
* the machine's IPv4 and IPv6 name.
|
||||
*
|
||||
* We return an array of file-descriptors to the sockets, with a trailing
|
||||
* -1 value to indicate the end of the list.
|
||||
*
|
||||
* Try to be better about handling the results of getaddrinfo(): when
|
||||
* opening an inbound socket, we might get several address results,
|
||||
* e.g. for the machine's ipv4 and ipv6 name.
|
||||
*
|
||||
* If binding a wildcard, then any one of them should do. If an address
|
||||
* was specified but it's insufficiently specific then that's not our
|
||||
* fault.
|
||||
*
|
||||
* However, some of the advertized addresses may not work because e.g. we
|
||||
* don't have IPv6 support in the kernel. In that case go on and try all
|
||||
* addresses until one succeeds.
|
||||
*
|
||||
* @param bind_address Local address to bind, or NULL to allow it to
|
||||
* default.
|
||||
**/
|
||||
static int open_socket_in(int type, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
{
|
||||
int one=1;
|
||||
int s;
|
||||
int one = 1;
|
||||
int s, *socks, maxs, i;
|
||||
struct addrinfo hints, *all_ai, *resp;
|
||||
char portbuf[10];
|
||||
int error;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = af_hint;
|
||||
hints.ai_socktype = type;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
snprintf(portbuf, sizeof(portbuf), "%d", port);
|
||||
snprintf(portbuf, sizeof portbuf, "%d", port);
|
||||
error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
|
||||
if (error) {
|
||||
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
|
||||
bind_address, gai_strerror(error));
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Count max number of sockets we might open. */
|
||||
for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
|
||||
|
||||
if (!(socks = new_array(int, maxs + 1)))
|
||||
out_of_memory("open_socket_in");
|
||||
|
||||
/* We may not be able to create the socket, if for example the
|
||||
* machine knows about IPv6 in the C library, but not in the
|
||||
* kernel. */
|
||||
for (resp = all_ai; resp; resp = resp->ai_next) {
|
||||
for (resp = all_ai, i = 0; resp; resp = resp->ai_next) {
|
||||
s = socket(resp->ai_family, resp->ai_socktype,
|
||||
resp->ai_protocol);
|
||||
|
||||
if (s == -1)
|
||||
if (s == -1) {
|
||||
/* See if there's another address that will work... */
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&one, sizeof one);
|
||||
|
||||
/* now we've got a socket - we need to bind it */
|
||||
if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (resp->ai_family == AF_INET6) {
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *)&one, sizeof one) < 0
|
||||
&& default_af_hint != AF_INET6) {
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now we've got a socket - we need to bind it. */
|
||||
if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
|
||||
/* Nope, try another */
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
freeaddrinfo(all_ai);
|
||||
return s;
|
||||
socks[i++] = s;
|
||||
}
|
||||
socks[i] = -1;
|
||||
|
||||
rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
|
||||
"%s\n",
|
||||
port,
|
||||
strerror(errno));
|
||||
if (all_ai)
|
||||
freeaddrinfo(all_ai);
|
||||
|
||||
freeaddrinfo(all_ai);
|
||||
return -1;
|
||||
if (!i) {
|
||||
rprintf(FERROR,
|
||||
"unable to bind any inbound sockets on port %d\n",
|
||||
port);
|
||||
free(socks);
|
||||
return NULL;
|
||||
}
|
||||
return socks;
|
||||
}
|
||||
|
||||
|
||||
@@ -354,55 +409,65 @@ static int open_socket_in(int type, int port, const char *bind_address,
|
||||
int is_a_socket(int fd)
|
||||
{
|
||||
int v;
|
||||
socklen_t l;
|
||||
l = sizeof(int);
|
||||
socklen_t l = sizeof (int);
|
||||
|
||||
/* Parameters to getsockopt, setsockopt etc are very
|
||||
* unstandardized across platforms, so don't be surprised if
|
||||
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
|
||||
* It seems they all eventually get the right idea.
|
||||
*
|
||||
* Debian says: ``The fifth argument of getsockopt and
|
||||
* setsockopt is in reality an int [*] (and this is what BSD
|
||||
* 4.* and libc4 and libc5 have). Some POSIX confusion
|
||||
* resulted in the present socklen_t. The draft standard has
|
||||
* not been adopted yet, but glibc2 already follows it and
|
||||
* also has socklen_t [*]. See also accept(2).''
|
||||
*
|
||||
* We now return to your regularly scheduled programming. */
|
||||
return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
|
||||
/* Parameters to getsockopt, setsockopt etc are very
|
||||
* unstandardized across platforms, so don't be surprised if
|
||||
* there are compiler warnings on e.g. SCO OpenSwerver or AIX.
|
||||
* It seems they all eventually get the right idea.
|
||||
*
|
||||
* Debian says: ``The fifth argument of getsockopt and
|
||||
* setsockopt is in reality an int [*] (and this is what BSD
|
||||
* 4.* and libc4 and libc5 have). Some POSIX confusion
|
||||
* resulted in the present socklen_t. The draft standard has
|
||||
* not been adopted yet, but glibc2 already follows it and
|
||||
* also has socklen_t [*]. See also accept(2).''
|
||||
*
|
||||
* We now return to your regularly scheduled programming. */
|
||||
return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
{
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
#ifdef WNOHANG
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0) {}
|
||||
#endif
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
}
|
||||
|
||||
|
||||
void start_accept_loop(int port, int (*fn)(int, int))
|
||||
{
|
||||
int s;
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
fd_set deffds;
|
||||
int *sp, maxfd, i;
|
||||
|
||||
/* open an incoming socket */
|
||||
s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
if (s == -1)
|
||||
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
if (sp == NULL)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
/* ready to listen */
|
||||
if (listen(s, 5) == -1) {
|
||||
close(s);
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
FD_ZERO(&deffds);
|
||||
for (i = 0, maxfd = -1; sp[i] >= 0; i++) {
|
||||
if (listen(sp[i], 5) < 0) {
|
||||
rsyserr(FERROR, errno, "listen() on socket failed");
|
||||
#ifdef INET6
|
||||
if (errno == EADDRINUSE && i > 0) {
|
||||
rprintf(FINFO,
|
||||
"Try using --ipv4 or --ipv6 to avoid this listen() error.");
|
||||
}
|
||||
#endif
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
FD_SET(sp[i], &deffds);
|
||||
if (maxfd < sp[i])
|
||||
maxfd = sp[i];
|
||||
}
|
||||
|
||||
|
||||
/* now accept incoming connections - forking a new process
|
||||
for each incoming connection */
|
||||
* for each incoming connection */
|
||||
while (1) {
|
||||
fd_set fds;
|
||||
pid_t pid;
|
||||
@@ -411,39 +476,45 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
socklen_t addrlen = sizeof addr;
|
||||
|
||||
/* close log file before the potentially very long select so
|
||||
file can be trimmed by another process instead of growing
|
||||
forever */
|
||||
* file can be trimmed by another process instead of growing
|
||||
* forever */
|
||||
log_close();
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(s, &fds);
|
||||
#ifdef FD_COPY
|
||||
FD_COPY(&deffds, &fds);
|
||||
#else
|
||||
fds = deffds;
|
||||
#endif
|
||||
|
||||
if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
|
||||
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
|
||||
continue;
|
||||
|
||||
for (i = 0, fd = -1; sp[i] >= 0; i++) {
|
||||
if (FD_ISSET(sp[i], &fds)) {
|
||||
fd = accept(sp[i], (struct sockaddr *)&addr,
|
||||
&addrlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!FD_ISSET(s, &fds)) continue;
|
||||
|
||||
fd = accept(s,(struct sockaddr *)&addr,&addrlen);
|
||||
|
||||
if (fd == -1) continue;
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
int ret;
|
||||
close(s);
|
||||
for (i = 0; sp[i] >= 0; i++)
|
||||
close(sp[i]);
|
||||
/* open log file in child before possibly giving
|
||||
up privileges */
|
||||
* up privileges */
|
||||
log_open();
|
||||
ret = fn(fd, fd);
|
||||
close_all();
|
||||
_exit(ret);
|
||||
} else if (pid < 0) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME
|
||||
": could not create child server process: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"could not create child server process");
|
||||
close(fd);
|
||||
/* This might have happened because we're
|
||||
* overloaded. Sleep briefly before trying to
|
||||
@@ -454,6 +525,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
|
||||
@@ -499,7 +571,7 @@ struct
|
||||
#endif
|
||||
{NULL,0,0,0,0}};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set user socket options
|
||||
@@ -507,13 +579,16 @@ struct
|
||||
void set_socket_options(int fd, char *options)
|
||||
{
|
||||
char *tok;
|
||||
if (!options || !*options) return;
|
||||
|
||||
if (!options || !*options)
|
||||
return;
|
||||
|
||||
options = strdup(options);
|
||||
|
||||
if (!options) out_of_memory("set_socket_options");
|
||||
|
||||
for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
|
||||
if (!options)
|
||||
out_of_memory("set_socket_options");
|
||||
|
||||
for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) {
|
||||
int ret=0,i;
|
||||
int value = 1;
|
||||
char *p;
|
||||
@@ -525,9 +600,10 @@ void set_socket_options(int fd, char *options)
|
||||
got_value = 1;
|
||||
}
|
||||
|
||||
for (i=0;socket_options[i].name;i++)
|
||||
for (i = 0; socket_options[i].name; i++) {
|
||||
if (strcmp(socket_options[i].name,tok)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!socket_options[i].name) {
|
||||
rprintf(FERROR,"Unknown socket option %s\n",tok);
|
||||
@@ -538,9 +614,10 @@ void set_socket_options(int fd, char *options)
|
||||
case OPT_BOOL:
|
||||
case OPT_INT:
|
||||
ret = setsockopt(fd,socket_options[i].level,
|
||||
socket_options[i].option,(char *)&value,sizeof(int));
|
||||
socket_options[i].option,
|
||||
(char *)&value, sizeof (int));
|
||||
break;
|
||||
|
||||
|
||||
case OPT_ON:
|
||||
if (got_value)
|
||||
rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
|
||||
@@ -548,14 +625,16 @@ void set_socket_options(int fd, char *options)
|
||||
{
|
||||
int on = socket_options[i].value;
|
||||
ret = setsockopt(fd,socket_options[i].level,
|
||||
socket_options[i].option,(char *)&on,sizeof(int));
|
||||
socket_options[i].option,
|
||||
(char *)&on, sizeof (int));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to set socket option %s", tok);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
free(options);
|
||||
@@ -579,15 +658,15 @@ void become_daemon(void)
|
||||
#ifdef TIOCNOTTY
|
||||
i = open("/dev/tty", O_RDWR);
|
||||
if (i >= 0) {
|
||||
ioctl(i, (int) TIOCNOTTY, (char *)0);
|
||||
ioctl(i, (int)TIOCNOTTY, (char *)0);
|
||||
close(i);
|
||||
}
|
||||
#endif /* TIOCNOTTY */
|
||||
#endif
|
||||
/* make sure that stdin, stdout an stderr don't stuff things
|
||||
up (library functions, for example) */
|
||||
for (i=0;i<3;i++) {
|
||||
close(i);
|
||||
* up (library functions, for example) */
|
||||
for (i = 0; i < 3; i++) {
|
||||
close(i);
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
}
|
||||
@@ -596,7 +675,7 @@ void become_daemon(void)
|
||||
/**
|
||||
* This is like socketpair but uses tcp. It is used by the Samba
|
||||
* regression test code.
|
||||
*
|
||||
*
|
||||
* The function guarantees that nobody else can attach to the socket,
|
||||
* or if they do that this function fails and the socket gets closed
|
||||
* returns 0 on success, -1 on failure the resulting file descriptors
|
||||
@@ -607,56 +686,67 @@ static int socketpair_tcp(int fd[2])
|
||||
int listener;
|
||||
struct sockaddr_in sock;
|
||||
struct sockaddr_in sock2;
|
||||
socklen_t socklen = sizeof(sock);
|
||||
socklen_t socklen = sizeof sock;
|
||||
int connect_done = 0;
|
||||
|
||||
|
||||
fd[0] = fd[1] = listener = -1;
|
||||
|
||||
memset(&sock, 0, sizeof(sock));
|
||||
|
||||
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
|
||||
memset(&sock, 0, sizeof sock);
|
||||
|
||||
memset(&sock2, 0, sizeof(sock2));
|
||||
#ifdef HAVE_SOCKADDR_LEN
|
||||
sock2.sin_len = sizeof(sock2);
|
||||
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto failed;
|
||||
|
||||
memset(&sock2, 0, sizeof sock2);
|
||||
#if HAVE_SOCKADDR_IN_LEN
|
||||
sock2.sin_len = sizeof sock2;
|
||||
#endif
|
||||
sock2.sin_family = PF_INET;
|
||||
sock2.sin_family = PF_INET;
|
||||
|
||||
bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
|
||||
bind(listener, (struct sockaddr *)&sock2, sizeof sock2);
|
||||
|
||||
if (listen(listener, 1) != 0) goto failed;
|
||||
if (listen(listener, 1) != 0)
|
||||
goto failed;
|
||||
|
||||
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
|
||||
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)
|
||||
goto failed;
|
||||
|
||||
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
|
||||
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto failed;
|
||||
|
||||
set_nonblocking(fd[1]);
|
||||
|
||||
sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
|
||||
if (errno != EINPROGRESS) goto failed;
|
||||
} else {
|
||||
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) {
|
||||
if (errno != EINPROGRESS)
|
||||
goto failed;
|
||||
} else
|
||||
connect_done = 1;
|
||||
}
|
||||
|
||||
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
|
||||
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)
|
||||
goto failed;
|
||||
|
||||
close(listener);
|
||||
if (connect_done == 0) {
|
||||
if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
|
||||
&& errno != EISCONN) goto failed;
|
||||
}
|
||||
listener = -1;
|
||||
|
||||
set_blocking (fd[1]);
|
||||
set_blocking(fd[1]);
|
||||
|
||||
if (connect_done == 0) {
|
||||
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
|
||||
&& errno != EISCONN)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* all OK! */
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
if (fd[0] != -1) close(fd[0]);
|
||||
if (fd[1] != -1) close(fd[1]);
|
||||
if (listener != -1) close(listener);
|
||||
if (fd[0] != -1)
|
||||
close(fd[0]);
|
||||
if (fd[1] != -1)
|
||||
close(fd[1]);
|
||||
if (listener != -1)
|
||||
close(listener);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -674,30 +764,21 @@ static int socketpair_tcp(int fd[2])
|
||||
int sock_exec(const char *prog)
|
||||
{
|
||||
int fd[2];
|
||||
|
||||
|
||||
if (socketpair_tcp(fd) != 0) {
|
||||
rprintf (FERROR, RSYNC_NAME
|
||||
": socketpair_tcp failed (%s)\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "socketpair_tcp failed");
|
||||
return -1;
|
||||
}
|
||||
if (verbose >= 2)
|
||||
rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
|
||||
if (fork() == 0) {
|
||||
close(fd[0]);
|
||||
close(0);
|
||||
close(1);
|
||||
dup(fd[1]);
|
||||
dup(fd[1]);
|
||||
if (verbose > 3) {
|
||||
/* Can't use rprintf because we've forked. */
|
||||
fprintf (stderr,
|
||||
RSYNC_NAME ": execute socket program \"%s\"\n",
|
||||
prog);
|
||||
}
|
||||
exit (system (prog));
|
||||
exit(system(prog));
|
||||
}
|
||||
close (fd[1]);
|
||||
close(fd[1]);
|
||||
return fd[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
55
syscall.c
55
syscall.c
@@ -31,19 +31,27 @@ extern int read_only;
|
||||
extern int list_only;
|
||||
extern int preserve_perms;
|
||||
|
||||
#define CHECK_RO if (read_only || list_only) {errno = EROFS; return -1;}
|
||||
#define RETURN_ERROR_IF(x,e) \
|
||||
do { \
|
||||
if (x) { \
|
||||
errno = (e); \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
|
||||
|
||||
int do_unlink(char *fname)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return unlink(fname);
|
||||
}
|
||||
|
||||
int do_symlink(char *fname1, char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return symlink(fname1, fname2);
|
||||
}
|
||||
|
||||
@@ -51,7 +59,7 @@ int do_symlink(char *fname1, char *fname2)
|
||||
int do_link(char *fname1, char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return link(fname1, fname2);
|
||||
}
|
||||
#endif
|
||||
@@ -59,7 +67,7 @@ int do_link(char *fname1, char *fname2)
|
||||
int do_lchown(const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return lchown(path, owner, group);
|
||||
}
|
||||
|
||||
@@ -67,7 +75,7 @@ int do_lchown(const char *path, uid_t owner, gid_t group)
|
||||
int do_mknod(char *pathname, mode_t mode, dev_t dev)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return mknod(pathname, mode, dev);
|
||||
}
|
||||
#endif
|
||||
@@ -75,18 +83,16 @@ int do_mknod(char *pathname, mode_t mode, dev_t dev)
|
||||
int do_rmdir(char *pathname)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return rmdir(pathname);
|
||||
}
|
||||
|
||||
int do_open(char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
if (flags != O_RDONLY) {
|
||||
if (dry_run) return -1;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF(dry_run, 0);
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
}
|
||||
/* some systems can't handle a double / */
|
||||
if (pathname[0] == '/' && pathname[1] == '/') pathname++;
|
||||
|
||||
return open(pathname, flags | O_BINARY, mode);
|
||||
}
|
||||
@@ -96,9 +102,9 @@ int do_chmod(const char *path, mode_t mode)
|
||||
{
|
||||
int code;
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
code = chmod(path, mode);
|
||||
if ((code != 0) && preserve_perms)
|
||||
if (code != 0 && preserve_perms)
|
||||
return code;
|
||||
return 0;
|
||||
}
|
||||
@@ -107,7 +113,7 @@ int do_chmod(const char *path, mode_t mode)
|
||||
int do_rename(char *fname1, char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
CHECK_RO
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return rename(fname1, fname2);
|
||||
}
|
||||
|
||||
@@ -133,9 +139,8 @@ void trim_trailing_slashes(char *name)
|
||||
|
||||
int do_mkdir(char *fname, mode_t mode)
|
||||
{
|
||||
if (dry_run)
|
||||
return 0;
|
||||
CHECK_RO;
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
trim_trailing_slashes(fname);
|
||||
return mkdir(fname, mode);
|
||||
}
|
||||
@@ -144,22 +149,26 @@ int do_mkdir(char *fname, mode_t mode)
|
||||
/* like mkstemp but forces permissions */
|
||||
int do_mkstemp(char *template, mode_t perms)
|
||||
{
|
||||
if (dry_run) return -1;
|
||||
if (read_only) {errno = EROFS; return -1;}
|
||||
RETURN_ERROR_IF(dry_run, 0);
|
||||
RETURN_ERROR_IF(read_only, EROFS);
|
||||
|
||||
#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
|
||||
#if HAVE_SECURE_MKSTEMP && HAVE_FCHMOD && (!HAVE_OPEN64 || HAVE_MKSTEMP64)
|
||||
{
|
||||
int fd = mkstemp(template);
|
||||
if (fd == -1) return -1;
|
||||
if ((fchmod(fd, perms) != 0) && preserve_perms) {
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
if (fchmod(fd, perms) != 0 && preserve_perms) {
|
||||
int errno_save = errno;
|
||||
close(fd);
|
||||
unlink(template);
|
||||
errno = errno_save;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
#else
|
||||
if (!mktemp(template)) return -1;
|
||||
if (!mktemp(template))
|
||||
return -1;
|
||||
return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
|
||||
#endif
|
||||
}
|
||||
|
||||
15
t_stub.c
15
t_stub.c
@@ -28,7 +28,8 @@
|
||||
|
||||
int modify_window = 0;
|
||||
int module_id = -1;
|
||||
struct exclude_struct **server_exclude_list;
|
||||
char *partial_dir;
|
||||
struct exclude_list_struct server_exclude_list;
|
||||
|
||||
void rprintf(UNUSED(enum logcode code), const char *format, ...)
|
||||
{
|
||||
@@ -38,6 +39,16 @@ struct exclude_struct **server_exclude_list;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void rsyserr(UNUSED(enum logcode code), int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
fputs(RSYNC_NAME ": ", stderr);
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s (%d)\n", strerror(errcode), errcode);
|
||||
}
|
||||
|
||||
void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
fprintf(stderr, "exit(%d): %s(%d)\n",
|
||||
@@ -45,7 +56,7 @@ struct exclude_struct **server_exclude_list;
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int check_exclude(UNUSED(struct exclude_struct **list), UNUSED(char *name),
|
||||
int check_exclude(UNUSED(struct exclude_list_struct *listp), UNUSED(char *name),
|
||||
UNUSED(int name_is_dir))
|
||||
{
|
||||
/* This function doesn't really get called in this test context, so
|
||||
|
||||
173
test.sh
173
test.sh
@@ -1,173 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
|
||||
#
|
||||
# This program is distributable under the terms of the GNU GPL (see COPYING)
|
||||
#
|
||||
# This is a simple test script that tests a few rsync
|
||||
# features to make sure I haven't broken them before a release.
|
||||
#
|
||||
#
|
||||
|
||||
# check if we are running under debian-test, and change behaviour to suit
|
||||
if test -n "${DEBIANTEST_LIB}" ; then
|
||||
# make sure rsync is installed
|
||||
test -e /usr/bin/rsync || exit 0
|
||||
|
||||
. ${DEBIANTEST_LIB}/functions.sh
|
||||
Debian=1
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
This set of tests is not completely portable. It is intended for developers
|
||||
not for end users. You may experience failures on some platforms that
|
||||
do not indicate a problem with rsync.
|
||||
|
||||
EOF
|
||||
|
||||
RSYNC=`pwd`/rsync
|
||||
|
||||
runtest() {
|
||||
echo -n "Test $1: "
|
||||
eval "$2"
|
||||
}
|
||||
printmsg() {
|
||||
echo ""
|
||||
echo "**** ${1}^G ****"
|
||||
echo ""
|
||||
}
|
||||
fi
|
||||
|
||||
TMP=/tmp/rsync-test.$$
|
||||
FROM=${TMP}/from
|
||||
TO=${TMP}/to
|
||||
F1=text1
|
||||
LOG=${TMP}/log
|
||||
|
||||
mkdir $TMP
|
||||
mkdir $FROM
|
||||
mkdir $TO
|
||||
|
||||
# set up test data
|
||||
touch ${FROM}/empty
|
||||
mkdir ${FROM}/emptydir
|
||||
ps ax > ${FROM}/pslist
|
||||
echo -n "This file has no trailing lf" > ${FROM}/nolf
|
||||
ln -s nolf ${FROM}/nolf-symlink
|
||||
|
||||
# Gather some random text. We need files that will exist and be
|
||||
# publicly readable on all platforms: hopefully this will work.
|
||||
cat /etc/*tab /etc/services /etc/*.conf /etc/*rc > ${FROM}/${F1}
|
||||
|
||||
mkdir ${FROM}/dir
|
||||
cp ${FROM}/${F1} ${FROM}/dir/
|
||||
mkdir ${FROM}/dir/subdir
|
||||
mkdir ${FROM}/dir/subdir/subsubdir
|
||||
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
|
||||
mkdir ${FROM}/dir/subdir/subsubdir2
|
||||
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
|
||||
|
||||
checkit() {
|
||||
testnum=`expr 0${testnum} + 1`
|
||||
log=${LOG}.${testnum}
|
||||
failed=
|
||||
echo "Running: \"$1\"" >${log}
|
||||
echo "">>${log}
|
||||
eval "$1" >>${log} 2>&1
|
||||
status=$?
|
||||
if [ $status != 0 ]; then
|
||||
failed="YES";
|
||||
fi
|
||||
echo "-------------">>${log}
|
||||
echo "check how the files compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
diff -ur $2 $3 >>${log} 2>&1 || failed=YES
|
||||
echo "-------------">>${log}
|
||||
echo "check how the directory listings compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
( cd $2 ; ls -laR ) > ${TMP}/ls-from 2>>${log}
|
||||
( cd $3 ; ls -laR ) > ${TMP}/ls-to 2>>${log}
|
||||
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} 2>&1 || failed=YES
|
||||
if [ -z "${failed}" ] ; then
|
||||
test -z "${Debian}" && echo " done."
|
||||
rm $log
|
||||
return 0
|
||||
else
|
||||
if test -n "${Debian}" ; then
|
||||
cat ${log}
|
||||
rm ${log}
|
||||
else
|
||||
echo " FAILED (test # ${testnum} status=$status)."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
checkforlogs() {
|
||||
# skip it if we're under debian-test
|
||||
if test -n "${Debian}" ; then return 0 ; fi
|
||||
|
||||
if [ -f $1 ] ; then
|
||||
cat <<EOF
|
||||
|
||||
Failures have occured.
|
||||
|
||||
You can find the output of the tests in these files:
|
||||
$@
|
||||
|
||||
Please hit <RETURN>
|
||||
EOF
|
||||
read input
|
||||
else
|
||||
|
||||
rm -rf ${TMP}
|
||||
echo ""
|
||||
echo "Tests Completed Successfully :-)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main script starts here
|
||||
|
||||
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
ln ${FROM}/pslist ${FROM}/dir
|
||||
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
rm ${TO}/${F1}
|
||||
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
echo "extra line" >> ${TO}/${F1}
|
||||
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
cp ${FROM}/${F1} ${TO}/ThisShouldGo
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
mkdir -p ${LONGDIR}
|
||||
date > ${LONGDIR}/1
|
||||
ls -la / > ${LONGDIR}/2
|
||||
runtest "long paths" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
if type ssh >/dev/null 2>&1; then
|
||||
if [ "`ssh -o'BatchMode yes' localhost echo yes 2>/dev/null`" = "yes" ]; then
|
||||
rm -rf ${TO}
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
mv ${TO}/${F1} ${TO}/ThisShouldGo
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
else
|
||||
printmsg "Skipping SSH tests because ssh conection to localhost not authorised"
|
||||
fi
|
||||
else
|
||||
printmsg "Skipping SSH tests because ssh is not in the path"
|
||||
fi
|
||||
|
||||
rm -rf ${TO}
|
||||
mkdir -p ${FROM}2/dir/subdir
|
||||
cp -a ${FROM}/dir/subdir/subsubdir ${FROM}2/dir/subdir
|
||||
cp ${FROM}/dir/* ${FROM}2/dir 2>/dev/null
|
||||
runtest "excludes" 'checkit "$RSYNC -vv -Hlrt --delete --include /dir/ --include /dir/\* --include /dir/\*/subsubdir --include /dir/\*/subsubdir/\*\* --exclude \*\* ${FROM}/dir ${TO}" ${FROM}2/ ${TO}'
|
||||
rm -r ${FROM}2
|
||||
|
||||
checkforlogs ${LOG}.?
|
||||
@@ -17,8 +17,8 @@ with the GNU Standards, installcheck does not look for rsync on the
|
||||
path.
|
||||
|
||||
If the tests pass, you should see a report to that effect. Some tests
|
||||
require being root or some other precondition, and so will normally be
|
||||
checked -- look at the test scripts for more information.
|
||||
require being root or some other precondition, and so will normally not
|
||||
be checked -- look at the test scripts for more information.
|
||||
|
||||
If the tests fail, you will see rather more output. The scratch
|
||||
directory will remain in the build directory. It would be useful if
|
||||
|
||||
61
testsuite/backup.test
Normal file
61
testsuite/backup.test
Normal file
@@ -0,0 +1,61 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that the --backup option works right.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
bakdir="$tmpdir/bak"
|
||||
|
||||
mkdir "$fromdir" "$bakdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
cat $srcdir/[gr]*.[ch] > "$name1"
|
||||
cat $srcdir/[et]*.[ch] > "$name2"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
cat $srcdir/[fgpr]*.[ch] > "$name1"
|
||||
cat $srcdir/[etw]*.[ch] > "$name2"
|
||||
|
||||
$RSYNC -avv --no-whole-file --backup "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
for fn in name1 name2; do
|
||||
grep "backed up $fn to $fn~" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
diff $diffopt "$fromdir/$fn" "$todir" || test_fail "copy of $fn failed"
|
||||
diff $diffopt "$chkdir/$fn" "$todir/$fn~" || test_fail "backup of $fn to $fn~ failed"
|
||||
mv "$todir/$fn~" "$todir/$fn"
|
||||
done
|
||||
|
||||
checkit "$RSYNC -avv --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
for fn in name1 name2; do
|
||||
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
done
|
||||
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
cat $srcdir/[efgr]*.[ch] > "$name1"
|
||||
cat $srcdir/[ew]*.[ch] > "$name2"
|
||||
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
for fn in name1 name2; do
|
||||
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
done
|
||||
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
|
||||
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file \"$fromdir/\" \"$bakdir/\"" "$fromdir" "$bakdir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
45
testsuite/batch-mode.test
Normal file
45
testsuite/batch-mode.test
Normal file
@@ -0,0 +1,45 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Chris Shoemaker <c.shoemaker@cox.net>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync's --write-batch and --read-batch options
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
cd "$tmpdir"
|
||||
|
||||
# Build chkdir for the daemon tests using a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
runtest "local --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "--read-batch" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
build_rsyncd_conf
|
||||
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "daemon sender --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH rsync://localhost/test-from/ \"$todir\"" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "--read-batch from daemon" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "BATCH.sh use of --read-batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
mkdir "$todir" || test_fail "failed to restore empty destination directory"
|
||||
runtest "daemon recv --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" rsync://localhost/test-to" "$chkdir" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we pass.
|
||||
exit 0
|
||||
@@ -9,17 +9,12 @@
|
||||
# the test is a member of them. Hopefully they're in at least one
|
||||
# test.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
# TODO: I guess some systems will not have 'id', and therefore we have
|
||||
# to ship or emulate it.
|
||||
mygrps="`rsync_getgroups`" || fail "Can't get groups"
|
||||
mkdir "$fromdir"
|
||||
|
||||
@@ -31,8 +26,7 @@ do
|
||||
done
|
||||
sleep 2
|
||||
|
||||
checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -rtgpvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
|
||||
41
testsuite/chmod-temp-dir.test
Normal file
41
testsuite/chmod-temp-dir.test
Normal file
@@ -0,0 +1,41 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test that various read-only and set[ug]id permissions work properly,
|
||||
# even when using a --temp-dir option (which we try to point at a
|
||||
# different filesystem than the destination dir).
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
tmpdir2=/tmp
|
||||
sdev=`$TOOLDIR/getfsdev $scratchdir`
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
if [ x$sdev = x$tdev ]; then
|
||||
tmpdir2=/var/tmp
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
[ x$sdev = x$tdev ] && test_skipped "Can't find a tmp dir on a different file system"
|
||||
fi
|
||||
|
||||
chmod 440 "$fromdir/text"
|
||||
chmod 500 "$fromdir/dir/text"
|
||||
e="$fromdir/dir/subdir/foobar.baz"
|
||||
chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e"
|
||||
e="$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e"
|
||||
|
||||
# First a normal copy.
|
||||
runtest "normal copy" 'checkit "$RSYNC -avv --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# Then we update all the files.
|
||||
runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
32
testsuite/chmod.test
Normal file
32
testsuite/chmod.test
Normal file
@@ -0,0 +1,32 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test that various read-only and set[ug]id permissions work properly,
|
||||
# even when using a --temp-dir option (which we try to point at a
|
||||
# different filesystem than the destination dir).
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
chmod 440 "$fromdir/text"
|
||||
chmod 500 "$fromdir/dir/text"
|
||||
e="$fromdir/dir/subdir/foobar.baz"
|
||||
chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e"
|
||||
e="$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e"
|
||||
|
||||
# First a normal copy.
|
||||
runtest "normal copy" 'checkit "$RSYNC -avv \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# Then we update all the files.
|
||||
runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -11,15 +11,12 @@
|
||||
# We don't know what users will be present on this system, so we just
|
||||
# use random numeric uids and gids.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
mkdir "$fromdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
@@ -33,6 +30,5 @@ chgrp 5003 "$name2" || test_skipped "Can't chgrp (probably need root)"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
|
||||
33
testsuite/compare-dest.test
Normal file
33
testsuite/compare-dest.test
Normal file
@@ -0,0 +1,33 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of the --compare-dest option.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
altdir="$tmpdir/alt"
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
hands_setup
|
||||
|
||||
# Setup the alt and chk dirs
|
||||
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$altdir/"
|
||||
|
||||
sleep 1
|
||||
touch "$fromdir/dir/text"
|
||||
|
||||
$RSYNC -av --exclude=/text "$fromdir/" "$chkdir/"
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avv --no-whole-file --compare-dest=\"$altdir\" \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -27,5 +27,11 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
hands_setup
|
||||
checkit "$RSYNC -avvz localhost::test-from/ \"$TO/\"" "$FROM" "$TO"
|
||||
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avvvvz localhost::test-from/ \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -21,5 +21,11 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
hands_setup
|
||||
checkit "$RSYNC -avvz \"$FROM/\" localhost::test-to/" "$FROM" "$TO"
|
||||
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avvvvz \"$fromdir/\" localhost::test-to/" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -7,23 +7,30 @@
|
||||
|
||||
# Test rsync handling of devices. This can only run if you're root.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) test_skipped "Rsync won't copy devices unless we're root" ;;
|
||||
esac
|
||||
|
||||
# TODO: Need to test whether hardlinks are possible on this OS/filesystem
|
||||
|
||||
mkdir "$fromdir"
|
||||
mknod "$fromdir/char" c 42 69 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/char" c 41 67 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/char2" c 42 68 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node unless root"
|
||||
mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node unless root"
|
||||
mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node unless root"
|
||||
mkfifo "$fromdir/fifo" || test_skipped "Can't run mkfifo"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
|
||||
@@ -19,15 +19,12 @@
|
||||
|
||||
# This test is not great, because it is a timing-dependent bug.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
mkdir "$fromdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
@@ -49,5 +46,5 @@ then
|
||||
test_fail "name2 was not copied exactly once"
|
||||
fi
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
@@ -10,30 +10,38 @@
|
||||
# Test some of the more obscure wildcard handling of exclude/include
|
||||
# processing.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
HOME="$scratchdir"
|
||||
CVSIGNORE='*.junk'
|
||||
export HOME CVSIGNORE
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
chkdir="$scratchdir/chk"
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
makepath "$fromdir/foo/down/to/you"
|
||||
makepath "$fromdir/bar/down/to/foo/too"
|
||||
makepath "$fromdir/mid/for/foo/and/that/is/who"
|
||||
echo kept >"$fromdir/foo/file1"
|
||||
echo removed >"$fromdir/foo/file2"
|
||||
echo cvsout >"$fromdir/foo/file2.old"
|
||||
echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
|
||||
echo keeper >"$fromdir/bar/down/to/foo/file1"
|
||||
echo cvsout >"$fromdir/bar/down/to/foo/file1.bak"
|
||||
echo gone >"$fromdir/bar/down/to/foo/file3"
|
||||
echo lost >"$fromdir/bar/down/to/foo/file4"
|
||||
echo cvsout >"$fromdir/bar/down/to/foo/file4.junk"
|
||||
echo smashed >"$fromdir/bar/down/to/foo/to"
|
||||
echo cvsout >"$fromdir/mid/one-in-one-out"
|
||||
echo one-in-one-out >"$fromdir/mid/.cvsignore"
|
||||
echo cvsin >"$fromdir/mid/one-for-all"
|
||||
echo cvsin >"$fromdir/mid/for/one-in-one-out"
|
||||
echo expunged >"$fromdir/mid/for/foo/extra"
|
||||
echo retained >"$fromdir/mid/for/foo/keep"
|
||||
ln -s too "$fromdir/bar/down/to/foo/sym"
|
||||
|
||||
# Setup our test exclude/include file.
|
||||
# Setup our test exclude/include files.
|
||||
|
||||
excl="$scratchdir/exclude-from"
|
||||
cat >"$excl" <<EOF
|
||||
@@ -52,6 +60,10 @@ cat >"$excl" <<EOF
|
||||
- /mid/for/foo/extra
|
||||
EOF
|
||||
|
||||
cat >"$scratchdir/.cvsignore" <<EOF
|
||||
home-cvs-exclude
|
||||
EOF
|
||||
|
||||
# Create the chk dir with what we expect to be excluded
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
@@ -70,6 +82,23 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files.
|
||||
|
||||
checkit "$RSYNC -avv --exclude-from=$excl \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv --exclude-from=\"$excl\" \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir by removing cvs-ignored files and then tweaking the dir times.
|
||||
|
||||
rm "$chkdir"/foo/*.old
|
||||
rm "$chkdir"/bar/down/to/foo/*.bak
|
||||
rm "$chkdir"/bar/down/to/foo/*.junk
|
||||
rm "$chkdir"/bar/down/to/home-cvs-exclude
|
||||
rm "$chkdir"/mid/one-in-one-out
|
||||
|
||||
$RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files, this time with --cvs-exclude
|
||||
# and --delete-excluded.
|
||||
|
||||
checkit "$RSYNC -avvC --exclude-from=\"$excl\" \
|
||||
--delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -11,18 +11,19 @@ hands_setup
|
||||
|
||||
# Main script starts here
|
||||
|
||||
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
runtest "basic operation" 'checkit "$RSYNC -av \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
ln ${FROM}/filelist ${FROM}/dir
|
||||
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
ln "$fromdir/filelist" "$fromdir/dir"
|
||||
runtest "hard links" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
rm ${TO}/text
|
||||
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
rm "$todir/text"
|
||||
runtest "one file" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
echo "extra line" >> ${TO}/text
|
||||
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
echo "extra line" >> "$todir/text"
|
||||
runtest "extra data" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
cp ${FROM}/text ${TO}/ThisShouldGo
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
cp "$fromdir/text" "$todir/ThisShouldGo"
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# specify -H, then hard links are detected and recreated as hardlinks
|
||||
# on the other end.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
@@ -33,6 +33,5 @@ cp "$name2" "$name4" || fail "Can't copy file"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've won
|
||||
|
||||
|
||||
@@ -11,11 +11,14 @@
|
||||
|
||||
hands_setup
|
||||
|
||||
LONGNAME=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
LONGDIR=$FROM/$LONGNAME/$LONGNAME/$LONGNAME
|
||||
longname=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
longdir="$fromdir/$longname/$longname/$longname"
|
||||
|
||||
makepath $LONGDIR || test_skipped "unable to create long directory"
|
||||
touch $LONGDIR/1 || test_skipped "unable to create files in long directory"
|
||||
date > ${LONGDIR}/1
|
||||
ls -la / > ${LONGDIR}/2
|
||||
checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}
|
||||
makepath "$longdir" || test_skipped "unable to create long directory"
|
||||
touch "$longdir/1" || test_skipped "unable to create files in long directory"
|
||||
date > "$longdir/1"
|
||||
ls -la / > "$longdir/2"
|
||||
checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
48
testsuite/merge.test
Normal file
48
testsuite/merge.test
Normal file
@@ -0,0 +1,48 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Make sure we can merge files from multiple directories into one.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
from1dir="${fromdir}1"
|
||||
from2dir="${fromdir}2"
|
||||
from3dir="${fromdir}3"
|
||||
|
||||
mkdir "$from1dir" "$from2dir" "$from3dir"
|
||||
mkdir "$from2dir"/sub1 "$from3dir"/sub1
|
||||
mkdir "$from3dir"/sub2
|
||||
mkdir "$chkdir" "$chkdir"/sub1 "$chkdir"/sub2
|
||||
echo "one" >"$from1dir"/one
|
||||
cp -p "$from1dir"/one "$from2dir"/one
|
||||
cp -p "$from1dir"/one "$from3dir"/one
|
||||
echo "two" >"$from1dir"/two
|
||||
echo "three" >"$from2dir"/three
|
||||
echo "four" >"$from3dir"/four
|
||||
echo "five" >"$from1dir"/five
|
||||
echo "six" >"$from3dir"/six
|
||||
echo "sub1" >"$from2dir"/sub1/uno
|
||||
cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/uno
|
||||
echo "sub2" >"$from3dir"/sub1/dos
|
||||
echo "sub3" >"$from2dir"/sub1/tres
|
||||
echo "subby" >"$from3dir"/sub2/subby
|
||||
|
||||
cp -p "$from1dir"/one "$from1dir"/two "$from2dir"/three "$from3dir"/four "$from1dir"/five "$from3dir"/six "$chkdir"
|
||||
cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/dos "$from2dir"/sub1/tres "$chkdir"/sub1
|
||||
cp -p "$from3dir"/sub2/subby "$chkdir"/sub2
|
||||
|
||||
# Get rid of any directory-time differences
|
||||
$RSYNC -av --existing --include='*/' --exclude='*' "$from1dir/" "$from2dir/" "$from3dir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$from1dir/\" \"$from2dir/\" \"$from3dir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -18,16 +18,15 @@
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
TMP="$scratchdir"
|
||||
FROM=${TMP}/from
|
||||
TO=${TMP}/to
|
||||
LOG=${TMP}/log
|
||||
RSYNC="$rsync_bin"
|
||||
tmpdir="$scratchdir"
|
||||
fromdir="$tmpdir/from"
|
||||
todir="$tmpdir/to"
|
||||
chkdir="$tmpdir/chk"
|
||||
|
||||
# Berkley's nice.
|
||||
PATH="$PATH:/usr/ucb"
|
||||
|
||||
if diff -u $srcdir/testsuite/rsync.fns $srcdir/testsuite/rsync.fns >/dev/null 2>&1; then
|
||||
if diff -u "$srcdir/testsuite/rsync.fns" "$srcdir/testsuite/rsync.fns" >/dev/null 2>&1; then
|
||||
diffopt="-u"
|
||||
else
|
||||
diffopt="-c"
|
||||
@@ -37,10 +36,10 @@ runtest() {
|
||||
echo $ECHO_N "Test $1: $ECHO_C"
|
||||
if eval "$2"
|
||||
then
|
||||
echo "${ECHO_T} done."
|
||||
echo "$ECHO_T done."
|
||||
return 0
|
||||
else
|
||||
echo "${ECHO_T} failed!"
|
||||
echo "$ECHO_T failed!"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -60,16 +59,16 @@ rsync_getgroups() {
|
||||
|
||||
|
||||
####################
|
||||
# Build test directories TO and FROM, with FROM full of files.
|
||||
# Build test directories $todir and $fromdir, with $fromdir full of files.
|
||||
|
||||
hands_setup() {
|
||||
# Clean before creation
|
||||
rm -rf $FROM
|
||||
rm -rf $TO
|
||||
rm -rf "$fromdir"
|
||||
rm -rf "$todir"
|
||||
|
||||
[ -d $TMP ] || mkdir $TMP
|
||||
[ -d $FROM ] || mkdir $FROM
|
||||
[ -d $TO ] || mkdir $TO
|
||||
[ -d "$tmpdir" ] || mkdir "$tmpdir"
|
||||
[ -d "$fromdir" ] || mkdir "$fromdir"
|
||||
[ -d "$todir" ] || mkdir "$todir"
|
||||
|
||||
# On some BSD systems, the umask affects the mode of created
|
||||
# symlinks, even though the mode apparently has no effect on how
|
||||
@@ -82,29 +81,37 @@ hands_setup() {
|
||||
# the same. So, we need to set our umask before doing any creations.
|
||||
|
||||
# set up test data
|
||||
touch ${FROM}/empty
|
||||
mkdir ${FROM}/emptydir
|
||||
touch "$fromdir/empty"
|
||||
mkdir "$fromdir/emptydir"
|
||||
|
||||
# a hundred lines of text or so
|
||||
rsync_ls_lR "${srcdir}" > ${FROM}/filelist
|
||||
rsync_ls_lR "$srcdir" > "$fromdir/filelist"
|
||||
|
||||
# This might fail on systems that don't have -n
|
||||
echo $ECHO_N "This file has no trailing lf$ECHO_C" > ${FROM}/nolf
|
||||
echo $ECHO_N "This file has no trailing lf$ECHO_C" > "$fromdir/nolf"
|
||||
umask 0
|
||||
ln -s nolf ${FROM}/nolf-symlink
|
||||
ln -s nolf "$fromdir/nolf-symlink"
|
||||
umask 022
|
||||
|
||||
cat $srcdir/*.c > ${FROM}/text
|
||||
mkdir ${FROM}/dir
|
||||
cp ${FROM}/text ${FROM}/dir
|
||||
mkdir ${FROM}/dir/subdir
|
||||
mkdir ${FROM}/dir/subdir/subsubdir
|
||||
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
|
||||
mkdir ${FROM}/dir/subdir/subsubdir2
|
||||
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
|
||||
cat $srcdir/*.c > "$fromdir/text"
|
||||
mkdir "$fromdir/dir"
|
||||
cp "$fromdir/text" "$fromdir/dir"
|
||||
mkdir "$fromdir/dir/subdir"
|
||||
echo some data > "$fromdir/dir/subdir/foobar.baz"
|
||||
mkdir "$fromdir/dir/subdir/subsubdir"
|
||||
if [ -r /etc ]; then
|
||||
ls -ltr /etc > "$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
else
|
||||
ls -ltr / > "$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
fi
|
||||
mkdir "$fromdir/dir/subdir/subsubdir2"
|
||||
if [ -r /bin ]; then
|
||||
ls -lt /bin > "$fromdir/dir/subdir/subsubdir2/bin-lt-list"
|
||||
else
|
||||
ls -lt / > "$fromdir/dir/subdir/subsubdir2/bin-lt-list"
|
||||
fi
|
||||
|
||||
# echo testing head:
|
||||
# ls -lR ${srcdir} | head -10 || echo failed
|
||||
# ls -lR "$srcdir" | head -10 || echo failed
|
||||
}
|
||||
|
||||
|
||||
@@ -169,10 +176,10 @@ checkit() {
|
||||
echo "-------------"
|
||||
echo "check how the directory listings compare with diff:"
|
||||
echo ""
|
||||
( cd "$2" && rsync_ls_lR . ) > ${TMP}/ls-from
|
||||
( cd "$3" && rsync_ls_lR . ) > ${TMP}/ls-to
|
||||
diff $diffopt ${TMP}/ls-from ${TMP}/ls-to || failed=YES
|
||||
if [ -z "${failed}" ] ; then
|
||||
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
|
||||
( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
|
||||
if [ -z "$failed" ] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@@ -189,31 +196,31 @@ build_rsyncd_conf() {
|
||||
pidfile="$scratchdir/rsyncd.pid"
|
||||
logfile="$scratchdir/rsyncd.log"
|
||||
|
||||
cat >$conf <<EOF
|
||||
cat >"$conf" <<EOF
|
||||
# rsyncd configuration file autogenerated by $0
|
||||
|
||||
pid file = $pidfile
|
||||
use chroot = no
|
||||
hosts allow = localhost, 127.0.0.1
|
||||
log file = $logfile
|
||||
exclude = foobar.baz
|
||||
max verbosity = 9
|
||||
|
||||
uid = 0
|
||||
gid = 0
|
||||
|
||||
[test-from]
|
||||
path = $FROM
|
||||
path = $fromdir
|
||||
read only = yes
|
||||
|
||||
[test-to]
|
||||
path = $TO
|
||||
path = $todir
|
||||
read only = no
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
build_symlinks() {
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
mkdir "$fromdir"
|
||||
date >"$fromdir/referent"
|
||||
ln -s referent "$fromdir/relative"
|
||||
@@ -229,7 +236,7 @@ test_fail() {
|
||||
|
||||
test_skipped() {
|
||||
echo "$@" >&2
|
||||
echo "$@" > "$TMP/whyskipped"
|
||||
echo "$@" > "$tmpdir/whyskipped"
|
||||
exit 77
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ if ! [ "`ssh -o'BatchMode yes' localhost echo yes`" = "yes" ]; then
|
||||
fi
|
||||
|
||||
# Added by Steve Bonds Feb 2 2003
|
||||
# Without this, there are no files in the ${FROM} directory, so rsync has
|
||||
# Without this, there are no files in the $fromdir directory, so rsync has
|
||||
# nothing to do.
|
||||
hands_setup
|
||||
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
# Added by Steve Bonds Feb 2 2003
|
||||
# I assumed that "F1" was intended to hold a single file for testing if
|
||||
@@ -36,8 +36,8 @@ runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FRO
|
||||
# it was unset so the "mv" tried to move a parent directory into a
|
||||
# subdirectory of itself. There is probably a better way of pulling out
|
||||
# a sample file to rename.
|
||||
F1=`ls ${TO} | head -5 | tail -1`
|
||||
F1=`ls "$todir" | head -5 | tail -1`
|
||||
|
||||
mv ${TO}/${F1} ${TO}/ThisShouldGo
|
||||
mv "$todir/$F1" "$todir/ThisShouldGo"
|
||||
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Test rsync's somewhat over-featured symlink control: the default
|
||||
# behaviour is that symlinks should not be copied at all.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
@@ -18,23 +18,22 @@ build_symlinks || test_fail "failed to build symlinks"
|
||||
# should be missing.
|
||||
$RSYNC -r "$fromdir/" "$todir" || test_fail "$RSYNC returned $?"
|
||||
|
||||
[ -f "${todir}/referent" ] || test_fail "referent was not copied"
|
||||
[ -d "${todir}/from" ] && test_fail "extra level of directories"
|
||||
if is_a_link "${todir}/dangling"
|
||||
[ -f "$todir/referent" ] || test_fail "referent was not copied"
|
||||
[ -d "$todir/from" ] && test_fail "extra level of directories"
|
||||
if is_a_link "$todir/dangling"
|
||||
then
|
||||
test_fail "dangling symlink was copied"
|
||||
fi
|
||||
|
||||
if is_a_link "${todir}/relative"
|
||||
if is_a_link "$todir/relative"
|
||||
then
|
||||
test_fail "relative symlink was copied"
|
||||
fi
|
||||
|
||||
if is_a_link "${todir}/absolute"
|
||||
if is_a_link "$todir/absolute"
|
||||
then
|
||||
test_fail "absolute symlink was copied"
|
||||
fi
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
# last [] may have failed but if we get here then we've one
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
# Test tiny function to trim trailing slashes.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
@@ -24,4 +24,5 @@ diff $diffopt "$scratchdir/slash.out" - <<EOF
|
||||
/Users/Wierd Macintosh Name/// Ooh, translucent plastic
|
||||
EOF
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
# Call directly into unsafe_symlink and test its handling of various filenames
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
test_unsafe() {
|
||||
# $1 is the target of a symlink
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Originally by Vladim<69>r Michl <Vladimir.Michl@hlubocky.del.cz>
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
test_symlink() {
|
||||
is_a_link "$1" || test_fail "File $1 is not a symlink"
|
||||
@@ -14,7 +14,7 @@ test_regular() {
|
||||
fi;
|
||||
};
|
||||
|
||||
cd "$TMP"
|
||||
cd "$tmpdir"
|
||||
|
||||
mkdir from
|
||||
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
|
||||
# Test the wildmatch functionality
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
"$TOOLDIR/wildtest" >"$scratchdir/wild.out"
|
||||
"$TOOLDIR/wildtest" "$srcdir/wildtest.txt" >"$scratchdir/wild.out"
|
||||
diff $diffopt "$scratchdir/wild.out" - <<EOF
|
||||
No wildmatch errors found.
|
||||
EOF
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
49
tls.c
49
tls.c
@@ -1,16 +1,16 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -49,17 +49,16 @@ int list_only = 0;
|
||||
int preserve_perms = 0;
|
||||
|
||||
|
||||
static void failed (char const *what,
|
||||
char const *where)
|
||||
static void failed(char const *what, char const *where)
|
||||
{
|
||||
fprintf (stderr, PROGRAM ": %s %s: %s\n",
|
||||
what, where, strerror (errno));
|
||||
exit (1);
|
||||
fprintf(stderr, PROGRAM ": %s %s: %s\n",
|
||||
what, where, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void list_file (const char *fname)
|
||||
static void list_file(const char *fname)
|
||||
{
|
||||
STRUCT_STAT buf;
|
||||
char permbuf[PERMSTRING_SIZE];
|
||||
@@ -68,7 +67,7 @@ static void list_file (const char *fname)
|
||||
char linkbuf[4096];
|
||||
|
||||
if (do_lstat(fname, &buf) == -1)
|
||||
failed ("stat", fname);
|
||||
failed("stat", fname);
|
||||
|
||||
/* The size of anything but a regular file is probably not
|
||||
* worth thinking about. */
|
||||
@@ -86,7 +85,7 @@ static void list_file (const char *fname)
|
||||
strcpy(linkbuf, " -> ");
|
||||
/* const-cast required for silly UNICOS headers */
|
||||
len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
|
||||
if (len == -1)
|
||||
if (len == -1)
|
||||
failed("readlink", fname);
|
||||
else
|
||||
/* it's not nul-terminated */
|
||||
@@ -99,7 +98,7 @@ static void list_file (const char *fname)
|
||||
|
||||
if (buf.st_mtime) {
|
||||
mt = gmtime(&buf.st_mtime);
|
||||
|
||||
|
||||
sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
mt->tm_year + 1900,
|
||||
mt->tm_mon + 1,
|
||||
@@ -110,16 +109,18 @@ static void list_file (const char *fname)
|
||||
} else {
|
||||
strcpy(datebuf, " ");
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Perhaps escape special characters in fname? */
|
||||
|
||||
|
||||
/* NB: need to pass size as a double because it might be be
|
||||
* too large for a long. */
|
||||
printf("%s %12.0f %6ld.%-6ld %6d %s %s%s\n",
|
||||
permbuf, (double) buf.st_size,
|
||||
(long) buf.st_uid, (long) buf.st_gid,
|
||||
buf.st_nlink,
|
||||
|
||||
printf("%s ", permbuf);
|
||||
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
|
||||
printf("%5ld,%6ld",
|
||||
(long)major(buf.st_rdev),
|
||||
(long)minor(buf.st_rdev));
|
||||
} else /* NB: use double for size since it might not fit in a long. */
|
||||
printf("%12.0f", (double)buf.st_size);
|
||||
printf(" %6ld.%-6ld %6ld %s %s%s\n",
|
||||
(long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
|
||||
datebuf, fname, linkbuf);
|
||||
}
|
||||
|
||||
@@ -128,13 +129,13 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf (stderr, "usage: " PROGRAM " DIR ...\n"
|
||||
"Trivial file listing program for portably checking rsync\n");
|
||||
fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
|
||||
"Trivial file listing program for portably checking rsync\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (argv++; *argv; argv++) {
|
||||
list_file (*argv);
|
||||
list_file(*argv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
66
token.c
66
token.c
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -21,23 +21,26 @@
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
extern int do_compression;
|
||||
extern int module_id;
|
||||
|
||||
static int compression_level = Z_DEFAULT_COMPRESSION;
|
||||
|
||||
/* determine the compression level based on a wildcard filename list */
|
||||
void set_compression(char *fname)
|
||||
{
|
||||
extern int module_id;
|
||||
char *dont;
|
||||
char *tok;
|
||||
|
||||
if (!do_compression) return;
|
||||
if (!do_compression)
|
||||
return;
|
||||
|
||||
compression_level = Z_DEFAULT_COMPRESSION;
|
||||
dont = lp_dont_compress(module_id);
|
||||
|
||||
if (!dont || !*dont) return;
|
||||
if (!dont || !*dont)
|
||||
return;
|
||||
|
||||
if ((dont[0] == '*') && (!dont[1])) {
|
||||
if (dont[0] == '*' && !dont[1]) {
|
||||
/* an optimization to skip the rest of this routine */
|
||||
compression_level = 0;
|
||||
return;
|
||||
@@ -45,12 +48,13 @@ void set_compression(char *fname)
|
||||
|
||||
dont = strdup(dont);
|
||||
fname = strdup(fname);
|
||||
if (!dont || !fname) return;
|
||||
if (!dont || !fname)
|
||||
return;
|
||||
|
||||
strlower(dont);
|
||||
strlower(fname);
|
||||
|
||||
for (tok=strtok(dont," ");tok;tok=strtok(NULL," ")) {
|
||||
for (tok = strtok(dont, " "); tok; tok = strtok(NULL, " ")) {
|
||||
if (wildmatch(tok, fname)) {
|
||||
compression_level = 0;
|
||||
break;
|
||||
@@ -69,12 +73,14 @@ static int simple_recv_token(int f,char **data)
|
||||
|
||||
if (!buf) {
|
||||
buf = new_array(char, CHUNK_SIZE);
|
||||
if (!buf) out_of_memory("simple_recv_token");
|
||||
if (!buf)
|
||||
out_of_memory("simple_recv_token");
|
||||
}
|
||||
|
||||
if (residue == 0) {
|
||||
int i = read_int(f);
|
||||
if (i <= 0) return i;
|
||||
if (i <= 0)
|
||||
return i;
|
||||
residue = i;
|
||||
}
|
||||
|
||||
@@ -90,29 +96,18 @@ static int simple_recv_token(int f,char **data)
|
||||
static void simple_send_token(int f,int token,
|
||||
struct map_struct *buf,OFF_T offset,int n)
|
||||
{
|
||||
extern int write_batch;
|
||||
int hold_int;
|
||||
|
||||
if (n > 0) {
|
||||
int l = 0;
|
||||
while (l < n) {
|
||||
int n1 = MIN(CHUNK_SIZE,n-l);
|
||||
write_int(f,n1);
|
||||
write_buf(f,map_ptr(buf,offset+l,n1),n1);
|
||||
if (write_batch) {
|
||||
write_batch_delta_file( (char *) &n1, sizeof(int) );
|
||||
write_batch_delta_file(map_ptr(buf,offset+l,n1),n1);
|
||||
}
|
||||
l += n1;
|
||||
}
|
||||
}
|
||||
/* a -2 token means to send data only and no token */
|
||||
if (token != -2) {
|
||||
write_int(f,-(token+1));
|
||||
if (write_batch) {
|
||||
hold_int = -(token+1);
|
||||
write_batch_delta_file( (char *) &hold_int, sizeof(int) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,8 +154,6 @@ send_deflated_token(int f, int token,
|
||||
{
|
||||
int n, r;
|
||||
static int init_done, flush_pending;
|
||||
extern int write_batch;
|
||||
char temp_byte;
|
||||
|
||||
if (last_token == -1) {
|
||||
/* initialization */
|
||||
@@ -193,27 +186,13 @@ send_deflated_token(int f, int token,
|
||||
n = last_token - run_start;
|
||||
if (r >= 0 && r <= 63) {
|
||||
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
|
||||
if (write_batch) {
|
||||
temp_byte = (char)( (n==0? TOKEN_REL: TOKENRUN_REL) + r);
|
||||
write_batch_delta_file(&temp_byte,sizeof(char));
|
||||
}
|
||||
} else {
|
||||
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
|
||||
write_int(f, run_start);
|
||||
if (write_batch) {
|
||||
temp_byte = (char)(n==0? TOKEN_LONG: TOKENRUN_LONG);
|
||||
write_batch_delta_file(&temp_byte,sizeof(temp_byte));
|
||||
write_batch_delta_file((char *)&run_start,sizeof(run_start));
|
||||
}
|
||||
}
|
||||
if (n != 0) {
|
||||
write_byte(f, n);
|
||||
write_byte(f, n >> 8);
|
||||
if (write_batch) {
|
||||
write_batch_delta_file((char *)&n,sizeof(char));
|
||||
temp_byte = (char)(n >> 8);
|
||||
write_batch_delta_file(&temp_byte,sizeof(temp_byte));
|
||||
}
|
||||
}
|
||||
last_run_end = last_token;
|
||||
run_start = token;
|
||||
@@ -272,8 +251,6 @@ send_deflated_token(int f, int token,
|
||||
obuf[0] = DEFLATED_DATA + (n >> 8);
|
||||
obuf[1] = n;
|
||||
write_buf(f, obuf, n+2);
|
||||
if (write_batch)
|
||||
write_batch_delta_file(obuf,n+2);
|
||||
}
|
||||
}
|
||||
} while (nb != 0 || tx_strm.avail_out == 0);
|
||||
@@ -283,11 +260,6 @@ send_deflated_token(int f, int token,
|
||||
if (token == -1) {
|
||||
/* end of file - clean up */
|
||||
write_byte(f, END_FLAG);
|
||||
if (write_batch) {
|
||||
temp_byte = END_FLAG;
|
||||
write_batch_delta_file((char *)&temp_byte,sizeof(temp_byte));
|
||||
}
|
||||
|
||||
} else if (token != -2) {
|
||||
/* add the data in the current block to the compressor's
|
||||
history and hash table */
|
||||
@@ -490,7 +462,7 @@ static void see_deflate_token(char *buf, int len)
|
||||
|
||||
/**
|
||||
* Transmit a verbatim buffer of length @p n followed by a token.
|
||||
* If token == -1 then we have reached EOF
|
||||
* If token == -1 then we have reached EOF
|
||||
* If n == 0 then don't send a buffer
|
||||
*/
|
||||
void send_token(int f,int token,struct map_struct *buf,OFF_T offset,
|
||||
|
||||
335
uidlist.c
335
uidlist.c
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -19,12 +19,19 @@
|
||||
|
||||
/* handle the mapping of uid/gid and user/group names between systems.
|
||||
If the source username/group does not exist on the target then use
|
||||
the numeric ids. Never do any mapping for uid=0 or gid=0 as these
|
||||
the numeric IDs. Never do any mapping for uid=0 or gid=0 as these
|
||||
are special.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
# if !defined(GETGROUPS_T)
|
||||
# define GETGROUPS_T gid_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int numeric_ids;
|
||||
@@ -39,24 +46,26 @@ struct idlist {
|
||||
static struct idlist *uidlist;
|
||||
static struct idlist *gidlist;
|
||||
|
||||
static struct idlist *add_list(int id, char *name)
|
||||
static struct idlist *add_to_list(struct idlist **root, int id, char *name,
|
||||
int id2)
|
||||
{
|
||||
struct idlist *list = new(struct idlist);
|
||||
if (!list) out_of_memory("add_list");
|
||||
list->next = NULL;
|
||||
list->name = strdup(name);
|
||||
if (!list->name) out_of_memory("add_list");
|
||||
list->id = (int)id;
|
||||
return list;
|
||||
struct idlist *node = new(struct idlist);
|
||||
if (!node)
|
||||
out_of_memory("add_to_list");
|
||||
node->next = *root;
|
||||
node->name = name;
|
||||
node->id = id;
|
||||
node->id2 = id2;
|
||||
*root = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* turn a uid into a user name */
|
||||
static char *uid_to_name(uid_t uid)
|
||||
{
|
||||
struct passwd *pass = getpwuid(uid);
|
||||
if (pass) return(pass->pw_name);
|
||||
if (pass)
|
||||
return strdup(pass->pw_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -64,14 +73,15 @@ static char *uid_to_name(uid_t uid)
|
||||
static char *gid_to_name(gid_t gid)
|
||||
{
|
||||
struct group *grp = getgrgid(gid);
|
||||
if (grp) return(grp->gr_name);
|
||||
if (grp)
|
||||
return strdup(grp->gr_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int map_uid(int id, char *name)
|
||||
{
|
||||
uid_t uid;
|
||||
if (name_to_uid(name, &uid) && uid != 0)
|
||||
if (id != 0 && name_to_uid(name, &uid))
|
||||
return uid;
|
||||
return id;
|
||||
}
|
||||
@@ -79,113 +89,180 @@ static int map_uid(int id, char *name)
|
||||
static int map_gid(int id, char *name)
|
||||
{
|
||||
gid_t gid;
|
||||
if (name_to_gid(name, &gid) && gid != 0)
|
||||
if (id != 0 && name_to_gid(name, &gid))
|
||||
return gid;
|
||||
return id;
|
||||
}
|
||||
|
||||
static int is_in_group(gid_t gid)
|
||||
{
|
||||
#ifdef HAVE_GETGROUPS
|
||||
static gid_t last_in = GID_NONE, last_out;
|
||||
static int ngroups = -2;
|
||||
static GETGROUPS_T *gidset;
|
||||
int n;
|
||||
|
||||
if (gid == last_in)
|
||||
return last_out;
|
||||
if (ngroups < -1) {
|
||||
gid_t mygid = MY_GID();
|
||||
if ((ngroups = getgroups(0, NULL)) < 0)
|
||||
ngroups = 0;
|
||||
gidset = new_array(GETGROUPS_T, ngroups+1);
|
||||
if (!gidset)
|
||||
out_of_memory("is_in_group");
|
||||
if (ngroups > 0)
|
||||
ngroups = getgroups(ngroups, gidset);
|
||||
/* The default gid might not be in the list on some systems. */
|
||||
for (n = 0; n < ngroups; n++) {
|
||||
if (gidset[n] == mygid)
|
||||
break;
|
||||
}
|
||||
if (n == ngroups)
|
||||
gidset[ngroups++] = mygid;
|
||||
if (verbose > 3) {
|
||||
int pos;
|
||||
char *gidbuf = new_array(char, ngroups*21+32);
|
||||
if (!gidbuf)
|
||||
out_of_memory("is_in_group");
|
||||
sprintf(gidbuf, "process has %d gid%s: ",
|
||||
ngroups, ngroups == 1? "" : "s");
|
||||
pos = strlen(gidbuf);
|
||||
for (n = 0; n < ngroups; n++) {
|
||||
sprintf(gidbuf+pos, " %d", (int)gidset[n]);
|
||||
pos += strlen(gidbuf+pos);
|
||||
}
|
||||
rprintf(FINFO, "%s\n", gidbuf);
|
||||
free(gidbuf);
|
||||
}
|
||||
}
|
||||
|
||||
last_in = gid;
|
||||
for (n = 0; n < ngroups; n++) {
|
||||
if (gidset[n] == gid)
|
||||
return last_out = 1;
|
||||
}
|
||||
return last_out = 0;
|
||||
|
||||
#else
|
||||
static gid_t mygid = GID_NONE;
|
||||
if (mygid == GID_NONE) {
|
||||
mygid = MY_GID();
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "process has gid %d\n", (int)mygid);
|
||||
}
|
||||
return gid == mygid;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Add a uid to the list of uids. Only called on receiving side. */
|
||||
static struct idlist *recv_add_uid(int id, char *name)
|
||||
{
|
||||
int id2 = name ? map_uid(id, name) : id;
|
||||
struct idlist *node;
|
||||
|
||||
node = add_to_list(&uidlist, id, name, id2);
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "uid %d(%s) maps to %d\n",
|
||||
id, name ? name : "", id2);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Add a gid to the list of gids. Only called on receiving side. */
|
||||
static struct idlist *recv_add_gid(int id, char *name)
|
||||
{
|
||||
int id2 = name ? map_gid(id, name) : id;
|
||||
struct idlist *node;
|
||||
|
||||
if (!am_root && !is_in_group(id2))
|
||||
id2 = GID_NONE;
|
||||
node = add_to_list(&gidlist, id, name, id2);
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "gid %d(%s) maps to %d\n",
|
||||
id, name ? name : "", id2);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* this function is a definate candidate for a faster algorithm */
|
||||
static uid_t match_uid(uid_t uid)
|
||||
{
|
||||
static uid_t last_in, last_out;
|
||||
struct idlist *list = uidlist;
|
||||
struct idlist *list;
|
||||
|
||||
if (uid == last_in) return last_out;
|
||||
if (uid == 0)
|
||||
return 0;
|
||||
|
||||
if (uid == last_in)
|
||||
return last_out;
|
||||
|
||||
last_in = uid;
|
||||
|
||||
while (list) {
|
||||
if (list->id == (int)uid) {
|
||||
last_out = (uid_t)list->id2;
|
||||
return last_out;
|
||||
}
|
||||
list = list->next;
|
||||
for (list = uidlist; list; list = list->next) {
|
||||
if (list->id == (int)uid)
|
||||
return last_out = (uid_t)list->id2;
|
||||
}
|
||||
|
||||
last_out = uid;
|
||||
return last_out;
|
||||
|
||||
return last_out = uid;
|
||||
}
|
||||
|
||||
static gid_t match_gid(gid_t gid)
|
||||
{
|
||||
static gid_t last_in, last_out;
|
||||
struct idlist *list = gidlist;
|
||||
static gid_t last_in = GID_NONE, last_out = GID_NONE;
|
||||
struct idlist *list;
|
||||
|
||||
if (gid == last_in) return last_out;
|
||||
if (gid == GID_NONE)
|
||||
return GID_NONE;
|
||||
|
||||
if (gid == last_in)
|
||||
return last_out;
|
||||
|
||||
last_in = gid;
|
||||
|
||||
while (list) {
|
||||
if (list->id == (int)gid) {
|
||||
last_out = (gid_t)list->id2;
|
||||
return last_out;
|
||||
}
|
||||
list = list->next;
|
||||
for (list = gidlist; list; list = list->next) {
|
||||
if (list->id == (int)gid)
|
||||
return last_out = (gid_t)list->id2;
|
||||
}
|
||||
|
||||
if (am_root)
|
||||
last_out = gid;
|
||||
else
|
||||
last_out = (gid_t) -1;
|
||||
return last_out;
|
||||
|
||||
list = recv_add_gid(gid, NULL);
|
||||
return last_out = list->id2;
|
||||
}
|
||||
|
||||
/* add a uid to the list of uids */
|
||||
/* Add a uid to the list of uids. Only called on sending side. */
|
||||
void add_uid(uid_t uid)
|
||||
{
|
||||
struct idlist *list = uidlist;
|
||||
char *name;
|
||||
struct idlist *list;
|
||||
|
||||
if (numeric_ids) return;
|
||||
|
||||
/* don't map root */
|
||||
if (uid==0) return;
|
||||
|
||||
if (!list) {
|
||||
if (!(name = uid_to_name(uid))) return;
|
||||
uidlist = add_list((int)uid, name);
|
||||
if (uid == 0) /* don't map root */
|
||||
return;
|
||||
|
||||
for (list = uidlist; list; list = list->next) {
|
||||
if (list->id == (int)uid)
|
||||
return;
|
||||
}
|
||||
|
||||
while (list->next) {
|
||||
if (list->id == (int)uid) return;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (list->id == (int)uid) return;
|
||||
|
||||
if (!(name = uid_to_name(uid))) return;
|
||||
|
||||
list->next = add_list((int)uid, name);
|
||||
add_to_list(&uidlist, (int)uid, uid_to_name(uid), 0);
|
||||
}
|
||||
|
||||
/* add a gid to the list of gids */
|
||||
/* Add a gid to the list of gids. Only called on sending side. */
|
||||
void add_gid(gid_t gid)
|
||||
{
|
||||
struct idlist *list = gidlist;
|
||||
char *name;
|
||||
struct idlist *list;
|
||||
|
||||
if (numeric_ids) return;
|
||||
|
||||
/* don't map root */
|
||||
if (gid==0) return;
|
||||
|
||||
if (!list) {
|
||||
if (!(name = gid_to_name(gid))) return;
|
||||
gidlist = add_list((int)gid, name);
|
||||
if (gid == 0) /* don't map root */
|
||||
return;
|
||||
|
||||
for (list = gidlist; list; list = list->next) {
|
||||
if (list->id == (int)gid)
|
||||
return;
|
||||
}
|
||||
|
||||
while (list->next) {
|
||||
if (list->id == (int)gid) return;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (list->id == (int)gid) return;
|
||||
|
||||
if (!(name = gid_to_name(gid))) return;
|
||||
|
||||
list->next = add_list((int)gid, name);
|
||||
add_to_list(&gidlist, (int)gid, gid_to_name(gid), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,102 +271,80 @@ void send_uid_list(int f)
|
||||
{
|
||||
struct idlist *list;
|
||||
|
||||
if (numeric_ids) return;
|
||||
if (numeric_ids)
|
||||
return;
|
||||
|
||||
if (preserve_uid) {
|
||||
int len;
|
||||
/* we send sequences of uid/byte-length/name */
|
||||
list = uidlist;
|
||||
while (list) {
|
||||
int len = strlen(list->name);
|
||||
for (list = uidlist; list; list = list->next) {
|
||||
if (!list->name)
|
||||
continue;
|
||||
len = strlen(list->name);
|
||||
write_int(f, list->id);
|
||||
write_byte(f, len);
|
||||
write_buf(f, list->name, len);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* terminate the uid list with a 0 uid. We explicitly exclude
|
||||
0 from the list */
|
||||
* 0 from the list */
|
||||
write_int(f, 0);
|
||||
}
|
||||
|
||||
if (preserve_gid) {
|
||||
list = gidlist;
|
||||
while (list) {
|
||||
int len = strlen(list->name);
|
||||
int len;
|
||||
for (list = gidlist; list; list = list->next) {
|
||||
if (!list->name)
|
||||
continue;
|
||||
len = strlen(list->name);
|
||||
write_int(f, list->id);
|
||||
write_byte(f, len);
|
||||
write_buf(f, list->name, len);
|
||||
list = list->next;
|
||||
}
|
||||
write_int(f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* recv a complete uid/gid mapping from the peer and map the uid/gid
|
||||
in the file list to local names */
|
||||
* in the file list to local names */
|
||||
void recv_uid_list(int f, struct file_list *flist)
|
||||
{
|
||||
int id, i;
|
||||
char *name;
|
||||
struct idlist *list;
|
||||
|
||||
if (numeric_ids) return;
|
||||
|
||||
if (preserve_uid) {
|
||||
if (preserve_uid && !numeric_ids) {
|
||||
/* read the uid list */
|
||||
list = uidlist;
|
||||
id = read_int(f);
|
||||
while (id != 0) {
|
||||
while ((id = read_int(f)) != 0) {
|
||||
int len = read_byte(f);
|
||||
name = new_array(char, len+1);
|
||||
if (!name) out_of_memory("recv_uid_list");
|
||||
if (!name)
|
||||
out_of_memory("recv_uid_list");
|
||||
read_sbuf(f, name, len);
|
||||
if (!list) {
|
||||
uidlist = add_list(id, name);
|
||||
list = uidlist;
|
||||
} else {
|
||||
list->next = add_list(id, name);
|
||||
list = list->next;
|
||||
}
|
||||
list->id2 = map_uid(id, name);
|
||||
free(name);
|
||||
id = read_int(f);
|
||||
recv_add_uid(id, name); /* node keeps name's memory */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (preserve_gid) {
|
||||
/* and the gid list */
|
||||
list = gidlist;
|
||||
id = read_int(f);
|
||||
while (id != 0) {
|
||||
if (preserve_gid && !numeric_ids) {
|
||||
/* read the gid list */
|
||||
while ((id = read_int(f)) != 0) {
|
||||
int len = read_byte(f);
|
||||
name = new_array(char, len+1);
|
||||
if (!name) out_of_memory("recv_uid_list");
|
||||
if (!name)
|
||||
out_of_memory("recv_uid_list");
|
||||
read_sbuf(f, name, len);
|
||||
if (!list) {
|
||||
gidlist = add_list(id, name);
|
||||
list = gidlist;
|
||||
} else {
|
||||
list->next = add_list(id, name);
|
||||
list = list->next;
|
||||
}
|
||||
list->id2 = map_gid(id, name);
|
||||
free(name);
|
||||
id = read_int(f);
|
||||
recv_add_gid(id, name); /* node keeps name's memory */
|
||||
}
|
||||
}
|
||||
|
||||
if (!(am_root && preserve_uid) && !preserve_gid) return;
|
||||
|
||||
/* now convert the uid/gid of all files in the list to the mapped
|
||||
uid/gid */
|
||||
for (i=0;i<flist->count;i++) {
|
||||
if (am_root && preserve_uid && flist->files[i]->uid != 0) {
|
||||
* uid/gid */
|
||||
if (am_root && preserve_uid && !numeric_ids) {
|
||||
for (i = 0; i < flist->count; i++)
|
||||
flist->files[i]->uid = match_uid(flist->files[i]->uid);
|
||||
}
|
||||
if (preserve_gid && flist->files[i]->gid != 0) {
|
||||
}
|
||||
if (preserve_gid && (!am_root || !numeric_ids)) {
|
||||
for (i = 0; i < flist->count; i++)
|
||||
flist->files[i]->gid = match_gid(flist->files[i]->gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
wildtest.c
25
wildtest.c
@@ -19,9 +19,6 @@ int wildmatch_errors = 0;
|
||||
|
||||
typedef char bool;
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
int output_iterations = 0;
|
||||
|
||||
static struct poptOption long_options[] = {
|
||||
@@ -84,8 +81,14 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if ((fp = fopen("wildtest.txt", "r")) == NULL) {
|
||||
fprintf(stderr, "Unable to open wildtest.txt.\n");
|
||||
argv = (char**)poptGetArgs(pc);
|
||||
if (!argv || argv[1]) {
|
||||
fprintf(stderr, "Usage: wildtest TESTFILE\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((fp = fopen(*argv, "r")) == NULL) {
|
||||
fprintf(stderr, "Unable to open %s\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -104,8 +107,8 @@ main(int argc, char **argv)
|
||||
if (*++s != ' ' && *s != '\t')
|
||||
flag[i] = -1;
|
||||
if (flag[i] < 0) {
|
||||
fprintf(stderr, "Invalid flag syntax on line %d of wildtest.txt:%s\n",
|
||||
line, buf);
|
||||
fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s",
|
||||
line, *argv, buf);
|
||||
exit(1);
|
||||
}
|
||||
while (*++s == ' ' || *s == '\t') {}
|
||||
@@ -116,16 +119,16 @@ main(int argc, char **argv)
|
||||
string[i] = s;
|
||||
while (*s && *s != quote) s++;
|
||||
if (!*s) {
|
||||
fprintf(stderr, "Unmatched quote on line %d of wildtest.txt:%s\n",
|
||||
line, buf);
|
||||
fprintf(stderr, "Unmatched quote on line %d of %s:\n%s",
|
||||
line, *argv, buf);
|
||||
exit(1);
|
||||
}
|
||||
end[i] = s;
|
||||
}
|
||||
else {
|
||||
if (!*s || *s == '\n') {
|
||||
fprintf(stderr, "Not enough strings on line %d of wildtest.txt:%s\n",
|
||||
line, buf);
|
||||
fprintf(stderr, "Not enough strings on line %d of %s:\n%s",
|
||||
line, *argv, buf);
|
||||
exit(1);
|
||||
}
|
||||
string[i] = s;
|
||||
|
||||
Reference in New Issue
Block a user