mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-26 07:45:33 -04:00
Compare commits
906 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dfe1c37ad | ||
|
|
b9949780f4 | ||
|
|
5fe857d4be | ||
|
|
3d86c6b18f | ||
|
|
0f0b2e66b8 | ||
|
|
5d24ee71ad | ||
|
|
3a05c5d3ce | ||
|
|
89ec535af5 | ||
|
|
e96d7972c4 | ||
|
|
962a3f0b6e | ||
|
|
cbb5fa4f07 | ||
|
|
b57907efb2 | ||
|
|
26beb7861f | ||
|
|
6e8b9f1341 | ||
|
|
6efe94167f | ||
|
|
51cc96e469 | ||
|
|
bdedced84b | ||
|
|
f497ad722d | ||
|
|
339eb8943e | ||
|
|
c36864e40e | ||
|
|
af6155bb0e | ||
|
|
605fed4b46 | ||
|
|
ac40b74788 | ||
|
|
3e6ddb3738 | ||
|
|
9ac756c6ea | ||
|
|
3b0a30eba8 | ||
|
|
bac7259081 | ||
|
|
4d474ad513 | ||
|
|
e50e82ab40 | ||
|
|
4922175589 | ||
|
|
a289f89fbe | ||
|
|
ba64001df8 | ||
|
|
b225b089b8 | ||
|
|
557a35f55b | ||
|
|
1848fd6fa1 | ||
|
|
f2a4853c93 | ||
|
|
e65154085c | ||
|
|
e4676bb59b | ||
|
|
3b968014c9 | ||
|
|
21b9b93377 | ||
|
|
c4d1b2983d | ||
|
|
7d7a34aeb2 | ||
|
|
65c84700fc | ||
|
|
5a727522f0 | ||
|
|
1599754727 | ||
|
|
d90338cec6 | ||
|
|
d0e94abb40 | ||
|
|
d8c4d6de10 | ||
|
|
74ba98a51b | ||
|
|
c296031d9f | ||
|
|
81c453b16a | ||
|
|
4a34c6f176 | ||
|
|
9b3150bd2e | ||
|
|
6f2245c8fa | ||
|
|
0f9941dc5a | ||
|
|
060f31500b | ||
|
|
7c2a83c635 | ||
|
|
97e3c50cd9 | ||
|
|
b2360dabf6 | ||
|
|
723160280f | ||
|
|
fa92818af3 | ||
|
|
289a32167c | ||
|
|
95e107db96 | ||
|
|
513fd04d21 | ||
|
|
7a16e12207 | ||
|
|
de8252f67f | ||
|
|
98e4741463 | ||
|
|
028245a57b | ||
|
|
2765f2e4a7 | ||
|
|
79db59d1a7 | ||
|
|
c48cff9fbe | ||
|
|
f4b8e829e9 | ||
|
|
468d766819 | ||
|
|
f3ab64d3a8 | ||
|
|
a234bca4ef | ||
|
|
42e9c7eb56 | ||
|
|
9d19f8a5fe | ||
|
|
24e61cffe3 | ||
|
|
3556fe5d86 | ||
|
|
ee887d98f6 | ||
|
|
5c7b1feb4c | ||
|
|
3cd5301f40 | ||
|
|
d8169e6f6b | ||
|
|
c4833b024e | ||
|
|
2a5d5a8cc4 | ||
|
|
f7112154e9 | ||
|
|
f83051b2e3 | ||
|
|
2e42adb302 | ||
|
|
c09ebb8c04 | ||
|
|
042dc7360e | ||
|
|
7a6e294f7b | ||
|
|
97e786c331 | ||
|
|
8ee6adefe3 | ||
|
|
64c37826e4 | ||
|
|
2e8015e0da | ||
|
|
5b6281afcf | ||
|
|
e732fb0c4f | ||
|
|
b10917a426 | ||
|
|
7ae64260e0 | ||
|
|
f97f6bcd3a | ||
|
|
e86d98cbaa | ||
|
|
6afb90778b | ||
|
|
32c7f91a14 | ||
|
|
b28a27e9e9 | ||
|
|
15164c0aa9 | ||
|
|
bf011fedfc | ||
|
|
d7d11b7ebd | ||
|
|
9a929c8f68 | ||
|
|
298d8c0a9b | ||
|
|
a054570942 | ||
|
|
a0009fc30d | ||
|
|
beb51aa09e | ||
|
|
e8a96e275e | ||
|
|
11e758a430 | ||
|
|
d630f53e0d | ||
|
|
5918daf8a4 | ||
|
|
326bb56e40 | ||
|
|
f96154f44c | ||
|
|
45c5b903eb | ||
|
|
5037cf3adf | ||
|
|
180443af42 | ||
|
|
4f3f97fbde | ||
|
|
664cf3278a | ||
|
|
cd36049cd1 | ||
|
|
c2523a0541 | ||
|
|
92739a0aa7 | ||
|
|
cd908ef4ff | ||
|
|
ebd33e0cea | ||
|
|
5f2c5bf110 | ||
|
|
417099fa20 | ||
|
|
626bec8e84 | ||
|
|
a06e2b7cab | ||
|
|
3ae5367ff2 | ||
|
|
b4ef0bca47 | ||
|
|
4313d6f9c0 | ||
|
|
2a0dd9bd70 | ||
|
|
3eeac9bc7e | ||
|
|
67de72bd9b | ||
|
|
552a218468 | ||
|
|
d940151496 | ||
|
|
f5c7f4abe7 | ||
|
|
3ae6c1875d | ||
|
|
1ad6a7f611 | ||
|
|
89d26123ff | ||
|
|
46bffd98cb | ||
|
|
41b84ce012 | ||
|
|
de392f1e5c | ||
|
|
0455cd933d | ||
|
|
d9c0051fae | ||
|
|
126e7affb7 | ||
|
|
624d6be2a5 | ||
|
|
16f960feb5 | ||
|
|
e145d51ba6 | ||
|
|
dcbae65444 | ||
|
|
b4bf2b5a7e | ||
|
|
9baed7609c | ||
|
|
1c2efa1706 | ||
|
|
80a24d52d4 | ||
|
|
af9f56a09d | ||
|
|
ddd74b67be | ||
|
|
7b558d7f8b | ||
|
|
c87ae64a82 | ||
|
|
b9f0ca7274 | ||
|
|
c1759b9fa2 | ||
|
|
9c63d83d3d | ||
|
|
1ed91a04fe | ||
|
|
154cdaaa40 | ||
|
|
33c4b445ef | ||
|
|
53135fe89a | ||
|
|
083acd496d | ||
|
|
00348fd793 | ||
|
|
ddb6fc696b | ||
|
|
f7e48a5cb8 | ||
|
|
70352269ba | ||
|
|
0b94147928 | ||
|
|
da9f59264f | ||
|
|
96b7b48efa | ||
|
|
aea4bf2894 | ||
|
|
855ef72f3f | ||
|
|
98dc857b32 | ||
|
|
94af17a6eb | ||
|
|
00fd35482e | ||
|
|
cc3e0770bc | ||
|
|
e7f7064cc5 | ||
|
|
7b759fe0df | ||
|
|
254ee3baab | ||
|
|
f957e8fdf9 | ||
|
|
822012eea9 | ||
|
|
bb21ecac5b | ||
|
|
648859bda2 | ||
|
|
f328e0f3a8 | ||
|
|
6012eaa183 | ||
|
|
da2a6c1f1c | ||
|
|
0438f100ae | ||
|
|
b95ad9ac55 | ||
|
|
828a256123 | ||
|
|
ebf447ac81 | ||
|
|
124f349ea1 | ||
|
|
26718401fb | ||
|
|
f463e20753 | ||
|
|
1129070514 | ||
|
|
ac3f7b81f8 | ||
|
|
62f9573fb3 | ||
|
|
6d0e5d2e62 | ||
|
|
8b48bf1154 | ||
|
|
42be53201f | ||
|
|
c7791b8cb2 | ||
|
|
7e9059d60f | ||
|
|
f3ebe1a77e | ||
|
|
301fb56ce9 | ||
|
|
aa7a6e878b | ||
|
|
0a39837a62 | ||
|
|
b2e8a9b293 | ||
|
|
a98ad81760 | ||
|
|
ccc51c8331 | ||
|
|
ee171c6da9 | ||
|
|
d5609e969d | ||
|
|
927c806841 | ||
|
|
2da9dda1c0 | ||
|
|
3117bc16a5 | ||
|
|
717b04306a | ||
|
|
271220c542 | ||
|
|
566a874141 | ||
|
|
967866d4df | ||
|
|
1de3e99bc5 | ||
|
|
3e13004b6b | ||
|
|
2f03ce67d6 | ||
|
|
b9232d45eb | ||
|
|
6087ef2a84 | ||
|
|
1f1d368ad5 | ||
|
|
dd18526e5b | ||
|
|
4d53c4dd46 | ||
|
|
9e4a8d29b5 | ||
|
|
ef20efcbb6 | ||
|
|
c70e07d9ac | ||
|
|
b7d4d28bb3 | ||
|
|
9a6ed83f2c | ||
|
|
fd84673e54 | ||
|
|
57b12568e6 | ||
|
|
f9a9f54720 | ||
|
|
3019a9bafd | ||
|
|
278e3d4f6e | ||
|
|
9b9dd06894 | ||
|
|
1f7e29b99c | ||
|
|
c2f0e6e5e3 | ||
|
|
c2b11ba017 | ||
|
|
f75a53e71b | ||
|
|
054abde25f | ||
|
|
24cecf1365 | ||
|
|
821ff7f49a | ||
|
|
ff3d3c32d5 | ||
|
|
3b2ef5b11c | ||
|
|
0394e34a69 | ||
|
|
56efa56474 | ||
|
|
ed7e79553e | ||
|
|
dec71e94f3 | ||
|
|
ac4f91a5ee | ||
|
|
e957626347 | ||
|
|
b4875de45c | ||
|
|
2cfe44eee4 | ||
|
|
fad3dc421c | ||
|
|
22907b6bd9 | ||
|
|
3485ae8321 | ||
|
|
ca62acc3ca | ||
|
|
cdf236aaf5 | ||
|
|
9f2e3c3f52 | ||
|
|
ee1d11c495 | ||
|
|
669e76717c | ||
|
|
4e107712f3 | ||
|
|
85aa57a7dd | ||
|
|
58a14ed950 | ||
|
|
165e6d446c | ||
|
|
1c3e3679ef | ||
|
|
8a513e55b0 | ||
|
|
a314f7c155 | ||
|
|
9497b0d4e9 | ||
|
|
b694f8a245 | ||
|
|
afc65a5acf | ||
|
|
5f40615cd5 | ||
|
|
c6816b9444 | ||
|
|
46e99b09b9 | ||
|
|
af436313a0 | ||
|
|
d64e6f42b4 | ||
|
|
a00628b335 | ||
|
|
33ab4ad879 | ||
|
|
99eb41b25f | ||
|
|
e86ae6bc1f | ||
|
|
c3cbcfb8ef | ||
|
|
a1d23b5314 | ||
|
|
d4d4890d4e | ||
|
|
30e66e53de | ||
|
|
e224331729 | ||
|
|
70b54e4e43 | ||
|
|
9ba463435b | ||
|
|
05ee48661c | ||
|
|
aef9882581 | ||
|
|
78bcddcc6a | ||
|
|
68e169ab4d | ||
|
|
f62eaa24f1 | ||
|
|
d3e553b4bd | ||
|
|
3753975f48 | ||
|
|
2d81114b23 | ||
|
|
472135e0bc | ||
|
|
c60b7056b2 | ||
|
|
42ccb4c091 | ||
|
|
b31c92edcc | ||
|
|
08b018304f | ||
|
|
d19320fdf6 | ||
|
|
860236bf90 | ||
|
|
4d3abf1360 | ||
|
|
305666bf59 | ||
|
|
b03c719f04 | ||
|
|
62f27e3c02 | ||
|
|
4dc67d5e30 | ||
|
|
8ebdc9724e | ||
|
|
9e0582f9bf | ||
|
|
705de51a73 | ||
|
|
1a8e5c97eb | ||
|
|
55bb7fff14 | ||
|
|
662bdcd4ac | ||
|
|
fef101a548 | ||
|
|
18a11cfd48 | ||
|
|
0f80c3e886 | ||
|
|
f122383179 | ||
|
|
e6bc6f4232 | ||
|
|
ac1cb9380d | ||
|
|
40df65fdb4 | ||
|
|
cb2e1f18c2 | ||
|
|
0ecd03e396 | ||
|
|
e6f5ac116b | ||
|
|
051182cb75 | ||
|
|
574c250093 | ||
|
|
8dad7fc6ea | ||
|
|
b558728875 | ||
|
|
e777afad6f | ||
|
|
87703a1b1f | ||
|
|
981b202661 | ||
|
|
13725744fd | ||
|
|
363c3ece3a | ||
|
|
47780ddfef | ||
|
|
251f22b5d7 | ||
|
|
4e0fcd85ae | ||
|
|
59faec8b8b | ||
|
|
32cbfe7b17 | ||
|
|
f08ca43472 | ||
|
|
8eb6cf784b | ||
|
|
7433d73adc | ||
|
|
3221f451a0 | ||
|
|
9e4536748d | ||
|
|
ea67c71505 | ||
|
|
ea38b5af72 | ||
|
|
89d19eedef | ||
|
|
41b5b5e756 | ||
|
|
a3e1363aaa | ||
|
|
2217b30adf | ||
|
|
9ac2395bf0 | ||
|
|
9e2409ab22 | ||
|
|
8e6cf5d189 | ||
|
|
d17190df44 | ||
|
|
fbe5eeb831 | ||
|
|
ed9d969c4c | ||
|
|
7f2a1f651e | ||
|
|
bbbb44ee0f | ||
|
|
29fbd1eea6 | ||
|
|
33f839b319 | ||
|
|
bc83274ad6 | ||
|
|
38e3910b6f | ||
|
|
c26c51a7ee | ||
|
|
e9973668a4 | ||
|
|
4104c3bf52 | ||
|
|
b7c2481933 | ||
|
|
cfb691ac9a | ||
|
|
cb8240a291 | ||
|
|
352963ddc3 | ||
|
|
8c57732324 | ||
|
|
8a33c406b3 | ||
|
|
340bd68f59 | ||
|
|
8237f9305b | ||
|
|
5b1c1eefda | ||
|
|
6258626751 | ||
|
|
87fd439059 | ||
|
|
564ef546a9 | ||
|
|
94dcbf8367 | ||
|
|
1bad11c759 | ||
|
|
ba679d5194 | ||
|
|
e1ad7fe63d | ||
|
|
f18d87b6ed | ||
|
|
a6c15e9a38 | ||
|
|
64bba1465b | ||
|
|
638e106568 | ||
|
|
34e18ecd61 | ||
|
|
d4021b6d9b | ||
|
|
40b1393880 | ||
|
|
30688bf11b | ||
|
|
a7d7a805dc | ||
|
|
4a239e98f6 | ||
|
|
7b97c38898 | ||
|
|
1f35babc6b | ||
|
|
80ffc3de12 | ||
|
|
507b61d5a6 | ||
|
|
8db3106e0b | ||
|
|
1b1fef20b3 | ||
|
|
22c7c5fb0b | ||
|
|
13d00101e8 | ||
|
|
3e7934a5fb | ||
|
|
815193e89e | ||
|
|
4fd4b3d667 | ||
|
|
1526b8b17d | ||
|
|
732537212b | ||
|
|
4adbb5f246 | ||
|
|
30fa772457 | ||
|
|
ee03617b3d | ||
|
|
19cb6106d2 | ||
|
|
cd6bececc1 | ||
|
|
88b93c6159 | ||
|
|
b62fd39392 | ||
|
|
95306d9d50 | ||
|
|
3e870a6444 | ||
|
|
bf26aa2219 | ||
|
|
9981c27ef1 | ||
|
|
fe96018750 | ||
|
|
07c6ae7de8 | ||
|
|
e163683020 | ||
|
|
961103049b | ||
|
|
0254bd46ec | ||
|
|
8b806ed347 | ||
|
|
8e3ead09a3 | ||
|
|
8715db2cab | ||
|
|
50839b4bb0 | ||
|
|
e1f40891c7 | ||
|
|
042f470ef9 | ||
|
|
40cc28516d | ||
|
|
8174bc3506 | ||
|
|
9118a09c77 | ||
|
|
8324bd5c21 | ||
|
|
7f37167da5 | ||
|
|
227a9c41c1 | ||
|
|
6c3862fae3 | ||
|
|
1eec003a80 | ||
|
|
684d7582b6 | ||
|
|
f39b2060fe | ||
|
|
4f2ba7e056 | ||
|
|
1dcf3b4345 | ||
|
|
aa57d14ae7 | ||
|
|
3c54d8a3ad | ||
|
|
c0814b813f | ||
|
|
088aff1a48 | ||
|
|
d6707171e6 | ||
|
|
5c5e159892 | ||
|
|
6d7b3d52dc | ||
|
|
591b908fbf | ||
|
|
742be97ce4 | ||
|
|
1f30a674cd | ||
|
|
19bc826d8b | ||
|
|
c786a7aec5 | ||
|
|
8a8356b7db | ||
|
|
0d67e00af8 | ||
|
|
7448177753 | ||
|
|
90d151f423 | ||
|
|
9f7c5dabf8 | ||
|
|
a85a151430 | ||
|
|
5dd97ab999 | ||
|
|
8daa9925cc | ||
|
|
e844be4e7b | ||
|
|
88b218fa5c | ||
|
|
e66d70e34c | ||
|
|
9361f83933 | ||
|
|
3b2bebbf90 | ||
|
|
4f90eb433a | ||
|
|
b485e0c16c | ||
|
|
bc1fac9648 | ||
|
|
c78779cce3 | ||
|
|
702cd15cb0 | ||
|
|
1da05366ad | ||
|
|
2267efeac5 | ||
|
|
15954da08f | ||
|
|
b2dc7bad39 | ||
|
|
d4e0196346 | ||
|
|
2fc50f5a98 | ||
|
|
bd5b85dbc7 | ||
|
|
8a8324657e | ||
|
|
4bb0af79b7 | ||
|
|
e3bcd89319 | ||
|
|
87383697e8 | ||
|
|
e4b808989e | ||
|
|
59e52bf276 | ||
|
|
9b40e44ef4 | ||
|
|
e92f21d2f7 | ||
|
|
910e89b963 | ||
|
|
8a9cfb2459 | ||
|
|
41961db0bd | ||
|
|
e76518843d | ||
|
|
ef74f5d626 | ||
|
|
c557eb8cec | ||
|
|
0cc279e0d3 | ||
|
|
0cfdf22655 | ||
|
|
527a010f10 | ||
|
|
c8ca974634 | ||
|
|
3296f91bb0 | ||
|
|
e2124620eb | ||
|
|
69864a5ccf | ||
|
|
5b4e1f318d | ||
|
|
b78296cb0b | ||
|
|
06a1dbad61 | ||
|
|
93c31c1a6d | ||
|
|
a8ed495833 | ||
|
|
4a14ed068c | ||
|
|
dc0f24976d | ||
|
|
1e7098b5e3 | ||
|
|
2f24fb18c4 | ||
|
|
96a8ca6d98 | ||
|
|
37a5644576 | ||
|
|
a1cbe76e2c | ||
|
|
98bf61c80e | ||
|
|
01f439ec6e | ||
|
|
acc461c7da | ||
|
|
1585958497 | ||
|
|
7cacd47edd | ||
|
|
e461b9bed4 | ||
|
|
3723c04850 | ||
|
|
73273075c8 | ||
|
|
8e85be0a16 | ||
|
|
37802f40dc | ||
|
|
06b96ffa86 | ||
|
|
c4ed1487f9 | ||
|
|
e64ae6d766 | ||
|
|
5b4837552b | ||
|
|
d2004814f0 | ||
|
|
bf0c5bec45 | ||
|
|
0dd046d36f | ||
|
|
4f5b0756df | ||
|
|
fe1c19dcdf | ||
|
|
24b2096e86 | ||
|
|
86e97e178d | ||
|
|
905d906d69 | ||
|
|
abce74bb93 | ||
|
|
f5db099330 | ||
|
|
122d1771db | ||
|
|
8824e2cee4 | ||
|
|
8a6f3fead8 | ||
|
|
9c71f56a25 | ||
|
|
f924946eba | ||
|
|
32a5edf43f | ||
|
|
9a338344da | ||
|
|
df337831dc | ||
|
|
bb558f6791 | ||
|
|
22558cdd7e | ||
|
|
28c54e81c1 | ||
|
|
0dfffb88e1 | ||
|
|
ed243f8c29 | ||
|
|
a427e8938a | ||
|
|
cc25d29132 | ||
|
|
134f43385b | ||
|
|
a5a264842e | ||
|
|
eed47b6b9c | ||
|
|
3841a04e88 | ||
|
|
9eef8f0b73 | ||
|
|
c258230722 | ||
|
|
345e0988cb | ||
|
|
3671987f4d | ||
|
|
5aa7b20a3e | ||
|
|
68795c640b | ||
|
|
4f1f94d1de | ||
|
|
0f7e31f7d7 | ||
|
|
2f3cad893b | ||
|
|
e79666267d | ||
|
|
d91de04671 | ||
|
|
64b761c19a | ||
|
|
a1ac8edd66 | ||
|
|
1dca857b5b | ||
|
|
f8cd88dbd1 | ||
|
|
71903f601a | ||
|
|
719bc858b5 | ||
|
|
a6126d678b | ||
|
|
4875d6b64d | ||
|
|
54b4059856 | ||
|
|
38059f8e8e | ||
|
|
bb5f4e7285 | ||
|
|
448797a1e6 | ||
|
|
a261103ce0 | ||
|
|
7b82b5adb3 | ||
|
|
397a344364 | ||
|
|
bafa48759f | ||
|
|
46db185081 | ||
|
|
1412da7c32 | ||
|
|
d09e800a0e | ||
|
|
53b417e414 | ||
|
|
57dee64e82 | ||
|
|
fdc795015f | ||
|
|
3a5e9224d0 | ||
|
|
ebfd1a1cf7 | ||
|
|
dd667c2301 | ||
|
|
d727f0ff48 | ||
|
|
eb9b2e53c8 | ||
|
|
b6f06b8e8b | ||
|
|
0a68f869d7 | ||
|
|
3b2461cf2e | ||
|
|
346402ddbf | ||
|
|
44d60d5f83 | ||
|
|
f2ae9e8583 | ||
|
|
7c8e23bd9f | ||
|
|
0752721dc3 | ||
|
|
68a94ac30f | ||
|
|
ee3751c8d7 | ||
|
|
ec33e0e6bd | ||
|
|
31937d363b | ||
|
|
8982a89b24 | ||
|
|
0492fdfb2e | ||
|
|
14698a3a1a | ||
|
|
8c2ffaf095 | ||
|
|
afd72c78bd | ||
|
|
6bf822649b | ||
|
|
67dde16163 | ||
|
|
f1d5ba4005 | ||
|
|
794b0a037f | ||
|
|
c32edbe02e | ||
|
|
f3c3ed44e6 | ||
|
|
f805730493 | ||
|
|
2b1366635d | ||
|
|
42f23f479d | ||
|
|
62bf783f06 | ||
|
|
0b2901b72d | ||
|
|
faa82484a5 | ||
|
|
4ccfd96cfe | ||
|
|
408aa7b24c | ||
|
|
776b9d1c00 | ||
|
|
c93fad5ee0 | ||
|
|
19b2a5d9fd | ||
|
|
f1773e09ab | ||
|
|
462c51d9a1 | ||
|
|
2430e98412 | ||
|
|
78fc60cd29 | ||
|
|
864146de58 | ||
|
|
45478cc79b | ||
|
|
5454d22ad8 | ||
|
|
dc1488ae47 | ||
|
|
0121a8ecad | ||
|
|
7bc90b3066 | ||
|
|
bf39270e0c | ||
|
|
211bc43b6e | ||
|
|
91c5833bd0 | ||
|
|
8311f1c11e | ||
|
|
ae2836325f | ||
|
|
a897af2cde | ||
|
|
cc80022e84 | ||
|
|
5a016db9b6 | ||
|
|
92e1aeede7 | ||
|
|
f846a9bfe9 | ||
|
|
3db859e8b5 | ||
|
|
0eeb1cf83a | ||
|
|
5f238db203 | ||
|
|
422696201a | ||
|
|
58fef0ac38 | ||
|
|
25e1181466 | ||
|
|
5b5f7e3b59 | ||
|
|
dc3afaf6aa | ||
|
|
1164f67827 | ||
|
|
c83a2c8ec5 | ||
|
|
43d0f38b24 | ||
|
|
e95538ca2c | ||
|
|
25ff04417e | ||
|
|
63ecee4d1a | ||
|
|
4c8f6b6a06 | ||
|
|
2161111900 | ||
|
|
24b0922b0e | ||
|
|
186387301f | ||
|
|
1bd9db74ba | ||
|
|
df6933406f | ||
|
|
d679c8390a | ||
|
|
d4daa7b68c | ||
|
|
44d98d6166 | ||
|
|
b3708acf27 | ||
|
|
2c0fa6c5df | ||
|
|
57f74bd1c2 | ||
|
|
598c409e63 | ||
|
|
c6eb7fad68 | ||
|
|
c561edaa72 | ||
|
|
031fa9ad4d | ||
|
|
d622d4bf30 | ||
|
|
e32db5c9aa | ||
|
|
4a6c209a13 | ||
|
|
0d2aa5d9d7 | ||
|
|
e30b1fb8fd | ||
|
|
da1b6eeaf2 | ||
|
|
01b835c237 | ||
|
|
48e1c8c69d | ||
|
|
f06e708282 | ||
|
|
f0f7e760ae | ||
|
|
31b4d25d10 | ||
|
|
d41988232e | ||
|
|
880570f228 | ||
|
|
72a90c750a | ||
|
|
e1988bc744 | ||
|
|
d6a3e37b83 | ||
|
|
8261047b1e | ||
|
|
417b59997f | ||
|
|
4366d2c428 | ||
|
|
217cc3b045 | ||
|
|
757e0a5445 | ||
|
|
ddf6410130 | ||
|
|
7842418b7b | ||
|
|
9624b86426 | ||
|
|
201a2fe5ff | ||
|
|
ed032a88b8 | ||
|
|
ae76a74043 | ||
|
|
3359acb8cb | ||
|
|
a2b371cd52 | ||
|
|
dd69b3976a | ||
|
|
16e5de84da | ||
|
|
46fa602530 | ||
|
|
aa4d3b4cc0 | ||
|
|
73ed23495e | ||
|
|
c7d970f782 | ||
|
|
6dfd07d025 | ||
|
|
e7bf7c0161 | ||
|
|
f5a7b9e716 | ||
|
|
b951e023ec | ||
|
|
3ea9bbd632 | ||
|
|
aaca3daa27 | ||
|
|
a51b316824 | ||
|
|
928a00c474 | ||
|
|
fa13f396d5 | ||
|
|
3ab56a20ee | ||
|
|
649f874292 | ||
|
|
90fdd89a0b | ||
|
|
54e66f1d59 | ||
|
|
82471e68a8 | ||
|
|
20fb7b9175 | ||
|
|
859fdaad45 | ||
|
|
09ed309996 | ||
|
|
65e4cda059 | ||
|
|
7e037c4226 | ||
|
|
f636c38440 | ||
|
|
b98f040ef2 | ||
|
|
e57211c544 | ||
|
|
48a1ff0d45 | ||
|
|
032dcf74b0 | ||
|
|
51d4839861 | ||
|
|
9f125ea7c1 | ||
|
|
9bcb25958d | ||
|
|
866925bfb7 | ||
|
|
f8b3c05311 | ||
|
|
353f272434 | ||
|
|
3d54c6ec46 | ||
|
|
71e27c463d | ||
|
|
8c48382049 | ||
|
|
11781089d1 | ||
|
|
d97fd43a72 | ||
|
|
f5ea4b3b39 | ||
|
|
f227ffe4b9 | ||
|
|
027428eb1d | ||
|
|
15778afbdc | ||
|
|
d06f63287e | ||
|
|
1490812ab2 | ||
|
|
707415d4fc | ||
|
|
9cea6ef1b6 | ||
|
|
48ea74bf01 | ||
|
|
026deaf759 | ||
|
|
4c59971194 | ||
|
|
fd8571c2c9 | ||
|
|
dd096ae080 | ||
|
|
eb1accaa91 | ||
|
|
7e38410e47 | ||
|
|
d336388403 | ||
|
|
c207d7ec62 | ||
|
|
018b28328c | ||
|
|
0957a7463e | ||
|
|
c72f5bd9c4 | ||
|
|
0f57446da7 | ||
|
|
3a90ea0acd | ||
|
|
58af2f958c | ||
|
|
a8fd4161bb | ||
|
|
53f8519a38 | ||
|
|
eb162f3b0a | ||
|
|
4ce838e1f1 | ||
|
|
a36ffd3910 | ||
|
|
17b5b32f75 | ||
|
|
9b919d590a | ||
|
|
80264051d8 | ||
|
|
188fed9570 | ||
|
|
eae7165c79 | ||
|
|
54281fe733 | ||
|
|
2b2ea368aa | ||
|
|
67a28eb256 | ||
|
|
f5d96a6f80 | ||
|
|
44ac015598 | ||
|
|
89a9c0545e | ||
|
|
3b26bba0c4 | ||
|
|
2be2fb3ed3 | ||
|
|
e341588a8a | ||
|
|
c56595d749 | ||
|
|
ce0b384fa6 | ||
|
|
dfd7d541b0 | ||
|
|
ded4daf049 | ||
|
|
361428213b | ||
|
|
12a79db2f6 | ||
|
|
e8b155a3be | ||
|
|
716b46c550 | ||
|
|
9d954dca8c | ||
|
|
7162c65df7 | ||
|
|
bd9fca4708 | ||
|
|
14d496cc8b | ||
|
|
106a8ad918 | ||
|
|
44a82a175d | ||
|
|
99248631aa | ||
|
|
2836ee9b02 | ||
|
|
d82773ffe9 | ||
|
|
ec626b3f0e | ||
|
|
997d9ea67f | ||
|
|
aec6b9f86f | ||
|
|
d45898df80 | ||
|
|
b0da4b23a0 | ||
|
|
bf18b7ca67 | ||
|
|
cc17fbfe7d | ||
|
|
fa170b2e5a | ||
|
|
c61ba345f2 | ||
|
|
ae09fb1f91 | ||
|
|
70a2c84cd2 | ||
|
|
21524e3083 | ||
|
|
fbe2aba2e7 | ||
|
|
a41a1e8718 | ||
|
|
051547603a | ||
|
|
80a25bb880 | ||
|
|
0301b334c7 | ||
|
|
1492b4b2b2 | ||
|
|
5b7bcac260 | ||
|
|
7fcbf9e43e | ||
|
|
6c495e0da4 | ||
|
|
a06b419d42 | ||
|
|
a255c592e8 | ||
|
|
7aac6604c4 | ||
|
|
deb5bf1dff | ||
|
|
3dfe6e97a7 | ||
|
|
43bab4035b | ||
|
|
ef0c03ff70 | ||
|
|
ad54dcc827 | ||
|
|
c0ab28d1d9 | ||
|
|
5b2f48da27 | ||
|
|
132fcf36b2 | ||
|
|
4571df58c6 | ||
|
|
f6b384d41f | ||
|
|
c259892c3a | ||
|
|
b471329591 | ||
|
|
3add5835db | ||
|
|
cf510ad2c5 | ||
|
|
696a8d6191 | ||
|
|
01f8a1155f | ||
|
|
986aaaaa4b | ||
|
|
c96ee2310d | ||
|
|
76cb2a3a4f | ||
|
|
9bef934c76 | ||
|
|
85f14172dc | ||
|
|
4539c0d79f | ||
|
|
c3131af90a | ||
|
|
c2c14fa26e | ||
|
|
e49f61f5fc | ||
|
|
22f5bd5e35 | ||
|
|
7a1b73b983 | ||
|
|
0c56b1add7 | ||
|
|
1e60969646 | ||
|
|
ee29752217 | ||
|
|
e012f858d6 | ||
|
|
c3fad2e227 | ||
|
|
b7e8628c4b | ||
|
|
e4977b0b9f | ||
|
|
b127c1dc58 | ||
|
|
07bff66fb5 | ||
|
|
4a888ae6d4 | ||
|
|
a0a33ee506 | ||
|
|
98f8c9a5e5 | ||
|
|
1f69bec480 | ||
|
|
8f1b4f3642 | ||
|
|
ca39ebf9fb | ||
|
|
9fb0844100 | ||
|
|
bdf278f7a5 | ||
|
|
c8f2f8572f | ||
|
|
5d54f33962 | ||
|
|
ba449e444b | ||
|
|
87ba7282f6 | ||
|
|
7d1bfaf7be | ||
|
|
7d5acf1d44 | ||
|
|
3610c4583a | ||
|
|
41cfde6be3 | ||
|
|
34bde8d54a | ||
|
|
1ed55e3e3e | ||
|
|
f80a8520e8 | ||
|
|
740bab942d | ||
|
|
08b1b4860f | ||
|
|
18ea5dc0d7 | ||
|
|
3ac7f5d4c1 | ||
|
|
ad71500818 | ||
|
|
b2ad840a6b | ||
|
|
8db7cc2cff | ||
|
|
ac1541f4b7 | ||
|
|
09e2bbce8a | ||
|
|
73496a36a1 | ||
|
|
8303cc1021 | ||
|
|
ab759cd27b | ||
|
|
64444de582 | ||
|
|
e425fbe85d | ||
|
|
4f4b2f0927 | ||
|
|
da6eb9d123 | ||
|
|
1b15e07e99 | ||
|
|
e49d720081 | ||
|
|
3267d6a9ce | ||
|
|
3ba2c330e1 |
@@ -22,3 +22,4 @@ trimslash
|
||||
t_unsafe
|
||||
wildtest
|
||||
getfsdev
|
||||
.rsync-filter
|
||||
|
||||
11
COPYING
11
COPYING
@@ -2,7 +2,7 @@
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -279,7 +279,7 @@ POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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
|
||||
@@ -305,14 +305,15 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
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.
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
@@ -41,7 +41,7 @@ popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
popt/popthelp.o popt/poptparse.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
|
||||
|
||||
TLS_OBJ = tls.o syscall.o lib/permstring.o
|
||||
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
@@ -83,7 +83,7 @@ getgroups$(EXEEXT): getgroups.o
|
||||
getfsdev$(EXEEXT): getfsdev.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
|
||||
|
||||
327
NEWS
327
NEWS
@@ -1,252 +1,181 @@
|
||||
NEWS for rsync 2.6.3 (30 Sep 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.2:
|
||||
NEWS for rsync 2.6.5 (1 Jun 2005)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.4:
|
||||
|
||||
SECURITY FIXES:
|
||||
OUTPUT CHANGES:
|
||||
|
||||
- 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".
|
||||
- Non-printable chars in filenames are now output using backslash-
|
||||
escaped characters rather than '?'s. Any non-printable character is
|
||||
output using 3 digits of octal (e.g. "\n" -> "\012"), and a backslash
|
||||
is now output as "\\". Rsync also uses your locale setting, which
|
||||
can make it treat fewer high-bit characters as non-printable.
|
||||
|
||||
OUTPUT CHANGES (ATTN: those using a script to parse the verbose output):
|
||||
|
||||
- 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".
|
||||
|
||||
- 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 "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.
|
||||
- If rsync received an empty file-list when pulling files, it would
|
||||
output a "nothing to do" message and exit with a 0 (success) exit
|
||||
status, even if the remote rsync returned an error (it did not do
|
||||
this under the same conditions when pushing files). This was changed
|
||||
to make the pulling behavior the same as the pushing behavior: we
|
||||
now do the normal end-of-run outputting (depending on options) and
|
||||
exit with the appropriate exit status.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a crash bug that might appear when --delete was used and
|
||||
multiple source directories were specified.
|
||||
- A crash bug was fixed when a daemon had its "path" set to "/", did
|
||||
not have chroot enabled, and used some anchored excludes in the
|
||||
rsyncd.conf file.
|
||||
|
||||
- Fixed a 32-bit truncation of the file length when generating the
|
||||
checksums.
|
||||
- Fixed a bug in the transfer of a single file when -H is specified
|
||||
(rsync would either infinite loop or perhaps crash).
|
||||
|
||||
- The --backup code no longer attempts to create some directories
|
||||
over and over again (generating warnings along the way).
|
||||
- Fixed a case where the generator might try (and fail) to tweak the
|
||||
write-permissions of a read-only directory in list-only mode (this
|
||||
only caused an annoying warning message).
|
||||
|
||||
- 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.
|
||||
- If --compare-dest or --link-dest uses a locally-copied file as the
|
||||
basis for an updated version, log this better when --verbose or -i
|
||||
is in effect.
|
||||
|
||||
- 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.)
|
||||
- Fixed the accidental disabling of --backup during the --delete-after
|
||||
processing.
|
||||
|
||||
- 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).
|
||||
- Restored the ability to use the --address option in client mode (in
|
||||
addition to its use in daemon mode).
|
||||
|
||||
- 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.
|
||||
- Make sure that some temporary progress information from the delete
|
||||
processing does not get left on the screen when it is followed by a
|
||||
newline.
|
||||
|
||||
- Got rid of a potential hang in the receiver when near the end of a
|
||||
phase.
|
||||
- When --existing skips a directory with extra verbosity, refer to it
|
||||
as a "directory", not a "file".
|
||||
|
||||
- When using --backup without a --backup-dir, rsync no longer preserves
|
||||
the modify time on directories. This avoids confusing NFS.
|
||||
- When transferring a single file to a different-named file, any
|
||||
generator messages that are source-file related no longer refer to
|
||||
the file by the destination filename.
|
||||
|
||||
- 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".
|
||||
- Fixed a bug where hard-linking a group of files might fail if the
|
||||
generator hasn't created a needed destination directory yet.
|
||||
|
||||
- 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 a bug where a hard-linked group of files that is newly-linked
|
||||
to a file in a --link-dest dir doesn't link the files from the rest
|
||||
of the cluster.
|
||||
|
||||
- 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).
|
||||
- When deleting files with the --one-file-system (-x) option set, rsync
|
||||
no longer tries to remove files from inside a mount-point on the
|
||||
receiving side. Also, we don't complain about being unable to remove
|
||||
the mount-point dir.
|
||||
|
||||
- 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 compatibility problem when using --cvs-ignore (-C) and
|
||||
sending files to an older rsync without using --delete.
|
||||
|
||||
- Fixed a bug in the daemon authentication code when using one of the
|
||||
batch-processing options.
|
||||
- Make sure that a "- !" or "+ !" include/exclude pattern does not
|
||||
trigger the list-clearing action that is reserved for "!".
|
||||
|
||||
- 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).
|
||||
- Avoid a timeout in the generator when the sender/receiver aren't
|
||||
handling the generator's checksum output quickly enough.
|
||||
|
||||
- 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 the omission of some directories in the delete processing when
|
||||
--relative (-R) was combined with a source path that had a trailing
|
||||
slash.
|
||||
|
||||
- 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 a case where rsync would erroneously delete some files and then
|
||||
re-transfer them when the options --relative (-R) and --recursive
|
||||
(-r) were both enabled (along with --delete) and a source path had a
|
||||
trailing slash.
|
||||
|
||||
- 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.
|
||||
- Make sure that --max-size doesn't affect a device or a symlink.
|
||||
|
||||
- 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.
|
||||
- Make sure that a system with a really small MAXPATHLEN does not cause
|
||||
the buffers in readfd_unbuffered() to be too small to receive normal
|
||||
messages. (This mainly affected Cygwin.)
|
||||
|
||||
- Fixed an age-old crash problem with --read-batch on a local copy
|
||||
(rsync was improperly assuming --whole-file for the local copy).
|
||||
- If a source pathname ends with a filename of "..", treat it as if
|
||||
"../" had been specified (so that we don't copy files to the parent
|
||||
dir of the destination).
|
||||
|
||||
- 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.
|
||||
- If --delete is combined with a file-listing rsync command (i.e. no
|
||||
transfer is happening), avoid outputting a warning that we couldn't
|
||||
delete anything.
|
||||
|
||||
- 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.
|
||||
- If --stats is specified with --delete-after, ensure that all the
|
||||
"deleting" messages are output before the statistics.
|
||||
|
||||
- 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").
|
||||
- Improved one "if" in the deletion code that was only checking errno
|
||||
for ENOTEMPTY when it should have also been checking for EEXIST (for
|
||||
compatibility with OS variations).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- 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.
|
||||
- Added the --only-write-batch=FILE option that may be used (instead
|
||||
of --write-batch=FILE) to create a batch file without doing any
|
||||
actual updating of the destination. This allows you to divert all
|
||||
the file-updating data away from a slow data link (as long as you
|
||||
are pushing the data to the remote server when creating the batch).
|
||||
|
||||
- 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.
|
||||
- When the generator is taking a long time to fill up its output buffer
|
||||
(e.g. if the transferred files are few, small, or missing), it now
|
||||
periodically flushes the output buffer so that the sender/receiver
|
||||
can get started on the files sooner rather than later.
|
||||
|
||||
- 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).
|
||||
- Improved the keep-alive code to handle a long silence between the
|
||||
sender and the receiver that can occur when the sender is receiving
|
||||
the checksum data for a large file.
|
||||
|
||||
- Added the "write only" option for the daemon's config file.
|
||||
- Improved the auth-errors that are logged by the daemon to include
|
||||
some information on why the authorization failed: wrong user,
|
||||
password mismatch, etc. (The client-visible message is unchanged!)
|
||||
|
||||
- Added long-option names for -4 and -6 (namely --ipv4 and --ipv6)
|
||||
and documented all these options in the man page.
|
||||
- Improved the client's handling of an "@ERROR" from a daemon so that
|
||||
it does not complain about an unexpectedly closed socket (since we
|
||||
really did expect the socket to close).
|
||||
|
||||
- Improved the handling of the --bwlimit option so that it's less
|
||||
bursty, more accurate, and works properly over a larger range of
|
||||
values.
|
||||
- If the daemon can't open the log-file specified in rsyncd.conf, fall
|
||||
back to using syslog and log an appropriate warning. This is better
|
||||
than what was typically a totally silent (and fatal) failure (since a
|
||||
daemon is not usually run with the --no-detach option that was
|
||||
necessary to see the error on stderr).
|
||||
|
||||
- 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.
|
||||
- The man pages now consistently refer to an rsync daemon as a "daemon"
|
||||
instead of a "server" (to distinguish it from the server process in a
|
||||
non-daemon transfer).
|
||||
|
||||
- Added the --checksum-seed=N option for advanced users.
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- The daemon's "refuse options" config item now allows you to match
|
||||
option names using wildcards and/or the single-letter option names.
|
||||
|
||||
- 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.
|
||||
|
||||
- Added the ability to parse a literal IPv6 address in an "rsync:" URL
|
||||
(e.g. rsync://[2001:638:500:101::21]:873/module/dir).
|
||||
|
||||
- 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).
|
||||
- Made a small change to the rrsync script (restricted rsync -- in the
|
||||
support dir) to make a read-only server reject all --remove-* options
|
||||
when sending files (to future-proof it against the possibility of
|
||||
other similar options being added at some point).
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Some cleanup in the exclude code has saved some per-exclude memory
|
||||
and made the code easier to maintain.
|
||||
- Rsync now calls setlocale(LC_CTYPE, ""). This enables isprint() to
|
||||
better discern which filename characters need to be escaped in
|
||||
messages (which should result in fewer escaped characters in some
|
||||
locales).
|
||||
|
||||
- Improved the argv-overflow checking for a remote command that has a
|
||||
lot of args.
|
||||
- Improved the naming of the log-file open/reopen/close functions.
|
||||
|
||||
- Use rsyserr() in the various places that were still calling rprintf()
|
||||
with strerror() as an arg.
|
||||
|
||||
- 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).
|
||||
|
||||
- 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).
|
||||
- Removed some protocol-compatibility code that was only needed to help
|
||||
someone running a pre-release of 2.6.4.
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Added a "gen" target to rebuild most of the generated files,
|
||||
including configure, config.h.in, the man pages, and proto.h.
|
||||
- Added configure option "--disable-locale" to disable any use of
|
||||
setlocale() in the binary.
|
||||
|
||||
- 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).
|
||||
- Fixed a bug in the SUPPORT{,_HARD}_LINKS #defines which prevented
|
||||
rsync from being built without symlink or hard-link support.
|
||||
|
||||
- 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.
|
||||
- Only #define HAVE_REMSH if it is going to be set to 1.
|
||||
|
||||
- Fixed a build problem when SUPPORT_HARD_LINKS isn't defined.
|
||||
- Configure now disables the use of mkstemp() under HP-UX (since they
|
||||
refuse to fix its broken handling of large files).
|
||||
|
||||
- When cross-compiling, the gettimeofday() function is now assumed to
|
||||
be a modern version that takes two-args (since we can't test it).
|
||||
- Configure now explicitly checks for the lseek64() function so that
|
||||
the code can use HAVE_LSEEK64 instead of inferring lseek64()'s
|
||||
presence based on the presence of the off64_t type.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
- Configure no longer mentions the change in the default remote-shell
|
||||
(from rsh to ssh) that occurred for the 2.6.0 release.
|
||||
|
||||
- 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.
|
||||
- Some minor enhancements to the test scripts.
|
||||
|
||||
- Added a few new *.diff files to the patches dir, including a patch
|
||||
that enables the optional copying of extended attributes.
|
||||
|
||||
648
OLDNEWS
648
OLDNEWS
@@ -1,3 +1,647 @@
|
||||
NEWS for rsync 2.6.4 (30 March 2005)
|
||||
Protocol: 29 (changed)
|
||||
Changes since 2.6.3:
|
||||
|
||||
OUTPUT CHANGES:
|
||||
|
||||
- When rsync deletes a directory and outputs a verbose message about
|
||||
it, it now appends a trailing slash to the name instead of (only
|
||||
sometimes) outputting a preceding "directory " string.
|
||||
|
||||
- The --stats output will contain file-list time-statistics if both
|
||||
sides are 2.6.4, or if the local side is 2.6.4 and the files are
|
||||
being pushed (since the stats come from the sending side).
|
||||
(Requires protocol 29 for a pull.)
|
||||
|
||||
- The "%o" (operation) log-format escape now has a third value (besides
|
||||
"send" and "recv"): "del." (with trailing dot to make it 4 chars).
|
||||
This changes the way deletions are logged in the daemon's log file.
|
||||
|
||||
- When the --log-format option is combined with --verbose, rsync now
|
||||
avoids outputting the name of the file twice in most circumstances.
|
||||
As long as the --log-format item does not refer to any post-transfer
|
||||
items (such as %b or %c), the --log-format message is output prior to
|
||||
the transfer, so --verbose is now the equivalent of a --log-format of
|
||||
'%n%L' (which outputs the name and any link info). If the log output
|
||||
must occur after the transfer to be complete, the only time the name
|
||||
is also output prior to the transfer is when --progress was specified
|
||||
(so that the name will precede the progress stats, and the full
|
||||
--log-format output will come after).
|
||||
|
||||
- Non-printable characters in filenames are replaced with a '?' to
|
||||
avoid corrupting the screen or generating empty lines in the output.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Restore the list-clearing behavior of "!" in a .cvsignore file (2.6.3
|
||||
was only treating it as a special token in an rsync include/exclude
|
||||
file).
|
||||
|
||||
- The combination of --verbose and --dry-run now mentions the full list
|
||||
of changes that would be output without --dry-run.
|
||||
|
||||
- Avoid a mkdir warning when removing a directory in the destination
|
||||
that already exists in the --backup-dir.
|
||||
|
||||
- An OS that has a binary mode for its files (such as cygwin) needed
|
||||
setmode(fd, O_BINARY) called on the temp-file we opened with
|
||||
mkstemp(). (Fix derived from the cygwin's 2.6.3 rsync package.)
|
||||
|
||||
- Fixed a potential hang when verbosity is high, the client side is
|
||||
the sender, and the file-list is large.
|
||||
|
||||
- Fixed a potential protocol-corrupting bug where the generator could
|
||||
merge a message from the receiver into the middle of a multiplexed
|
||||
packet of data if only part of that data had been written out to the
|
||||
socket when the message from the generator arrived.
|
||||
|
||||
- We now check if the OS doesn't support using mknod() for creating
|
||||
FIFOs and sockets, and compile-in some compatibility code using
|
||||
mkfifo() and socket() when necessary.
|
||||
|
||||
- Fixed an off-by-one error in the handling of --max-delete=N. Also,
|
||||
if the --max-delete limit is exceeded during a run, we now output a
|
||||
warning about this at the end of the run and exit with a new error
|
||||
code (25).
|
||||
|
||||
- One place in the code wasn't checking if fork() failed.
|
||||
|
||||
- The "ignore nonreadable" daemon parameter used to erroneously affect
|
||||
readable symlinks that pointed to a non-existent file.
|
||||
|
||||
- If the OS does not have lchown() and a chown() of a symlink will
|
||||
affect the referent of a symlink (as it should), we no longer try
|
||||
to set the user and group of a symlink.
|
||||
|
||||
- The generator now properly runs the hard-link loop and the dir-time
|
||||
rewriting loop after we're sure that the redo phase is complete.
|
||||
|
||||
- When --backup was specified with --partial-dir=DIR, where DIR is a
|
||||
relative path, the backup code was erroneously trying to backup a
|
||||
file that was put into the partial-dir.
|
||||
|
||||
- If a file gets resent in a single transfer and the --backup option is
|
||||
enabled along with --inplace, rsync no longer performs a duplicate
|
||||
backup (it used to overwrite the first backup with the failed file).
|
||||
|
||||
- One call to flush_write_file() was not being checked for an error.
|
||||
|
||||
- The --no-relative option was not being sent from the client to a
|
||||
server sender.
|
||||
|
||||
- If an rsync daemon specified "dont compress = ..." for a file and the
|
||||
client tried to specify --compress, the libz code was not handling a
|
||||
compression level of 0 properly. This could cause a transfer failure
|
||||
if the block-size for a file was large enough (e.g. rsync might have
|
||||
exited with an error for large files).
|
||||
|
||||
- Fixed a bug that would sometimes surface when using --compress and
|
||||
sending a file with a block-size larger than 64K (either manually
|
||||
specified, or computed due to the file being really large). Prior
|
||||
versions of rsync would sometimes fail to decompress the data
|
||||
properly, and thus the transferred file would fail its verification.
|
||||
|
||||
- If a daemon can't open the specified log file (i.e. syslog is not
|
||||
being used), die without crashing. We also output an error about
|
||||
the failure on stderr (which will only be seen if --no-detach was
|
||||
specified) and exit with a new error code (6).
|
||||
|
||||
- A local transfer no longer duplicates all its include/exclude options
|
||||
(since the forked process already has a copy of the exclude list,
|
||||
there's no need to send them a set of duplicates).
|
||||
|
||||
- When --progress is specified, the output of items that the generator
|
||||
is creating (e.g. dirs, symlinks) is now integrated into the progress
|
||||
output without overlapping it. (Requires protocol 29.)
|
||||
|
||||
- When --timeout is specified, lulls that occur in the transfer while
|
||||
the generator is doing work that does not generate socket traffic
|
||||
(looking for changed files, deleting files, doing directory-time
|
||||
touch-ups, etc.) will cause a new keep-alive packet to be sent that
|
||||
should keep the transfer going as long as the generator continues to
|
||||
make progress. (Requires protocol 29.)
|
||||
|
||||
- The stat size of a device is not added to the total file size of the
|
||||
items in the transfer (the size might be undefined on some OSes).
|
||||
|
||||
- Fixed a problem with refused-option messages sometimes not making it
|
||||
back to the client side when a remote --files-from was in effect and
|
||||
the daemon was the receiver.
|
||||
|
||||
- The --compare-dest option was not updating a file that differed in
|
||||
(the preserved) attributes from the version in the compare-dest DIR.
|
||||
|
||||
- When rsync is copying files into a write-protected directory, fixed
|
||||
the change-report output for the directory so that we don't report
|
||||
an identical directory as changed.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Rsync now supports popt's option aliases, which means that you can
|
||||
use /etc/popt and/or ~/.popt to create your own option aliases.
|
||||
|
||||
- Added the --delete-during (--del) option which will delete files
|
||||
from the receiving side incrementally as each directory in the
|
||||
transfer is being processed. This makes it more efficient than the
|
||||
default, before-the-transfer behavior, which is now also available as
|
||||
--delete-before (and is still the default --delete-WHEN option that
|
||||
will be chosen if --delete or --delete-excluded is specified without
|
||||
a --delete-WHEN choice). All the --del* options infer --delete, so
|
||||
an rsync daemon that refuses "delete" will still refuse to allow any
|
||||
file-deleting options (including the new --remove-sent-files option).
|
||||
|
||||
- All the --delete-WHEN options are now more memory efficient:
|
||||
Previously an duplicate set of file-list objects was created on the
|
||||
receiving side for the entire destination hierarchy. The new
|
||||
algorithm only creates one directory of objects at a time (for files
|
||||
inside the transfer).
|
||||
|
||||
- Added the --copy-dest option, which works like --link-dest except
|
||||
that it locally copies identical files instead of hard-linking them.
|
||||
|
||||
- Added support for specifying multiple --compare-dest, --copy-dest, or
|
||||
--link-dest options, but only of a single type. (Promoted from the
|
||||
patches dir and enhanced.) (Requires protocol 29.)
|
||||
|
||||
- Added the --max-size option. (Promoted from the patches dir.)
|
||||
|
||||
- The daemon-mode options are now separated from the normal rsync
|
||||
options so that they can't be mixed together. This makes it
|
||||
impossible to start a daemon that has improper default option values
|
||||
(which could cause problems when a client connects, such as hanging
|
||||
or crashing).
|
||||
|
||||
- The --bwlimit option may now be used in combination with --daemon
|
||||
to specify both a default value for the daemon side and a value
|
||||
that cannot be exceeded by a user-specified --bwlimit option.
|
||||
|
||||
- Added the "port" parameter to the rsyncd.conf file. (Promoted from
|
||||
the patches dir.) Also added "address". The command-line options
|
||||
take precedence over a config-file option, as expected.
|
||||
|
||||
- In _exit_cleanup(): when we are exiting with a partially-received
|
||||
file, we now flush any data in the write-cache before closing the
|
||||
partial file.
|
||||
|
||||
- The --inplace support was enhanced to work with --compare-dest,
|
||||
--link-dest, and (the new) --copy-dest options. (Requires protocol
|
||||
29.)
|
||||
|
||||
- Added the --dirs (-d) option for an easier way to copy directories
|
||||
without recursion. Any directories that are encountered are created
|
||||
on the destination. Specifying a directory with a trailing slash
|
||||
copies its immediate contents to the destination.
|
||||
|
||||
- The --files-from option now implies --dirs (-d).
|
||||
|
||||
- Added the --list-only option, which is mainly a way for the client to
|
||||
put the server into listing mode without needing to resort to any
|
||||
internal option kluges (e.g. the age-old use of "-r --exclude="/*/*"
|
||||
for a non-recursive listing). This option is used automatically
|
||||
(behind the scenes) when a modern rsync speaks to a modern daemon,
|
||||
but may also be specified manually if you want to force the use of
|
||||
the --list-only option over a remote-shell connection.
|
||||
|
||||
- Added the --omit-dir-times (-O) option, which will avoid updating
|
||||
the modified time for directories when --times was specified. This
|
||||
option will avoid an extra pass through the file-list at the end of
|
||||
the transfer (to tweak all the directory times), which may provide
|
||||
an appreciable speedup for a really large transfer. (Promoted from
|
||||
the patches dir.)
|
||||
|
||||
- Added the --filter (-f) option and its helper option, -F. Filter
|
||||
rules are an extension to the existing include/exclude handling
|
||||
that also supports nested filter files as well as per-directory
|
||||
filter files (like .cvsignore, but with full filter-rule parsing).
|
||||
This new option was chosen in order to ensure that all existing
|
||||
include/exclude processing remained 100% compatible with older
|
||||
versions. Protocol 29 is needed for full filter-rule support, but
|
||||
backward-compatible rules work with earlier protocol versions.
|
||||
(Promoted from the patches dir and enhanced.)
|
||||
|
||||
- Added the --delay-updates option that puts all updated files into
|
||||
a temporary directory (by default ".~tmp~", but settable via the
|
||||
--partial-dir=DIR option) until the end of the transfer. This
|
||||
makes the updates a little more atomic for a large transfer.
|
||||
|
||||
- If rsync is put into the background, any output from --progress is
|
||||
reduced.
|
||||
|
||||
- Documented the "max verbosity" setting for rsyncd.conf. (This
|
||||
setting was added a couple releases ago, but left undocumented.)
|
||||
|
||||
- The sender and the generator now double-check the file-list index
|
||||
they are given, and refuse to try to do a file transfer on a
|
||||
non-file index (since that would indicate that something had gone
|
||||
very wrong).
|
||||
|
||||
- Added the --itemize-changes (-i) option, which is a way to output a
|
||||
more detailed list of what files changed and in what way. The effect
|
||||
is the same as specifying a --log-format of "%i %n%L" (see both the
|
||||
rsync and rsyncd.conf manpages). Works with --dry-run too.
|
||||
|
||||
- Added the --fuzzy (-y) option, which attempts to find a basis file
|
||||
for a file that is being created from scratch. The current algorithm
|
||||
only looks in the destination directory for the created file, but it
|
||||
does attempt to find a match based on size/mod-time (in case the file
|
||||
was renamed with no other changes) as well as based on a fuzzy
|
||||
name-matching algorithm. This option requires protocol 29 because it
|
||||
needs the new file-sorting order. (Promoted from patches dir and
|
||||
enhanced.) (Requires protocol 29.)
|
||||
|
||||
- Added the --remove-sent-files option, which lets you move files
|
||||
between systems.
|
||||
|
||||
- The hostname in HOST:PATH or HOST::PATH may now be an IPv6 literal
|
||||
enclosed in '[' and ']' (e.g. "[::1]"). (We already allowed IPv6
|
||||
literals in the rsync://HOST:PORT/PATH format.)
|
||||
|
||||
- When rsync recurses to build the file list, it no longer keeps open
|
||||
one or more directory handles from the dir's parent dirs.
|
||||
|
||||
- When building under windows, the default for --daemon is now to
|
||||
avoid detaching, requiring the new --detach option to force rsync
|
||||
to detach.
|
||||
|
||||
- The --dry-run option can now be combined with either --write-batch or
|
||||
--read-batch, allowing you to run a do-nothing test command to see
|
||||
what would happen without --dry-run.
|
||||
|
||||
- The daemon's "read only" config item now sets an internal read_only
|
||||
variable that makes extra sure that no write/delete calls on the
|
||||
read-only side can succeed.
|
||||
|
||||
- The log-format % escapes can now have a numeric field width in
|
||||
between the % and the escape letter (e.g. "%-40n %08p").
|
||||
|
||||
- Improved the option descriptions in the --help text.
|
||||
|
||||
SUPPORT FILES:
|
||||
|
||||
- Added atomic-rsync to the support dir: a perl script that will
|
||||
transfer some files using rsync, and then move the updated files into
|
||||
place all at once at the end of the transfer. Only works when
|
||||
pulling, and uses --link-dest and a parallel hierarchy of files to
|
||||
effect its update.
|
||||
|
||||
- Added mnt-excl to the support dir: a perl script that takes the
|
||||
/proc/mounts file and translates it into a set of excludes that will
|
||||
exclude all mount points (even mapped mounts to the same disk). The
|
||||
excludes are made relative to the specified source dir and properly
|
||||
anchored.
|
||||
|
||||
- Added savetransfer.c to the support dir: a C program that can make
|
||||
a copy of all the data that flows over the wire. This lets you test
|
||||
for data corruption (by saving the data on both the sending side and
|
||||
the receiving side) and provides one way to debug a protocol error.
|
||||
|
||||
- Added rrsync to the support dir: this is an updated version of Joe
|
||||
Smith's restricted rsync perl script. This helps to ensure that only
|
||||
certain rsync commands can be run by an ssh invocation.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Added better checking of the checksum-header values that come over
|
||||
the socket.
|
||||
|
||||
- Merged a variety of file-deleting functions into a single function so
|
||||
that it is easier to maintain.
|
||||
|
||||
- Improved the type of some variables (particularly blocksize vars) for
|
||||
consistency and proper size.
|
||||
|
||||
- Got rid of the uint64 type (which we didn't need).
|
||||
|
||||
- Use a slightly more compatible set of core #include directives.
|
||||
|
||||
- Defined int32 in a way that ensures that the build dies if we can't
|
||||
find a variable with at least 32 bits.
|
||||
|
||||
PROTOCOL DIFFERENCES FOR VERSION 29:
|
||||
|
||||
- A 16-bit flag-word is transmitted after every file-list index. This
|
||||
indicates what is changing between the sender and the receiver. The
|
||||
generator now transmits an index and a flag-word to indicate when
|
||||
dirs and symlinks have changed (instead of producing a message),
|
||||
which makes the outputting of the information more consistent and
|
||||
less prone to screen corruption (because the local receiver/sender is
|
||||
now outputting all the file-change info messages).
|
||||
|
||||
- If a file is being hard-linked, the ITEM_XNAME_FOLLOWS bit is enabled
|
||||
in the flag-word and the name of the file that was linked immediately
|
||||
follows in vstring format (see below).
|
||||
|
||||
- If a file is being transferred with an alternate-basis file, the
|
||||
ITEM_BASIS_TYPE_FOLLOWS bit is enabled in the flag-word and a single
|
||||
byte follows, indicating what type of basis file was chosen. If that
|
||||
indicates that a fuzzy-match was selected, the ITEM_XNAME_FOLLOWS bit
|
||||
is set in the flag-word and the name of the match in vstring format
|
||||
follows the basis byte. A vstring is a variable length string that
|
||||
has its size written prior to the string, and no terminating null.
|
||||
If the string is from 1-127 bytes, the length is a single byte. If
|
||||
it is from 128-32767 bytes, the length is written as ((len >> 8) |
|
||||
0x80) followed by (len % 0x100).
|
||||
|
||||
- The sending of exclude names is done using filter-rule syntax. This
|
||||
means that all names have a prefixed rule indicator, even excludes
|
||||
(which used to be sent as a bare pattern, when possible). The -C
|
||||
option will include the per-dir .cvsignore merge file in the list of
|
||||
filter rules so it is positioned correctly (unlike in some older
|
||||
transfer scenarios).
|
||||
|
||||
- Rsync sorts the filename list in a different way: it sorts the subdir
|
||||
names after the non-subdir names for each dir's contents, and it
|
||||
always puts a dir's contents immediately after the dir's name in the
|
||||
list. (Previously an item named "foo.txt" would sort in between
|
||||
directory "foo/" and "foo/bar".)
|
||||
|
||||
- When talking to a protocol 29 rsync daemon, a list-only request
|
||||
is able to note this before the options are sent over the wire and
|
||||
the new --list-only option is included in the options.
|
||||
|
||||
- When the --stats bytes are sent over the wire (or stored in a batch),
|
||||
they now include two elapsed-time values: one for how long it took to
|
||||
build the file-list, and one for how long it took to send it over the
|
||||
wire (each expressed in thousandths of a second).
|
||||
|
||||
- When --delete-excluded is specified with some filter rules (AKA
|
||||
excludes), a client sender will now initiate a send of the rules to
|
||||
the receiver (older protocols used to omit the sending of excludes in
|
||||
this situation since there were no receiver-specific rules that
|
||||
survived --delete-excluded back then). Note that, as with all the
|
||||
filter-list sending, only items that are significant to the other
|
||||
side will actually be sent over the wire, so the filter-rule list
|
||||
that is sent in this scenario is often empty.
|
||||
|
||||
- An index equal to the file-list count is sent as a keep-alive packet
|
||||
from the generator to the sender, which then forwards it on to the
|
||||
receiver. This normally invalid index is only a valid keep-alive
|
||||
packet if the 16-bit flag-word that follows it contains a single bit
|
||||
(ITEM_IS_NEW, which is normally an illegal flag to appear alone).
|
||||
|
||||
- A protocol-29 batch file includes a bit for the setting of the --dirs
|
||||
option and for the setting of the --compress option. Also, the shell
|
||||
script created by --write-batch will use the --filter option instead
|
||||
of --exclude-from to capture any filter rules.
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Handle an operating system that use mkdev() in place of makedev().
|
||||
|
||||
- Improved configure to better handle cross-compiling.
|
||||
NEWS for rsync 2.6.3 (30 Sep 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.2:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
- 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".
|
||||
|
||||
OUTPUT CHANGES (ATTN: those using a script to parse the verbose output):
|
||||
|
||||
- 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".
|
||||
|
||||
- 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 "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 a crash bug that might appear when --delete was used and
|
||||
multiple source directories were specified.
|
||||
|
||||
- Fixed a 32-bit truncation of the file length when generating the
|
||||
checksums.
|
||||
|
||||
- The --backup code no longer attempts to create some directories
|
||||
over and over again (generating warnings along the way).
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.)
|
||||
|
||||
- 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).
|
||||
|
||||
- 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.
|
||||
|
||||
- Got rid of a potential hang in the receiver when near the end of a
|
||||
phase.
|
||||
|
||||
- When using --backup without a --backup-dir, rsync no longer preserves
|
||||
the modify time on directories. This avoids confusing NFS.
|
||||
|
||||
- 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".
|
||||
|
||||
- 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.
|
||||
|
||||
- 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).
|
||||
|
||||
- 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 daemon authentication code when using one of the
|
||||
batch-processing options.
|
||||
|
||||
- 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).
|
||||
|
||||
- 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).
|
||||
|
||||
- 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).
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- Fixed an age-old crash problem with --read-batch on a local copy
|
||||
(rsync was improperly assuming --whole-file for the local copy).
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- 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:
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- 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).
|
||||
|
||||
- Added the "write only" option for the daemon's config file.
|
||||
|
||||
- Added long-option names for -4 and -6 (namely --ipv4 and --ipv6)
|
||||
and documented all these options in the man page.
|
||||
|
||||
- Improved the handling of the --bwlimit option so that it's less
|
||||
bursty, more accurate, and works properly over a larger range of
|
||||
values.
|
||||
|
||||
- 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 the --checksum-seed=N option for advanced users.
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- The daemon's "refuse options" config item now allows you to match
|
||||
option names using wildcards and/or the single-letter option names.
|
||||
|
||||
- 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.
|
||||
|
||||
- Added the ability to parse a literal IPv6 address in an "rsync:" URL
|
||||
(e.g. rsync://[2001:638:500:101::21]:873/module/dir).
|
||||
|
||||
- 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:
|
||||
|
||||
- Some cleanup in the exclude code has saved some per-exclude memory
|
||||
and made the code easier to maintain.
|
||||
|
||||
- Improved the argv-overflow checking for a remote command that has a
|
||||
lot of args.
|
||||
|
||||
- Use rsyserr() in the various places that were still calling rprintf()
|
||||
with strerror() as an arg.
|
||||
|
||||
- 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).
|
||||
|
||||
- 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.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.2 (30 Apr 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.1:
|
||||
@@ -789,7 +1433,9 @@ Changes since 2.4.6:
|
||||
build farm.
|
||||
|
||||
Partial Protocol History
|
||||
RELEASE DATE VER. DATE OF COMMIT PROTOCOL
|
||||
RELEASE DATE VER. DATE OF COMMIT* PROTOCOL
|
||||
01 Jun 2005 2.6.5 29
|
||||
30 Mar 2005 2.6.4 17 Jan 2005 29
|
||||
30 Sep 2004 2.6.3 28
|
||||
30 Apr 2004 2.6.2 28
|
||||
26 Apr 2004 2.6.1 08 Jan 2004 28
|
||||
|
||||
10
README
10
README
@@ -1,7 +1,7 @@
|
||||
WHAT IS RSYNC?
|
||||
--------------
|
||||
|
||||
rsync is a replacement for rcp that has many more features.
|
||||
rsync is a replacement for scp/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
|
||||
@@ -31,7 +31,7 @@ SETUP
|
||||
|
||||
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 ssh or rsh 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.
|
||||
@@ -89,6 +89,9 @@ mailing list archives at
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
If you don't have web access, email your bug report to
|
||||
rsync@lists.samba.org.
|
||||
|
||||
|
||||
CVS TREE
|
||||
--------
|
||||
@@ -102,8 +105,7 @@ recent version of cvs then use the following commands:
|
||||
|
||||
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co rsync
|
||||
|
||||
Look at the cvs documentation, or http://samba.org/cvs.html, for more
|
||||
details.
|
||||
Look at the cvs documentation for more details.
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
230
TODO
230
TODO
@@ -1,15 +1,9 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
BUGS ---------------------------------------------------------------
|
||||
Fix progress indicator to not corrupt log
|
||||
lchmod question
|
||||
Do not rely on having a group called "nobody"
|
||||
Incorrect timestamps (Debian #100295)
|
||||
Win32
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
server-imposed bandwidth limits
|
||||
rsyncd over ssh
|
||||
Use chroot only if supported
|
||||
Allow supplementary groups in rsyncd.conf 2002/04/09
|
||||
Handling IPv6 on old machines
|
||||
@@ -25,23 +19,18 @@ 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
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
LOGGING --------------------------------------------------------------
|
||||
Make dry run list all updates 2002/04/03
|
||||
Memory accounting
|
||||
Improve error messages
|
||||
Better statistics: Rasmus 2002/03/08
|
||||
Perhaps flush stdout like syslog
|
||||
Log deamon sessions that just list modules
|
||||
Log child death on signal
|
||||
Keep stderr and stdout properly separated (Debian #23626)
|
||||
Log errors with function that reports process of origin
|
||||
verbose output David Stein 2001/12/20
|
||||
Add reason for transfer to file logging
|
||||
debugging of daemon 2002/04/08
|
||||
internationalization
|
||||
|
||||
DEVELOPMENT --------------------------------------------------------
|
||||
@@ -49,9 +38,6 @@ Handling duplicate names
|
||||
Use generic zlib 2002/02/25
|
||||
TDB: 2002/03/12
|
||||
Splint 2002/03/12
|
||||
Memory debugger
|
||||
Create release script
|
||||
Add machines to build farm
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
File list structure in memory
|
||||
@@ -82,37 +68,6 @@ reverse rsync over HTTP Range
|
||||
|
||||
BUGS ---------------------------------------------------------------
|
||||
|
||||
Fix progress indicator to not corrupt log
|
||||
|
||||
Progress indicator can produce corrupt output when transferring directories:
|
||||
|
||||
main/binary-arm/
|
||||
main/binary-arm/admin/
|
||||
main/binary-arm/base/
|
||||
main/binary-arm/comm/8.56kB/s 0:00:52
|
||||
main/binary-arm/devel/
|
||||
main/binary-arm/doc/
|
||||
main/binary-arm/editors/
|
||||
main/binary-arm/electronics/s 0:00:53
|
||||
main/binary-arm/games/
|
||||
main/binary-arm/graphics/
|
||||
main/binary-arm/hamradio/
|
||||
main/binary-arm/interpreters/
|
||||
main/binary-arm/libs/6.61kB/s 0:00:54
|
||||
main/binary-arm/mail/
|
||||
main/binary-arm/math/
|
||||
main/binary-arm/misc/
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
lchmod question
|
||||
|
||||
I don't think we handle this properly on systems that don't have the
|
||||
call. Are there any such?
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Do not rely on having a group called "nobody"
|
||||
|
||||
@@ -122,40 +77,8 @@ Do not rely on having a group called "nobody"
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Incorrect timestamps (Debian #100295)
|
||||
|
||||
A bit hard to believe, but apparently it happens.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Win32
|
||||
|
||||
Don't detach, because this messes up --srvany.
|
||||
|
||||
http://sources.redhat.com/ml/cygwin/2001-08/msg00234.html
|
||||
|
||||
|
||||
|
||||
-- --
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
|
||||
server-imposed bandwidth limits
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
rsyncd over ssh
|
||||
|
||||
There are already some patches to do this.
|
||||
|
||||
BitKeeper uses a server whose login shell is set to bkd. That's
|
||||
probably a reasonable approach.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Use chroot only if supported
|
||||
|
||||
@@ -223,14 +146,6 @@ Other IPv6 stuff:
|
||||
multiple passive addresses. This might be a bit harder, because we
|
||||
may need to select on all of them. Hm.
|
||||
|
||||
Define a syntax for IPv6 literal addresses. Since they include
|
||||
colons, they tend to break most naming systems, including ours.
|
||||
Based on the HTTP IPv6 syntax, I think we should use
|
||||
|
||||
rsync://[::1]/foo/bar [::1]::bar
|
||||
|
||||
which should just take a small change to the parser code.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
@@ -239,6 +154,7 @@ Add ACL support 2001/12/02
|
||||
Transfer ACLs. Need to think of a standard representation.
|
||||
Probably better not to even try to convert between NT and POSIX.
|
||||
Possibly can share some code with Samba.
|
||||
NOTE: there is a patch that implements this in the "patches" subdir.
|
||||
|
||||
-- --
|
||||
|
||||
@@ -307,6 +223,8 @@ Allow forcing arbitrary permissions 2002/03/12
|
||||
|
||||
(Debian #23628)
|
||||
|
||||
NOTE: there is a patch that implements this in the "patches" subdir.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
@@ -351,10 +269,6 @@ Create more granular verbosity jw 2003/05/15
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
|
||||
Update README
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Keep list of open issues and todos on the web site
|
||||
|
||||
@@ -376,17 +290,6 @@ Perhaps redo manual as SGML
|
||||
|
||||
LOGGING --------------------------------------------------------------
|
||||
|
||||
Make dry run list all updates 2002/04/03
|
||||
|
||||
--dry-run is too dry
|
||||
|
||||
Mark Santcroos points out that -n fails to list files which have
|
||||
only metadata changes, though it probably should.
|
||||
|
||||
There may be a Debian bug about this as well.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Memory accounting
|
||||
|
||||
@@ -468,11 +371,6 @@ Log child death on signal
|
||||
-- --
|
||||
|
||||
|
||||
Keep stderr and stdout properly separated (Debian #23626)
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Log errors with function that reports process of origin
|
||||
|
||||
Use a separate function for reporting errors; prefix it with
|
||||
@@ -484,29 +382,12 @@ Log errors with function that reports process of origin
|
||||
|
||||
verbose output David Stein 2001/12/20
|
||||
|
||||
Indicate whether files are new, updated, or deleted
|
||||
|
||||
At end of transfer, show how many files were or were not transferred
|
||||
correctly.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Add reason for transfer to file logging
|
||||
|
||||
Explain *why* every file is transferred or not (e.g. "local mtime
|
||||
123123 newer than 1283198")
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
debugging of daemon 2002/04/08
|
||||
|
||||
Add an rsyncd.conf parameter to turn on debugging on the server.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
internationalization
|
||||
|
||||
Change to using gettext(). Probably need to ship this for platforms
|
||||
@@ -524,46 +405,16 @@ DEVELOPMENT --------------------------------------------------------
|
||||
|
||||
Handling duplicate names
|
||||
|
||||
We need to be careful of duplicate names getting into the file list.
|
||||
See clean_flist(). This could happen if multiple arguments include
|
||||
the same file. Bad.
|
||||
|
||||
I think duplicates are only a problem if they're both flowing
|
||||
through the pipeline at the same time. For example we might have
|
||||
updated the first occurrence after reading the checksums for the
|
||||
second. So possibly we just need to make sure that we don't have
|
||||
both in the pipeline at the same time.
|
||||
|
||||
Possibly if we did one directory at a time that would be sufficient.
|
||||
|
||||
Alternatively we could pre-process the arguments to make sure no
|
||||
duplicates will ever be inserted. There could be some bad cases
|
||||
when we're collapsing symlinks.
|
||||
|
||||
We could have a hash table.
|
||||
|
||||
The root of the problem is that we do not want more than one file
|
||||
list entry referring to the same file. At first glance there are
|
||||
several ways this could happen: symlinks, hardlinks, and repeated
|
||||
names on the command line.
|
||||
|
||||
If names are repeated on the command line, they may be present in
|
||||
different forms, perhaps by traversing directory paths in different
|
||||
ways, traversing paths including symlinks. Also we need to allow
|
||||
for expansion of globs by rsync.
|
||||
|
||||
At the moment, clean_flist() requires having the entire file list in
|
||||
memory. Duplicate names are detected just by a string comparison.
|
||||
|
||||
We don't need to worry about hard links causing duplicates because
|
||||
files are never updated in place. Similarly for symlinks.
|
||||
|
||||
I think even if we're using a different symlink mode we don't need
|
||||
to worry.
|
||||
|
||||
Unless we're really clever this will introduce a protocol
|
||||
incompatibility, so we need to be able to accept the old format as
|
||||
well.
|
||||
Some folks would like rsync to be deterministic in how it handles
|
||||
duplicate names that come from mering multiple source directories
|
||||
into a single destination directory; e.g. the last name wins. We
|
||||
could do this by switching our sort algorithm to one that will
|
||||
guarantee that the names won't be reordered. Alternately, we could
|
||||
assign an ever-increasing number to each item as we insert it into
|
||||
the list and then make sure that we leave the largest number when
|
||||
cleaning the file list (see clean_flist()). Another solution would
|
||||
be to add a hash table, and thus never put any duplicate names into
|
||||
the file list (and bump the protocol to handle this).
|
||||
|
||||
-- --
|
||||
|
||||
@@ -619,45 +470,6 @@ Splint 2002/03/12
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Memory debugger
|
||||
|
||||
jra recommends Valgrind:
|
||||
|
||||
http://devel-home.kde.org/~sewardj/
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create release script
|
||||
|
||||
Script would:
|
||||
|
||||
Update spec files
|
||||
|
||||
Build tar file; upload
|
||||
|
||||
Send announcement to mailing list and c.o.l.a.
|
||||
|
||||
Make freshmeat announcement
|
||||
|
||||
Update web site
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Add machines to build farm
|
||||
|
||||
Cygwin (on different versions of Win32?)
|
||||
|
||||
HP-UX variants (via HP?)
|
||||
|
||||
SCO
|
||||
|
||||
|
||||
|
||||
-- --
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
|
||||
File list structure in memory
|
||||
@@ -692,14 +504,10 @@ Allow skipping MD4 file_sum 2002/04/08
|
||||
calculating MD4 checksums uses 90% of CPU and is unlikely to be
|
||||
useful.
|
||||
|
||||
Indeed for transfers over zlib or ssh we can also rely on the
|
||||
transport to have quite strong protection against corruption.
|
||||
|
||||
Perhaps we should have an option to disable this,
|
||||
analogous to --whole-file, although it would default to
|
||||
disabled. The file checksum takes up a definite space in
|
||||
the protocol -- we can either set it to 0, or perhaps just
|
||||
leave it out.
|
||||
We should not allow it to be disabled separately from -W, though
|
||||
as it is the only thing that lets us know when the rsync algorithm
|
||||
got out of sync and messed the file up (i.e. if the basis file
|
||||
changed between checksum generation and reception).
|
||||
|
||||
-- --
|
||||
|
||||
@@ -842,5 +650,9 @@ reverse rsync over HTTP Range
|
||||
Goswin Brederlow suggested this on Debian; I think tridge and I
|
||||
talked about it previous in relation to rproxy.
|
||||
|
||||
Addendum: It looks like someone is working on a version of this:
|
||||
|
||||
http://zsync.moria.org.uk/
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
61
access.c
61
access.c
@@ -26,7 +26,8 @@
|
||||
|
||||
static int match_hostname(char *host, char *tok)
|
||||
{
|
||||
if (!host || !*host) return 0;
|
||||
if (!host || !*host)
|
||||
return 0;
|
||||
return wildmatch(tok, host);
|
||||
}
|
||||
|
||||
@@ -34,16 +35,16 @@ static int match_binary(char *b1, char *b2, char *mask, int addrlen)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<addrlen; i++) {
|
||||
if ((b1[i]^b2[i])&mask[i]) {
|
||||
for (i = 0; i < addrlen; i++) {
|
||||
if ((b1[i] ^ b2[i]) & mask[i])
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void make_mask(char *mask, int plen, int addrlen) {
|
||||
static void make_mask(char *mask, int plen, int addrlen)
|
||||
{
|
||||
int w, b;
|
||||
|
||||
w = plen >> 3;
|
||||
@@ -75,14 +76,14 @@ static int match_address(char *addr, char *tok)
|
||||
char *a = NULL, *t = NULL;
|
||||
unsigned int len;
|
||||
|
||||
if (!addr || !*addr) return 0;
|
||||
if (!addr || !*addr)
|
||||
return 0;
|
||||
|
||||
p = strchr(tok,'/');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
len = p - tok;
|
||||
}
|
||||
else
|
||||
} else
|
||||
len = strlen(tok);
|
||||
|
||||
/* Fail quietly if tok is a hostname (not an address) */
|
||||
@@ -218,12 +219,14 @@ static int access_match(char *list, char *addr, char *host)
|
||||
char *tok;
|
||||
char *list2 = strdup(list);
|
||||
|
||||
if (!list2) out_of_memory("access_match");
|
||||
if (!list2)
|
||||
out_of_memory("access_match");
|
||||
|
||||
strlower(list2);
|
||||
if (host) strlower(host);
|
||||
if (host)
|
||||
strlower(host);
|
||||
|
||||
for (tok=strtok(list2," ,\t"); tok; tok=strtok(NULL," ,\t")) {
|
||||
for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
|
||||
if (match_hostname(host, tok) || match_address(addr, tok)) {
|
||||
free(list2);
|
||||
return 1;
|
||||
@@ -236,29 +239,25 @@ static int access_match(char *list, char *addr, char *host)
|
||||
|
||||
int allow_access(char *addr, char *host, char *allow_list, char *deny_list)
|
||||
{
|
||||
/* if theres no deny list and no allow list then allow access */
|
||||
if ((!deny_list || !*deny_list) && (!allow_list || !*allow_list))
|
||||
return 1;
|
||||
if (allow_list && !*allow_list)
|
||||
allow_list = NULL;
|
||||
if (deny_list && !*deny_list)
|
||||
deny_list = NULL;
|
||||
|
||||
/* if there is an allow list but no deny list then allow only hosts
|
||||
on the allow list */
|
||||
if (!deny_list || !*deny_list)
|
||||
return(access_match(allow_list, addr, host));
|
||||
/* If we match an allow-list item, we always allow access. */
|
||||
if (allow_list) {
|
||||
if (access_match(allow_list, addr, host))
|
||||
return 1;
|
||||
/* For an allow-list w/o a deny-list, disallow non-matches. */
|
||||
if (!deny_list)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if theres a deny list but no allow list then allow
|
||||
all hosts not on the deny list */
|
||||
if (!allow_list || !*allow_list)
|
||||
return(!access_match(deny_list,addr,host));
|
||||
|
||||
/* if there are both type of list then allow all hosts on the
|
||||
allow list */
|
||||
if (access_match(allow_list,addr,host))
|
||||
return 1;
|
||||
|
||||
/* if there are both type of list and it's not on the allow then
|
||||
allow it if its not on the deny */
|
||||
if (access_match(deny_list,addr,host))
|
||||
/* If we match a deny-list item (and got past any allow-list
|
||||
* items), we always disallow access. */
|
||||
if (deny_list && access_match(deny_list, addr, host))
|
||||
return 0;
|
||||
|
||||
/* Allow all other access. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -51,10 +51,11 @@ void base64_encode(char *buf, int len, char *out)
|
||||
}
|
||||
}
|
||||
|
||||
/* create a 16 byte challenge buffer */
|
||||
/* Generate a challenge buffer and return it base64-encoded. */
|
||||
static void gen_challenge(char *addr, char *challenge)
|
||||
{
|
||||
char input[32];
|
||||
char md4_out[MD4_SUM_LENGTH];
|
||||
struct timeval tv;
|
||||
|
||||
memset(input, 0, sizeof input);
|
||||
@@ -67,7 +68,9 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
|
||||
sum_init(0);
|
||||
sum_update(input, sizeof input);
|
||||
sum_end(challenge);
|
||||
sum_end(md4_out);
|
||||
|
||||
base64_encode(md4_out, MD4_SUM_LENGTH, challenge);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +90,7 @@ static int get_secret(int module, char *user, char *secret, int len)
|
||||
return 0;
|
||||
|
||||
if (do_stat(fname, &st) == -1) {
|
||||
rsyserr(FLOG, errno, "stat(%s)", fname);
|
||||
rsyserr(FLOG, errno, "stat(%s)", safe_fname(fname));
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
@@ -156,14 +159,15 @@ static char *getpassf(char *filename)
|
||||
return NULL;
|
||||
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FERROR, errno, "could not open password file \"%s\"",filename);
|
||||
rsyserr(FERROR, errno, "could not open password file \"%s\"",
|
||||
safe_fname(filename));
|
||||
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);
|
||||
rsyserr(FERROR, errno, "stat(%s)", safe_fname(filename));
|
||||
ok = 0;
|
||||
} else if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR,"password file must not be other-accessible\n");
|
||||
@@ -194,17 +198,18 @@ static char *getpassf(char *filename)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* generate a 16 byte hash from a password and challenge */
|
||||
/* Generate an MD4 hash created from the combination of the password
|
||||
* and the challenge string and return it base64-encoded. */
|
||||
static void generate_hash(char *in, char *challenge, char *out)
|
||||
{
|
||||
char buf[16];
|
||||
char buf[MD4_SUM_LENGTH];
|
||||
|
||||
sum_init(0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
sum_end(buf);
|
||||
|
||||
base64_encode(buf, 16, out);
|
||||
base64_encode(buf, MD4_SUM_LENGTH, out);
|
||||
}
|
||||
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
@@ -213,17 +218,15 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
* 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 *auth_server(int f_in, int f_out, int module, char *host, char *addr,
|
||||
char *leader)
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
char challenge[16];
|
||||
char b64_challenge[30];
|
||||
char challenge[MD4_SUM_LENGTH*2];
|
||||
char line[MAXPATHLEN];
|
||||
static char user[100];
|
||||
char secret[100];
|
||||
char pass[30];
|
||||
char pass2[30];
|
||||
char *tok;
|
||||
char secret[512];
|
||||
char pass2[MD4_SUM_LENGTH*2];
|
||||
char *tok, *pass;
|
||||
|
||||
/* if no auth list then allow anyone in! */
|
||||
if (!users || !*users)
|
||||
@@ -231,52 +234,60 @@ char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
|
||||
|
||||
gen_challenge(addr, challenge);
|
||||
|
||||
base64_encode(challenge, 16, b64_challenge);
|
||||
io_printf(f_out, "%s%s\n", leader, 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)
|
||||
|| (pass = strchr(line, ' ')) == NULL) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"invalid challenge response\n",
|
||||
lp_name(module), host, addr);
|
||||
return NULL;
|
||||
}
|
||||
*pass++ = '\0';
|
||||
|
||||
memset(user, 0, sizeof user);
|
||||
memset(pass, 0, sizeof pass);
|
||||
if (!(users = strdup(users)))
|
||||
out_of_memory("auth_server");
|
||||
|
||||
if (sscanf(line,"%99s %29s", user, pass) != 2)
|
||||
return NULL;
|
||||
|
||||
users = strdup(users);
|
||||
if (!users)
|
||||
return NULL;
|
||||
|
||||
for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
|
||||
if (wildmatch(tok, user))
|
||||
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
|
||||
if (wildmatch(tok, line))
|
||||
break;
|
||||
}
|
||||
free(users);
|
||||
|
||||
if (!tok)
|
||||
return NULL;
|
||||
|
||||
memset(secret, 0, sizeof secret);
|
||||
if (!get_secret(module, user, secret, sizeof secret - 1)) {
|
||||
memset(secret, 0, sizeof secret);
|
||||
if (!tok) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"unauthorized user\n",
|
||||
lp_name(module), host, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
generate_hash(secret, b64_challenge, pass2);
|
||||
memset(secret, 0, sizeof secret);
|
||||
if (!get_secret(module, line, secret, sizeof secret - 1)) {
|
||||
memset(secret, 0, sizeof secret);
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"missing secret for user \"%s\"\n",
|
||||
lp_name(module), host, addr, line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
generate_hash(secret, challenge, pass2);
|
||||
memset(secret, 0, sizeof secret);
|
||||
|
||||
if (strcmp(pass, pass2) == 0)
|
||||
return user;
|
||||
if (strcmp(pass, pass2) != 0) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"password mismatch\n",
|
||||
lp_name(module), host, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return strdup(line);
|
||||
}
|
||||
|
||||
|
||||
void auth_client(int fd, char *user, char *challenge)
|
||||
{
|
||||
char *pass;
|
||||
char pass2[30];
|
||||
char pass2[MD4_SUM_LENGTH*2];
|
||||
|
||||
if (!user || !*user)
|
||||
user = "nobody";
|
||||
@@ -301,5 +312,3 @@ void auth_client(int fd, char *user, char *challenge)
|
||||
generate_hash(pass, challenge, pass2);
|
||||
io_printf(fd, "%s %s\n", user, pass2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
59
backup.c
59
backup.c
@@ -55,21 +55,37 @@ char *get_backup_name(char *fname)
|
||||
/* simple backup creates a backup with a suffix in the same directory */
|
||||
static int make_simple_backup(char *fname)
|
||||
{
|
||||
int rename_errno;
|
||||
char *fnamebak = get_backup_name(fname);
|
||||
|
||||
if (!fnamebak)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
while (1) {
|
||||
if (do_rename(fname, fnamebak) == 0) {
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
safe_fname(fname),
|
||||
safe_fname(fnamebak));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, fnamebak);
|
||||
/* cygwin (at least version b19) reports EINVAL */
|
||||
if (errno == ENOENT || errno == EINVAL)
|
||||
break;
|
||||
|
||||
rename_errno = errno;
|
||||
if (errno == EISDIR && do_rmdir(fnamebak) == 0)
|
||||
continue;
|
||||
if (errno == ENOTDIR && do_unlink(fnamebak) == 0)
|
||||
continue;
|
||||
|
||||
rsyserr(FERROR, rename_errno, "rename %s to backup %s",
|
||||
safe_fname(fname), safe_fname(fnamebak));
|
||||
errno = rename_errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -162,21 +178,15 @@ static int keep_backup(char *fname)
|
||||
int ret_code;
|
||||
|
||||
/* return if no file to keep */
|
||||
#if SUPPORT_LINKS
|
||||
ret_code = do_lstat(fname, &st);
|
||||
#else
|
||||
ret_code = do_stat(fname, &st);
|
||||
#endif
|
||||
if (ret_code < 0)
|
||||
if (do_lstat(fname, &st) < 0)
|
||||
return 1;
|
||||
|
||||
if (!(file = make_file(fname, NULL, NO_EXCLUDES)))
|
||||
if (!(file = make_file(fname, NULL, NO_FILTERS)))
|
||||
return 1; /* the file could have disappeared */
|
||||
|
||||
if (!(buf = get_backup_name(fname)))
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_MKNOD
|
||||
/* Check to see if this is a device file, or link */
|
||||
if (IS_DEVICE(file->mode)) {
|
||||
if (am_root && preserve_devices) {
|
||||
@@ -188,13 +198,12 @@ static int keep_backup(char *fname)
|
||||
} else if (verbose > 2) {
|
||||
rprintf(FINFO,
|
||||
"make_backup: DEVICE %s successful.\n",
|
||||
fname);
|
||||
safe_fname(fname));
|
||||
}
|
||||
}
|
||||
kept = 1;
|
||||
do_unlink(fname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!kept && S_ISDIR(file->mode)) {
|
||||
/* make an empty directory */
|
||||
@@ -213,7 +222,7 @@ static int keep_backup(char *fname)
|
||||
kept = 1;
|
||||
}
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (!kept && preserve_links && S_ISLNK(file->mode)) {
|
||||
if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
|
||||
if (verbose) {
|
||||
@@ -226,7 +235,7 @@ static int keep_backup(char *fname)
|
||||
&& (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);
|
||||
full_fname(buf), safe_fname(file->u.link));
|
||||
}
|
||||
do_unlink(fname);
|
||||
kept = 1;
|
||||
@@ -235,7 +244,7 @@ static int keep_backup(char *fname)
|
||||
|
||||
if (!kept && !S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
|
||||
fname);
|
||||
safe_fname(fname));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -243,7 +252,7 @@ static int keep_backup(char *fname)
|
||||
if (!kept) {
|
||||
if (robust_move(fname, buf) != 0) {
|
||||
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
|
||||
full_fname(fname), buf);
|
||||
full_fname(fname), safe_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! */
|
||||
@@ -253,8 +262,10 @@ static int keep_backup(char *fname)
|
||||
set_perms(buf, file, NULL, 0);
|
||||
free(file);
|
||||
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
safe_fname(fname), safe_fname(buf));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
116
batch.c
116
batch.c
@@ -8,26 +8,32 @@
|
||||
#include "rsync.h"
|
||||
#include <time.h>
|
||||
|
||||
extern char *batch_name;
|
||||
extern int am_sender;
|
||||
extern int eol_nulls;
|
||||
extern int recurse;
|
||||
extern int xfer_dirs;
|
||||
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;
|
||||
extern int do_compression;
|
||||
extern int protocol_version;
|
||||
extern char *batch_name;
|
||||
|
||||
extern struct exclude_list_struct exclude_list;
|
||||
extern struct filter_list_struct filter_list;
|
||||
|
||||
static int *flag_ptr[] = {
|
||||
&recurse,
|
||||
&preserve_uid,
|
||||
&preserve_gid,
|
||||
&preserve_links,
|
||||
&preserve_devices,
|
||||
&preserve_hard_links,
|
||||
&always_checksum,
|
||||
&recurse, /* 0 */
|
||||
&preserve_uid, /* 1 */
|
||||
&preserve_gid, /* 2 */
|
||||
&preserve_links, /* 3 */
|
||||
&preserve_devices, /* 4 */
|
||||
&preserve_hard_links, /* 5 */
|
||||
&always_checksum, /* 6 */
|
||||
&xfer_dirs, /* 7 (protocol 29) */
|
||||
&do_compression, /* 8 (protocol 29) */
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -39,6 +45,8 @@ static char *flag_name[] = {
|
||||
"--devices (-D)",
|
||||
"--hard-links (-H)",
|
||||
"--checksum (-c)",
|
||||
"--dirs (-d)",
|
||||
"--compress (-z)",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -48,6 +56,8 @@ void write_stream_flags(int fd)
|
||||
|
||||
/* Start the batch file with a bitmap of data-stream-affecting
|
||||
* flags. */
|
||||
if (protocol_version < 29)
|
||||
flag_ptr[7] = NULL;
|
||||
for (i = 0, flags = 0; flag_ptr[i]; i++) {
|
||||
if (*flag_ptr[i])
|
||||
flags |= 1 << i;
|
||||
@@ -59,6 +69,8 @@ void read_stream_flags(int fd)
|
||||
{
|
||||
int i, flags;
|
||||
|
||||
if (protocol_version < 29)
|
||||
flag_ptr[7] = NULL;
|
||||
for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) {
|
||||
int set = flags & (1 << i) ? 1 : 0;
|
||||
if (*flag_ptr[i] != set) {
|
||||
@@ -70,6 +82,12 @@ void read_stream_flags(int fd)
|
||||
*flag_ptr[i] = set;
|
||||
}
|
||||
}
|
||||
if (protocol_version < 29) {
|
||||
if (recurse)
|
||||
xfer_dirs |= 1;
|
||||
else if (xfer_dirs < 2)
|
||||
xfer_dirs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_arg(int fd, char *arg)
|
||||
@@ -95,19 +113,16 @@ static void write_arg(int fd, char *arg)
|
||||
write(fd, arg, strlen(arg));
|
||||
}
|
||||
|
||||
static void write_excludes(int fd)
|
||||
static void write_filter_rules(int fd)
|
||||
{
|
||||
struct exclude_struct *ent;
|
||||
struct filter_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);
|
||||
for (ent = filter_list.head; ent; ent = ent->next) {
|
||||
unsigned int plen;
|
||||
char *p = get_rule_prefix(ent->match_flags, "- ", 0, &plen);
|
||||
write_buf(fd, p, plen);
|
||||
write_sbuf(fd, ent->pattern);
|
||||
if (ent->match_flags & MATCHFLG_DIRECTORY)
|
||||
write_byte(fd, '/');
|
||||
write_byte(fd, eol_nulls ? 0 : '\n');
|
||||
@@ -124,7 +139,7 @@ static void write_excludes(int fd)
|
||||
* (hopefully) work. */
|
||||
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
{
|
||||
int fd, i;
|
||||
int fd, i, len;
|
||||
char *p, filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
@@ -132,45 +147,54 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
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);
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
safe_fname(filename));
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
/* Write argvs info to BATCH.sh file */
|
||||
write_arg(fd, argv[0]);
|
||||
if (exclude_list.head)
|
||||
write_sbuf(fd, " --exclude-from=-");
|
||||
if (filter_list.head) {
|
||||
if (protocol_version >= 29)
|
||||
write_sbuf(fd, " --filter=._-");
|
||||
else
|
||||
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, "--filter", 8) == 0
|
||||
|| strncmp(p, "--include", 9) == 0
|
||||
|| strncmp(p, "--exclude", 9) == 0) {
|
||||
if (strchr(p, '=') == NULL)
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(p, "-f") == 0) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
write(fd, " ", 1);
|
||||
if (strncmp(p, "--write-batch", 13) == 0) {
|
||||
if (strncmp(p, "--write-batch", len = 13) == 0
|
||||
|| strncmp(p, "--only-write-batch", len = 18) == 0) {
|
||||
write(fd, "--read-batch", 12);
|
||||
if (p[13] == '=') {
|
||||
if (p[len] == '=') {
|
||||
write(fd, "=", 1);
|
||||
write_arg(fd, p + 14);
|
||||
write_arg(fd, p + len + 1);
|
||||
}
|
||||
} else
|
||||
write_arg(fd, p);
|
||||
}
|
||||
if ((p = find_colon(argv[argc - 1])) != NULL) {
|
||||
if (*++p == ':')
|
||||
p++;
|
||||
} else
|
||||
if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
|
||||
p = argv[argc - 1];
|
||||
write(fd, " ${1:-", 6);
|
||||
write_arg(fd, p);
|
||||
write_byte(fd, '}');
|
||||
if (exclude_list.head)
|
||||
write_excludes(fd);
|
||||
if (filter_list.head)
|
||||
write_filter_rules(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error", filename);
|
||||
rsyserr(FERROR, errno, "Batch file %s write error",
|
||||
safe_fname(filename));
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
@@ -187,25 +211,25 @@ void show_flist(int index, struct file_struct **fptr)
|
||||
rprintf(FINFO, "flist->length=%.0f\n",
|
||||
(double) fptr[i]->length);
|
||||
rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
|
||||
rprintf(FINFO, "flist->basename=%s\n", fptr[i]->basename);
|
||||
if (fptr[i]->dirname)
|
||||
rprintf(FINFO, "flist->basename=%s\n",
|
||||
safe_fname(fptr[i]->basename));
|
||||
if (fptr[i]->dirname) {
|
||||
rprintf(FINFO, "flist->dirname=%s\n",
|
||||
fptr[i]->dirname);
|
||||
if (fptr[i]->basedir)
|
||||
rprintf(FINFO, "flist->basedir=%s\n",
|
||||
fptr[i]->basedir);
|
||||
safe_fname(fptr[i]->dirname));
|
||||
}
|
||||
if (am_sender && fptr[i]->dir.root) {
|
||||
rprintf(FINFO, "flist->dir.root=%s\n",
|
||||
safe_fname(fptr[i]->dir.root));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* for debugging */
|
||||
void show_argvs(int argc, char *argv[])
|
||||
{
|
||||
/* for debugging * */
|
||||
|
||||
int i;
|
||||
rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
/* if (argv[i]) */
|
||||
rprintf(FINFO, "i=%d,argv[i]=%s\n", i, argv[i]);
|
||||
|
||||
}
|
||||
rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc);
|
||||
for (i = 0; i < argc; i++)
|
||||
rprintf(FINFO, "i=%d,argv[i]=%s\n", i, safe_fname(argv[i]));
|
||||
}
|
||||
|
||||
48
checksum.c
48
checksum.c
@@ -30,9 +30,9 @@ extern int protocol_version;
|
||||
a simple 32 bit checksum that can be upadted from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
*/
|
||||
uint32 get_checksum1(char *buf1,int len)
|
||||
uint32 get_checksum1(char *buf1, int32 len)
|
||||
{
|
||||
int i;
|
||||
int32 i;
|
||||
uint32 s1, s2;
|
||||
schar *buf = (schar *)buf1;
|
||||
|
||||
@@ -49,18 +49,20 @@ uint32 get_checksum1(char *buf1,int len)
|
||||
}
|
||||
|
||||
|
||||
void get_checksum2(char *buf,int len,char *sum)
|
||||
void get_checksum2(char *buf, int32 len, char *sum)
|
||||
{
|
||||
int i;
|
||||
int32 i;
|
||||
static char *buf1;
|
||||
static int len1;
|
||||
static int32 len1;
|
||||
struct mdfour m;
|
||||
|
||||
if (len > len1) {
|
||||
if (buf1) free(buf1);
|
||||
if (buf1)
|
||||
free(buf1);
|
||||
buf1 = new_array(char, len+4);
|
||||
len1 = len;
|
||||
if (!buf1) out_of_memory("get_checksum2");
|
||||
if (!buf1)
|
||||
out_of_memory("get_checksum2");
|
||||
}
|
||||
|
||||
mdfour_begin(&m);
|
||||
@@ -125,7 +127,7 @@ void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
}
|
||||
|
||||
|
||||
static int sumresidue;
|
||||
static int32 sumresidue;
|
||||
static char sumrbuf[CSUM_CHUNK];
|
||||
static struct mdfour md;
|
||||
|
||||
@@ -146,41 +148,37 @@ void sum_init(int seed)
|
||||
* @todo Perhaps get rid of md and just pass in the address each time.
|
||||
* Very slightly clearer and slower.
|
||||
**/
|
||||
void sum_update(char *p, int len)
|
||||
void sum_update(char *p, int32 len)
|
||||
{
|
||||
int i;
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(sumrbuf+sumresidue, p, len);
|
||||
memcpy(sumrbuf + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sumresidue) {
|
||||
i = MIN(CSUM_CHUNK-sumresidue,len);
|
||||
memcpy(sumrbuf+sumresidue,p,i);
|
||||
mdfour_update(&md, (uchar *)sumrbuf, (i+sumresidue));
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(sumrbuf + sumresidue, p, i);
|
||||
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
memcpy(sumrbuf,p+i,CSUM_CHUNK);
|
||||
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
|
||||
while (len >= CSUM_CHUNK) {
|
||||
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
if (len - i > 0) {
|
||||
sumresidue = len-i;
|
||||
memcpy(sumrbuf,p+i,sumresidue);
|
||||
} else {
|
||||
sumresidue = 0;
|
||||
}
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(sumrbuf, p, sumresidue);
|
||||
}
|
||||
|
||||
void sum_end(char *sum)
|
||||
{
|
||||
if (sumresidue || protocol_version >= 27) {
|
||||
if (sumresidue || protocol_version >= 27)
|
||||
mdfour_update(&md, (uchar *)sumrbuf, sumresidue);
|
||||
}
|
||||
|
||||
mdfour_result(&md, (uchar *)sum);
|
||||
}
|
||||
|
||||
25
cleanup.c
25
cleanup.c
@@ -24,6 +24,7 @@
|
||||
extern int io_error;
|
||||
extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
extern char *partial_dir;
|
||||
|
||||
/**
|
||||
* Close all open sockets and files, allowing a (somewhat) graceful
|
||||
@@ -36,12 +37,11 @@ void close_all(void)
|
||||
int max_fd;
|
||||
int fd;
|
||||
int ret;
|
||||
struct stat st;
|
||||
STRUCT_STAT st;
|
||||
|
||||
max_fd = sysconf(_SC_OPEN_MAX) - 1;
|
||||
for (fd = max_fd; fd >= 0; fd--) {
|
||||
ret = fstat(fd,&st);
|
||||
if (fstat(fd,&st) == 0) {
|
||||
if ((ret = do_fstat(fd, &st)) == 0) {
|
||||
if (is_a_socket(fd))
|
||||
ret = shutdown(fd, 2);
|
||||
ret = close(fd);
|
||||
@@ -99,7 +99,7 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
code, file, line);
|
||||
code, safe_fname(file), line);
|
||||
}
|
||||
|
||||
if (cleanup_child_pid != -1) {
|
||||
@@ -117,9 +117,12 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
cleanup_fname = NULL;
|
||||
if (cleanup_fd_r != -1)
|
||||
close(cleanup_fd_r);
|
||||
if (cleanup_fd_w != -1)
|
||||
if (cleanup_fd_w != -1) {
|
||||
flush_write_file(cleanup_fd_w);
|
||||
close(cleanup_fd_w);
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file, 0);
|
||||
}
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file, 0,
|
||||
!partial_dir);
|
||||
}
|
||||
io_flush(FULL_FLUSH);
|
||||
if (cleanup_fname)
|
||||
@@ -133,10 +136,12 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
if ((io_error & ~IOERR_VANISHED) || log_got_error)
|
||||
code = RERR_PARTIAL;
|
||||
else if (io_error)
|
||||
if (io_error & IOERR_DEL_LIMIT)
|
||||
code = RERR_DEL_LIMIT;
|
||||
if (io_error & IOERR_VANISHED)
|
||||
code = RERR_VANISHED;
|
||||
if (io_error & IOERR_GENERAL || log_got_error)
|
||||
code = RERR_PARTIAL;
|
||||
}
|
||||
|
||||
if (code)
|
||||
@@ -144,7 +149,7 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
|
||||
ocode, file, line, code);
|
||||
ocode, safe_fname(file), line, code);
|
||||
}
|
||||
|
||||
close_all();
|
||||
|
||||
@@ -189,7 +189,7 @@ void client_sockaddr(int fd,
|
||||
memset(sin, 0, sizeof *sin);
|
||||
sin->sin_family = AF_INET;
|
||||
*ss_len = sizeof (struct sockaddr_in);
|
||||
#if HAVE_SOCKADDR_IN_LEN
|
||||
#ifdef HAVE_SOCKADDR_IN_LEN
|
||||
sin->sin_len = *ss_len;
|
||||
#endif
|
||||
sin->sin_port = sin6.sin6_port;
|
||||
|
||||
160
clientserver.c
160
clientserver.c
@@ -27,17 +27,15 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int list_only;
|
||||
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;
|
||||
extern int kludge_around_eof;
|
||||
extern int kluge_around_eof;
|
||||
extern int daemon_over_rsh;
|
||||
extern int list_only;
|
||||
extern int sanitize_paths;
|
||||
extern int filesfrom_fd;
|
||||
extern int remote_protocol;
|
||||
@@ -47,12 +45,18 @@ 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 struct filter_list_struct server_filter_list;
|
||||
extern char *config_file;
|
||||
extern char *files_from;
|
||||
|
||||
char *auth_user;
|
||||
int read_only = 0;
|
||||
int daemon_log_format_has_i = 0;
|
||||
int daemon_log_format_has_o_or_i = 0;
|
||||
int module_id = -1;
|
||||
|
||||
/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */
|
||||
unsigned int module_dirlen = 0;
|
||||
|
||||
/**
|
||||
* Run a client connected to an rsyncd. The alternative to this
|
||||
@@ -82,7 +86,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((p = strchr(host, '@')) != NULL) {
|
||||
if ((p = strrchr(host, '@')) != NULL) {
|
||||
user = host;
|
||||
host = p+1;
|
||||
*p = '\0';
|
||||
@@ -95,7 +99,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
|
||||
ret = start_inband_exchange(user, path, fd, fd, argc);
|
||||
|
||||
return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
|
||||
return ret ? ret : client_run(fd, fd, -1, argc, argv);
|
||||
}
|
||||
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
@@ -108,7 +112,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
char *p;
|
||||
|
||||
if (argc == 0 && !am_sender)
|
||||
list_only = 1;
|
||||
list_only |= 1;
|
||||
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR,
|
||||
@@ -121,19 +125,6 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
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;
|
||||
* this is a no-op for direct-socket-connection mode */
|
||||
daemon_over_rsh = 0;
|
||||
server_options(sargs, &sargc);
|
||||
|
||||
sargs[sargc++] = ".";
|
||||
|
||||
if (path && *path)
|
||||
sargs[sargc++] = path;
|
||||
|
||||
sargs[sargc] = NULL;
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
|
||||
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
@@ -150,6 +141,25 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
|
||||
if (list_only && protocol_version >= 29)
|
||||
list_only |= 2;
|
||||
|
||||
/* set daemon_over_rsh to false since we need to build the
|
||||
* true set of args passed through the rsh/ssh connection;
|
||||
* this is a no-op for direct-socket-connection mode */
|
||||
daemon_over_rsh = 0;
|
||||
server_options(sargs, &sargc);
|
||||
|
||||
sargs[sargc++] = ".";
|
||||
|
||||
if (path && *path)
|
||||
sargs[sargc++] = path;
|
||||
|
||||
sargs[sargc] = NULL;
|
||||
|
||||
if (verbose > 1)
|
||||
print_child_argv(sargs);
|
||||
|
||||
p = strchr(path,'/');
|
||||
if (p) *p = 0;
|
||||
io_printf(f_out, "%s\n", path);
|
||||
@@ -157,7 +167,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
|
||||
/* Old servers may just drop the connection here,
|
||||
rather than sending a proper EXIT command. Yuck. */
|
||||
kludge_around_eof = list_only && (protocol_version < 25);
|
||||
kluge_around_eof = list_only && protocol_version < 25 ? 1 : 0;
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
@@ -185,12 +195,12 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
rprintf(FERROR, "%s\n", line);
|
||||
/* This is always fatal; the server will now
|
||||
* close the socket. */
|
||||
return RERR_STARTCLIENT;
|
||||
} else {
|
||||
rprintf(FINFO,"%s\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rprintf(FINFO, "%s\n", line);
|
||||
}
|
||||
kludge_around_eof = False;
|
||||
kluge_around_eof = 0;
|
||||
|
||||
for (i = 0; i < sargc; i++) {
|
||||
io_printf(f_out, "%s\n", sargs[i]);
|
||||
@@ -246,29 +256,37 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
|
||||
if (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));
|
||||
safe_fname(lp_lock_file(i)));
|
||||
io_printf(f_out, "@ERROR: failed to open lock file\n");
|
||||
} else {
|
||||
rprintf(FLOG, "max connections (%d) reached\n",
|
||||
lp_max_connections(i));
|
||||
io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n",
|
||||
io_printf(f_out, "@ERROR: max connections (%d) reached -- try again later\n",
|
||||
lp_max_connections(i));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
auth_user = auth_server(f_in, f_out, i, addr, "@RSYNCD: AUTHREQD ");
|
||||
auth_user = auth_server(f_in, f_out, i, host, addr, "@RSYNCD: AUTHREQD ");
|
||||
|
||||
if (!auth_user) {
|
||||
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;
|
||||
}
|
||||
|
||||
module_id = i;
|
||||
|
||||
if (lp_read_only(i))
|
||||
read_only = 1;
|
||||
|
||||
if (lp_transfer_logging(i)) {
|
||||
if (log_format_has(lp_log_format(i), 'i'))
|
||||
daemon_log_format_has_i = 1;
|
||||
if (daemon_log_format_has_i
|
||||
|| log_format_has(lp_log_format(i), 'o'))
|
||||
daemon_log_format_has_o_or_i = 1;
|
||||
}
|
||||
|
||||
am_root = (MY_UID() == 0);
|
||||
|
||||
if (am_root) {
|
||||
@@ -300,26 +318,32 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
/* TODO: Perhaps take a list of gids, and make them into the
|
||||
* supplementary groups. */
|
||||
|
||||
exclude_path_prefix = use_chroot? "" : lp_path(i);
|
||||
if (*exclude_path_prefix == '/' && !exclude_path_prefix[1])
|
||||
exclude_path_prefix = "";
|
||||
if (use_chroot || (module_dirlen = strlen(lp_path(i))) == 1) {
|
||||
module_dirlen = 0;
|
||||
set_filter_dir("/", 1);
|
||||
} else
|
||||
set_filter_dir(lp_path(i), module_dirlen);
|
||||
|
||||
p = lp_filter(i);
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ANCHORED2ABS);
|
||||
|
||||
p = lp_include_from(i);
|
||||
add_exclude_file(&server_exclude_list, p,
|
||||
XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
|
||||
parse_filter_file(&server_filter_list, p, MATCHFLG_INCLUDE,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_include(i);
|
||||
add_exclude(&server_exclude_list, p,
|
||||
XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE);
|
||||
parse_rule(&server_filter_list, p,
|
||||
MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES);
|
||||
|
||||
p = lp_exclude_from(i);
|
||||
add_exclude_file(&server_exclude_list, p,
|
||||
XFLG_FATAL_ERRORS);
|
||||
parse_filter_file(&server_filter_list, p, 0,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_exclude(i);
|
||||
add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT);
|
||||
|
||||
exclude_path_prefix = NULL;
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES);
|
||||
|
||||
log_init();
|
||||
|
||||
@@ -337,20 +361,23 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
* in which case we fail.
|
||||
*/
|
||||
if (chroot(lp_path(i))) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chroot %s failed",
|
||||
safe_fname(lp_path(i)));
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/")) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n",
|
||||
safe_fname(lp_path(i)));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!push_dir(lp_path(i))) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n",
|
||||
safe_fname(lp_path(i)));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -429,6 +456,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
start_glob = 1;
|
||||
}
|
||||
|
||||
verbose = 0; /* future verbosity is controlled by client options */
|
||||
argp = argv;
|
||||
ret = parse_arguments(&argc, (const char ***) &argp, 0);
|
||||
|
||||
@@ -462,8 +490,24 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
* 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);
|
||||
if (!am_sender) {
|
||||
/* Since we failed in our option parsing, we may not
|
||||
* have finished parsing that the client sent us a
|
||||
* --files-from option, so look for it manually.
|
||||
* Without this, the socket would be in the wrong
|
||||
* state for the upcoming error message. */
|
||||
if (!files_from) {
|
||||
int i;
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (strncmp(argv[i], "--files-from", 12) == 0) {
|
||||
files_from = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (files_from)
|
||||
write_byte(f_out, 0);
|
||||
}
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
@@ -473,8 +517,8 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (lp_timeout(i))
|
||||
io_timeout = lp_timeout(i);
|
||||
if (lp_timeout(i) && lp_timeout(i) > io_timeout)
|
||||
set_io_timeout(lp_timeout(i));
|
||||
|
||||
start_server(f_in, f_out, argc, argp);
|
||||
|
||||
@@ -598,6 +642,11 @@ int daemon_main(void)
|
||||
if (!lp_load(config_file, 1))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
|
||||
if (rsync_port == 0 && (rsync_port = lp_rsync_port()) == 0)
|
||||
rsync_port = RSYNC_PORT;
|
||||
if (bind_address == NULL && *lp_bind_address())
|
||||
bind_address = lp_bind_address();
|
||||
|
||||
log_init();
|
||||
|
||||
rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n",
|
||||
@@ -614,7 +663,8 @@ int daemon_main(void)
|
||||
if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC,
|
||||
0666 & ~orig_umask)) == -1) {
|
||||
cleanup_set_pid(0);
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s",
|
||||
safe_fname(pid_file));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
|
||||
|
||||
27
compat.c
27
compat.c
@@ -30,9 +30,13 @@ int remote_protocol = 0;
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int inplace;
|
||||
extern int fuzzy_basis;
|
||||
extern int read_batch;
|
||||
extern int checksum_seed;
|
||||
extern int basis_dir_cnt;
|
||||
extern int protocol_version;
|
||||
extern char *dest_option;
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
@@ -55,7 +59,7 @@ void setup_protocol(int f_out,int f_in)
|
||||
}
|
||||
if (remote_protocol < MIN_PROTOCOL_VERSION
|
||||
|| remote_protocol > MAX_PROTOCOL_VERSION) {
|
||||
rprintf(FERROR,"protocol version mismatch - is your shell clean?\n");
|
||||
rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n");
|
||||
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
@@ -74,6 +78,27 @@ void setup_protocol(int f_out,int f_in)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (fuzzy_basis && protocol_version < 29) {
|
||||
rprintf(FERROR,
|
||||
"--fuzzy requires protocol 29 or higher (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (basis_dir_cnt && inplace && protocol_version < 29) {
|
||||
rprintf(FERROR,
|
||||
"%s with --inplace requires protocol 29 or higher (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (basis_dir_cnt > 1 && protocol_version < 29) {
|
||||
rprintf(FERROR,
|
||||
"Multiple %s options requires protocol 29 or higher (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (am_server) {
|
||||
if (!checksum_seed)
|
||||
checksum_seed = time(NULL);
|
||||
|
||||
219
configure.in
219
configure.in
@@ -3,9 +3,9 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT()
|
||||
AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.52)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
RSYNC_VERSION=2.6.3
|
||||
RSYNC_VERSION=2.6.5
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -57,7 +57,7 @@ fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE(profile,
|
||||
AC_HELP_STRING([--enable-profile],
|
||||
AC_HELP_STRING([--enable-profile],
|
||||
[turn on CPU profiling (default no)],
|
||||
[], []))
|
||||
if test x"$enable_profile" = xyes
|
||||
@@ -68,7 +68,7 @@ fi
|
||||
|
||||
# Specifically, this turns on panic_action handling.
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
AC_HELP_STRING([--enable-maintainer-mode],
|
||||
AC_HELP_STRING([--enable-maintainer-mode],
|
||||
[turn on extra debug features],
|
||||
[], []))
|
||||
if test x"$enable_maintainer_mode" = xyes
|
||||
@@ -82,7 +82,7 @@ fi
|
||||
CFLAGS="$CFLAGS -DHAVE_CONFIG_H"
|
||||
|
||||
# If GCC, turn on warnings.
|
||||
if test "x$GCC" = "xyes"
|
||||
if test x"$GCC" = x"yes"
|
||||
then
|
||||
CFLAGS="$CFLAGS -Wall -W"
|
||||
fi
|
||||
@@ -122,7 +122,9 @@ AC_ARG_WITH(rsh,
|
||||
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
|
||||
|
||||
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
|
||||
AC_DEFINE_UNQUOTED(HAVE_REMSH, $HAVE_REMSH, [remote shell is remsh not rsh])
|
||||
if test x$HAVE_REMSH = x1; then
|
||||
AC_DEFINE(HAVE_REMSH, 1, [Define to 1 if remote shell is remsh, not rsh])
|
||||
fi
|
||||
|
||||
if test x"$with_rsh" != x
|
||||
then
|
||||
@@ -181,6 +183,17 @@ ipv6trylibc=yes
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--disable-ipv6], [don't even try to use IPv6]))
|
||||
|
||||
dnl Do you want to disable use of locale functions
|
||||
AH_TEMPLATE([CONFIG_LOCALE],
|
||||
[Undefine if you don't want locale features. By default this is defined.])
|
||||
AC_ARG_ENABLE([locale],
|
||||
AC_HELP_STRING([--disable-locale], [turn off locale features]),
|
||||
[if test x$enableval = xyes; then
|
||||
AC_DEFINE(CONFIG_LOCALE)
|
||||
fi],
|
||||
AC_DEFINE(CONFIG_LOCALE)
|
||||
)
|
||||
|
||||
if test "x$enable_ipv6" != xno
|
||||
then
|
||||
AC_MSG_CHECKING([ipv6 stack type])
|
||||
@@ -275,7 +288,7 @@ 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,
|
||||
[Define if sockets need to be shutdown])
|
||||
[Define to 1 if sockets need to be shutdown])
|
||||
;;
|
||||
* ) AC_MSG_RESULT(no);;
|
||||
esac
|
||||
@@ -287,15 +300,19 @@ 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 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 \
|
||||
sys/un.h glob.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
|
||||
netdb.h malloc.h float.h)
|
||||
AC_HEADER_MAJOR
|
||||
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(off_t)
|
||||
AC_CHECK_SIZEOF(off64_t)
|
||||
|
||||
AC_C_INLINE
|
||||
AC_C_LONG_DOUBLE
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
AC_TYPE_UID_T
|
||||
@@ -306,14 +323,13 @@ AC_TYPE_PID_T
|
||||
AC_TYPE_GETGROUPS
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
|
||||
AC_CHECK_TYPE([ino_t], [unsigned])
|
||||
TYPE_SOCKLEN_T
|
||||
|
||||
AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [
|
||||
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
|
||||
rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)])
|
||||
if test x"$rsync_cv_errno" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ERRNO_DECL, 1, [ ])
|
||||
AC_DEFINE(HAVE_ERRNO_DECL, 1, [Define to 1 if errno is declared in errno.h])
|
||||
fi
|
||||
|
||||
# The following test taken from the cvs sources
|
||||
@@ -348,7 +364,7 @@ if test x"$ac_cv_func_connect" = x"no"; then
|
||||
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
|
||||
AC_DEFINE(HAVE_CONNECT, 1, [ ])
|
||||
AC_DEFINE(HAVE_CONNECT, 1, [Define to 1 if you have the "connect" function])
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -383,7 +399,7 @@ if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes"; then
|
||||
#include <netdb.h>],[getaddrinfo(NULL, NULL, NULL, NULL);],
|
||||
[AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_GETADDRINFO, 1,
|
||||
[Define if you have the `getaddrinfo' function.])],
|
||||
[Define to 1 if you have the "getaddrinfo" function.])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ(lib/getaddrinfo)])])
|
||||
AC_CHECK_FUNCS(getnameinfo, , [AC_LIBOBJ(lib/getnameinfo)])
|
||||
@@ -409,13 +425,22 @@ AC_CHECK_MEMBER([struct sockaddr_in.sin_len],
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_UN_LEN, 1, [Do we have sockaddr_un.sun_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,
|
||||
[Define if you have strct sockaddr_storage.] ),
|
||||
[Define to 1 if you have struct sockaddr_storage.] ),
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
|
||||
@@ -427,6 +452,27 @@ AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING(struct stat64)
|
||||
AC_TRY_COMPILE([#include <stdio.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
],[struct stat64 st;],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_STRUCT_STAT64,1,[Define to 1 if you have struct stat64.]),
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
# if we can't find strcasecmp, look in -lresolv (for Unixware at least)
|
||||
#
|
||||
AC_CHECK_FUNCS(strcasecmp)
|
||||
@@ -443,9 +489,34 @@ AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
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 \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
open64 mkstemp64)
|
||||
setlocale setmode open64 lseek64 mkstemp64 va_copy __va_copy)
|
||||
|
||||
AC_CHECK_FUNCS(getpgrp tcgetpgrp)
|
||||
if test $ac_cv_func_getpgrp = yes; then
|
||||
AC_FUNC_GETPGRP
|
||||
fi
|
||||
|
||||
# Determine whether chown follows symlinks (it should).
|
||||
AC_CACHE_CHECK([whether chown() dereferences symlinks],rsync_cv_chown_follows_symlink,[
|
||||
AC_TRY_RUN([
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
main() {
|
||||
char const *dangling_symlink = "conftest.dangle";
|
||||
unlink(dangling_symlink);
|
||||
if (symlink("conftest.no-such", dangling_symlink) < 0) abort();
|
||||
if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) exit(0);
|
||||
exit(1);
|
||||
}],
|
||||
rsync_cv_chown_follows_symlink=yes,rsync_cv_chown_follows_symlink=no,rsync_cv_chown_follows_symlink=yes)])
|
||||
if test $rsync_cv_chown_follows_symlink = no; then
|
||||
AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
|
||||
AC_TRY_RUN([
|
||||
@@ -458,7 +529,7 @@ main() {
|
||||
}],
|
||||
rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)])
|
||||
if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SOCKETPAIR, 1, [ ])
|
||||
AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function])
|
||||
fi
|
||||
|
||||
if test x"$with_included_popt" != x"yes"
|
||||
@@ -482,39 +553,11 @@ else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for long long],rsync_cv_HAVE_LONGLONG,[
|
||||
AC_TRY_RUN([#include <stdio.h>
|
||||
main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); }],
|
||||
rsync_cv_HAVE_LONGLONG=yes,rsync_cv_HAVE_LONGLONG=no,rsync_cv_HAVE_LONGLONG=cross)])
|
||||
if test x"$rsync_cv_HAVE_LONGLONG" = x"yes"; then
|
||||
AC_DEFINE(HAVE_LONGLONG, 1, [ ])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for off64_t],rsync_cv_HAVE_OFF64_T,[
|
||||
AC_TRY_RUN([#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }],
|
||||
rsync_cv_HAVE_OFF64_T=yes,rsync_cv_HAVE_OFF64_T=no,rsync_cv_HAVE_OFF64_T=cross)])
|
||||
if test x"$rsync_cv_HAVE_OFF64_T" = x"yes"; then
|
||||
AC_DEFINE(HAVE_OFF64_T, 1, [ ])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for short ino_t],rsync_cv_HAVE_SHORT_INO_T,[
|
||||
AC_TRY_RUN([#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
main() { if (sizeof(ino_t) < sizeof(unsigned int)) return 0; return 1; }],
|
||||
rsync_cv_HAVE_SHORT_INO_T=yes,rsync_cv_HAVE_SHORT_INO_T=no,rsync_cv_HAVE_SHORT_INO_T=cross)])
|
||||
if test x"$rsync_cv_HAVE_SHORT_INO_T" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SHORT_INO_T, 1, [ ])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for unsigned char],rsync_cv_HAVE_UNSIGNED_CHAR,[
|
||||
AC_TRY_RUN([#include <stdio.h>
|
||||
main() { char c; c=250; exit((c > 0)?0:1); }],
|
||||
rsync_cv_HAVE_UNSIGNED_CHAR=yes,rsync_cv_HAVE_UNSIGNED_CHAR=no,rsync_cv_HAVE_UNSIGNED_CHAR=cross)])
|
||||
if test x"$rsync_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_UNSIGNED_CHAR, 1, [ ])
|
||||
AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[
|
||||
AC_TRY_COMPILE([],[signed char *s = ""],
|
||||
rsync_cv_SIGNED_CHAR_OK=yes,rsync_cv_SIGNED_CHAR_OK=no)])
|
||||
if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then
|
||||
AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[
|
||||
@@ -525,26 +568,25 @@ if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
|
||||
di->d_name[0] == 0) exit(0); exit(1);} ],
|
||||
rsync_cv_HAVE_BROKEN_READDIR=yes,rsync_cv_HAVE_BROKEN_READDIR=no,rsync_cv_HAVE_BROKEN_READDIR=cross)])
|
||||
if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_BROKEN_READDIR, 1, [ ])
|
||||
AC_DEFINE(HAVE_BROKEN_READDIR, 1, [Define to 1 if readdir() is broken])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_UTIMBUF,[
|
||||
AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <utime.h>],
|
||||
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
|
||||
rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no,rsync_cv_HAVE_UTIMBUF=cross)])
|
||||
rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no)])
|
||||
if test x"$rsync_cv_HAVE_UTIMBUF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_UTIMBUF, 1, [ ])
|
||||
AC_DEFINE(HAVE_UTIMBUF, 1, [Define to 1 if you have the "struct utimbuf" type])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/time.h>
|
||||
#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)])
|
||||
AC_TRY_COMPILE([#include <sys/time.h>
|
||||
#include <unistd.h>],
|
||||
[struct timeval tv; exit(gettimeofday(&tv, NULL));],
|
||||
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no)])
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ])
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a time-zone arg])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
|
||||
@@ -569,7 +611,7 @@ main() { foo("hello"); }
|
||||
],
|
||||
rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)])
|
||||
if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ])
|
||||
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [Define to 1 if vsprintf has a C99-compatible return value])
|
||||
fi
|
||||
|
||||
|
||||
@@ -592,7 +634,17 @@ rsync_cv_HAVE_SECURE_MKSTEMP=yes,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=no,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
|
||||
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [ ])
|
||||
case $target_os in
|
||||
hpux*)
|
||||
dnl HP-UX has a broken mkstemp() implementation they refuse to fix,
|
||||
dnl so we noisily skip using it. See HP change request JAGaf34426
|
||||
dnl for details. (sbonds)
|
||||
AC_MSG_WARN(Skipping broken HP-UX mkstemp() -- using mktemp() instead)
|
||||
;;
|
||||
*)
|
||||
AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [Define to 1 if mkstemp() is available and works right])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
@@ -608,7 +660,7 @@ if (strcmp(inet_ntoa(ip),"18.52.86.120") &&
|
||||
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
|
||||
AC_DEFINE(REPLACE_INET_NTOA, 1, [ ])
|
||||
AC_DEFINE(REPLACE_INET_NTOA, 1, [Define to 1 if inet_ntoa() needs to be replaced])
|
||||
fi
|
||||
|
||||
|
||||
@@ -622,7 +674,35 @@ 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
|
||||
AC_DEFINE(REPLACE_INET_ATON, 1, [ ])
|
||||
AC_DEFINE(REPLACE_INET_ATON, 1, [Define to 1 if inet_aton() needs to be replaced])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[
|
||||
AC_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
main() { int rc, ec; char *fn = "fifo-test";
|
||||
unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn);
|
||||
if (rc) {printf("%d %d\n",rc,ec); return ec;}
|
||||
return 0;}],
|
||||
rsync_cv_MKNOD_CREATES_FIFOS=yes,rsync_cv_MKNOD_CREATES_FIFOS=no,rsync_cv_MKNOD_CREATES_FIFOS=cross)])
|
||||
if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then
|
||||
AC_DEFINE(MKNOD_CREATES_FIFOS, 1, [Define to 1 if mknod() can create FIFOs.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if mknod creates sockets],rsync_cv_MKNOD_CREATES_SOCKETS,[
|
||||
AC_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
main() { int rc, ec; char *fn = "sock-test";
|
||||
unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn);
|
||||
if (rc) {printf("%d %d\n",rc,ec); return ec;}
|
||||
return 0;}],
|
||||
rsync_cv_MKNOD_CREATES_SOCKETS=yes,rsync_cv_MKNOD_CREATES_SOCKETS=no,rsync_cv_MKNOD_CREATES_SOCKETS=cross)])
|
||||
if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then
|
||||
AC_DEFINE(MKNOD_CREATES_SOCKETS, 1, [Define to 1 if mknod() can create sockets.])
|
||||
fi
|
||||
|
||||
#
|
||||
@@ -659,21 +739,6 @@ 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()
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#define RERR_MALLOC 22 /* error allocating core memory buffers */
|
||||
#define RERR_PARTIAL 23 /* partial transfer */
|
||||
#define RERR_VANISHED 24 /* file(s) vanished on sender side */
|
||||
#define RERR_DEL_LIMIT 25 /* skipped some deletes due to --max-delete */
|
||||
|
||||
#define RERR_TIMEOUT 30 /* timeout in data send/receive */
|
||||
|
||||
|
||||
55
fileio.c
55
fileio.c
@@ -143,56 +143,52 @@ int write_file(int f,char *buf,size_t len)
|
||||
* 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_file(int fd, OFF_T len, int32 read_size,
|
||||
int32 blk_size)
|
||||
{
|
||||
struct map_struct *map;
|
||||
|
||||
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);
|
||||
if (blk_size && (read_size % blk_size))
|
||||
read_size += blk_size - (read_size % blk_size);
|
||||
|
||||
memset(map, 0, sizeof map[0]);
|
||||
map->fd = fd;
|
||||
map->file_size = len;
|
||||
map->def_window_size = map_size;
|
||||
map->def_window_size = read_size;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/* slide the read window in the file */
|
||||
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
||||
{
|
||||
int nread;
|
||||
int32 nread;
|
||||
OFF_T window_start, read_start;
|
||||
int window_size, read_size, read_offset;
|
||||
int32 window_size, read_size, read_offset;
|
||||
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
/* can't go beyond the end of file */
|
||||
if (len > (map->file_size - offset)) {
|
||||
len = map->file_size - offset;
|
||||
if (len < 0) {
|
||||
rprintf(FERROR, "invalid len passed to map_ptr: %ld\n",
|
||||
(long)len);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
/* in most cases the region will already be available */
|
||||
if (offset >= map->p_offset &&
|
||||
offset+len <= map->p_offset+map->p_len) {
|
||||
return (map->p + (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 */
|
||||
window_start = offset;
|
||||
window_size = map->def_window_size;
|
||||
if (window_start + window_size > map->file_size) {
|
||||
if (window_start + window_size > map->file_size)
|
||||
window_size = map->file_size - window_start;
|
||||
}
|
||||
if (offset + len > window_start + window_size) {
|
||||
window_size = (offset+len) - window_start;
|
||||
}
|
||||
if (len > window_size)
|
||||
window_size = len;
|
||||
|
||||
/* make sure we have allocated enough memory for the window */
|
||||
if (window_size > map->p_size) {
|
||||
@@ -202,8 +198,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
map->p_size = window_size;
|
||||
}
|
||||
|
||||
/* now try to avoid re-reading any bytes by reusing any bytes from the previous
|
||||
buffer. */
|
||||
/* Now try to avoid re-reading any bytes by reusing any bytes
|
||||
* from the previous buffer. */
|
||||
if (window_start >= map->p_offset &&
|
||||
window_start < map->p_offset + map->p_len &&
|
||||
window_start + window_size >= map->p_offset + map->p_len) {
|
||||
@@ -218,11 +214,16 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
}
|
||||
|
||||
if (read_size <= 0) {
|
||||
rprintf(FINFO,"Warning: unexpected read size of %d in map_ptr\n", read_size);
|
||||
rprintf(FERROR, "invalid read_size of %ld in map_ptr\n",
|
||||
(long)read_size);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
} else {
|
||||
if (map->p_fd_offset != read_start) {
|
||||
if (do_lseek(map->fd,read_start,SEEK_SET) != read_start) {
|
||||
rprintf(FERROR,"lseek failed in map_ptr\n");
|
||||
OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
|
||||
if (ret != read_start) {
|
||||
rsyserr(FERROR, errno,
|
||||
"lseek returned %.0f, not %.0f",
|
||||
(double)ret, (double)read_start);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
map->p_fd_offset = read_start;
|
||||
@@ -244,7 +245,7 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
1149
generator.c
1149
generator.c
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,15 @@
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
int ret;
|
||||
|
||||
while (--argc > 0) {
|
||||
if (stat(*++argv, &st) < 0) {
|
||||
#ifdef USE_STAT64_FUNCS
|
||||
ret = stat64(*++argv, &st);
|
||||
#else
|
||||
ret = stat(*++argv, &st);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Unable to stat `%s'\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
241
hlink.c
241
hlink.c
@@ -23,12 +23,21 @@
|
||||
extern int dry_run;
|
||||
extern int verbose;
|
||||
extern int make_backups;
|
||||
extern struct file_list *the_file_list;
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
static int hlink_compare(struct file_struct **file1, struct file_struct **file2)
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
|
||||
#define SKIPPED_LINK (-1)
|
||||
#define FINISHED_LINK (-2)
|
||||
|
||||
#define FPTR(i) (the_file_list->files[i])
|
||||
#define LINKED(p1,p2) (FPTR(p1)->F_DEV == FPTR(p2)->F_DEV \
|
||||
&& FPTR(p1)->F_INODE == FPTR(p2)->F_INODE)
|
||||
|
||||
static int hlink_compare(int *int1, int *int2)
|
||||
{
|
||||
struct file_struct *f1 = *file1;
|
||||
struct file_struct *f2 = *file2;
|
||||
struct file_struct *f1 = FPTR(*int1);
|
||||
struct file_struct *f2 = FPTR(*int2);
|
||||
|
||||
if (f1->F_DEV != f2->F_DEV)
|
||||
return (int) (f1->F_DEV > f2->F_DEV ? 1 : -1);
|
||||
@@ -36,54 +45,51 @@ static int hlink_compare(struct file_struct **file1, struct file_struct **file2)
|
||||
if (f1->F_INODE != f2->F_INODE)
|
||||
return (int) (f1->F_INODE > f2->F_INODE ? 1 : -1);
|
||||
|
||||
return file_compare(file1, file2);
|
||||
return f_name_cmp(f1, f2);
|
||||
}
|
||||
|
||||
static struct file_struct **hlink_list;
|
||||
static int *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)
|
||||
static void link_idev_data(void)
|
||||
{
|
||||
struct file_struct *head;
|
||||
int from, to, start;
|
||||
int cur, from, to, start;
|
||||
|
||||
alloc_pool_t hlink_pool;
|
||||
alloc_pool_t idev_pool = flist->hlink_pool;
|
||||
alloc_pool_t idev_pool = the_file_list->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,
|
||||
while (1) {
|
||||
cur = hlink_list[from];
|
||||
if (from == hlink_count-1
|
||||
|| !LINKED(cur, hlink_list[from+1]))
|
||||
break;
|
||||
pool_free(idev_pool, 0, FPTR(cur)->link_u.idev);
|
||||
FPTR(cur)->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++;
|
||||
FPTR(cur)->F_HLINDEX = to;
|
||||
FPTR(cur)->F_NEXT = hlink_list[++from];
|
||||
}
|
||||
pool_free(idev_pool, 0, FPTR(cur)->link_u.idev);
|
||||
if (from > start) {
|
||||
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
|
||||
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
|
||||
int head = hlink_list[start];
|
||||
FPTR(cur)->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;
|
||||
FPTR(head)->flags |= FLAG_HLINK_TOL;
|
||||
FPTR(cur)->F_HLINDEX = to;
|
||||
FPTR(cur)->F_NEXT = head;
|
||||
FPTR(cur)->flags |= FLAG_HLINK_EOL;
|
||||
hlink_list[to++] = head;
|
||||
} else {
|
||||
pool_free(idev_pool, 0, head->link_u.idev);
|
||||
head->link_u.idev = NULL;
|
||||
}
|
||||
} else
|
||||
FPTR(cur)->link_u.links = NULL;
|
||||
}
|
||||
|
||||
if (!to) {
|
||||
@@ -93,33 +99,30 @@ static void link_idev_data(struct file_list *flist)
|
||||
hlink_pool = NULL;
|
||||
} else {
|
||||
hlink_count = to;
|
||||
if (!(hlink_list = realloc_array(hlink_list,
|
||||
struct file_struct *, hlink_count)))
|
||||
hlink_list = realloc_array(hlink_list, int, hlink_count);
|
||||
if (!hlink_list)
|
||||
out_of_memory("init_hard_links");
|
||||
}
|
||||
flist->hlink_pool = hlink_pool;
|
||||
the_file_list->hlink_pool = hlink_pool;
|
||||
pool_destroy(idev_pool);
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_hard_links(struct file_list *flist)
|
||||
void init_hard_links(void)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
#ifdef 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(int, the_file_list->count)))
|
||||
out_of_memory("init_hard_links");
|
||||
|
||||
hlink_count = 0;
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
if (flist->files[i]->link_u.idev)
|
||||
hlink_list[hlink_count++] = flist->files[i];
|
||||
for (i = 0; i < the_file_list->count; i++) {
|
||||
if (FPTR(i)->link_u.idev)
|
||||
hlink_list[hlink_count++] = i;
|
||||
}
|
||||
|
||||
qsort(hlink_list, hlink_count,
|
||||
@@ -129,84 +132,136 @@ void init_hard_links(struct file_list *flist)
|
||||
free(hlink_list);
|
||||
hlink_list = NULL;
|
||||
} else
|
||||
link_idev_data(flist);
|
||||
link_idev_data();
|
||||
#endif
|
||||
}
|
||||
|
||||
int hard_link_check(struct file_struct *file, int skip)
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static int maybe_hard_link(struct file_struct *file, int ndx,
|
||||
char *fname, int statret, STRUCT_STAT *st,
|
||||
char *toname, STRUCT_STAT *to_st,
|
||||
int itemizing, enum logcode code)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
if (!hlink_list || !file->link_u.links)
|
||||
if (statret == 0) {
|
||||
if (st->st_dev == to_st->st_dev
|
||||
&& st->st_ino == to_st->st_ino) {
|
||||
if (itemizing) {
|
||||
itemize(file, ndx, statret, st,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
|
||||
0, "");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (make_backups) {
|
||||
if (!make_backup(fname))
|
||||
return -1;
|
||||
} else if (robust_unlink(fname)) {
|
||||
rsyserr(FERROR, errno, "unlink %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return hard_link_one(file, ndx, fname, statret, st, toname,
|
||||
0, itemizing, code);
|
||||
}
|
||||
#endif
|
||||
|
||||
int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
int statret, STRUCT_STAT *st, int itemizing,
|
||||
enum logcode code, int skip)
|
||||
{
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
int head;
|
||||
if (!file->link_u.links)
|
||||
return 0;
|
||||
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) {
|
||||
head = hlink_list[file->F_HLINDEX] = file->F_NEXT;
|
||||
else
|
||||
head = hlink_list[file->F_HLINDEX];
|
||||
if (ndx != head) {
|
||||
struct file_struct *head_file = FPTR(head);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "\"%s\" is a hard link\n",
|
||||
f_name(file));
|
||||
safe_fname(f_name(file)));
|
||||
}
|
||||
if (head_file->F_HLINDEX == FINISHED_LINK) {
|
||||
STRUCT_STAT st2;
|
||||
char *toname = f_name(head_file);
|
||||
if (link_stat(toname, &st2, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(toname));
|
||||
return -1;
|
||||
}
|
||||
maybe_hard_link(file, ndx, fname, statret, st,
|
||||
toname, &st2, itemizing, code);
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
} else
|
||||
file->F_HLINDEX = SKIPPED_LINK;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
static void hard_link_one(char *hlink1, char *hlink2)
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
int hard_link_one(struct file_struct *file, int ndx, char *fname,
|
||||
int statret, STRUCT_STAT *st, char *toname, int terse,
|
||||
int itemizing, enum logcode code)
|
||||
{
|
||||
if (do_link(hlink1, hlink2)) {
|
||||
if (verbose) {
|
||||
rsyserr(FINFO, errno, "link %s => %s failed",
|
||||
hlink2, hlink1);
|
||||
}
|
||||
if (do_link(toname, fname)) {
|
||||
if (terse) {
|
||||
if (!verbose)
|
||||
return -1;
|
||||
code = FINFO;
|
||||
} else
|
||||
code = FERROR;
|
||||
rsyserr(code, errno, "link %s => %s failed",
|
||||
full_fname(fname), safe_fname(toname));
|
||||
return -1;
|
||||
}
|
||||
else if (verbose)
|
||||
rprintf(FINFO, "%s => %s\n", hlink2, hlink1);
|
||||
|
||||
if (itemizing) {
|
||||
itemize(file, ndx, statret, st,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
|
||||
terse ? "" : toname);
|
||||
}
|
||||
if (code && verbose && !terse) {
|
||||
rprintf(code, "%s => %s\n",
|
||||
safe_fname(fname), safe_fname(toname));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create any hard links in the global hlink_list. They were put
|
||||
* there by running init_hard_links on the filelist.
|
||||
**/
|
||||
void do_hard_links(void)
|
||||
void hard_link_cluster(struct file_struct *file, int master, int itemizing,
|
||||
enum logcode code)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
struct file_struct *file, *first;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
char hlink1[MAXPATHLEN];
|
||||
char *hlink2;
|
||||
STRUCT_STAT st1, st2;
|
||||
int i;
|
||||
int statret, ndx = master;
|
||||
|
||||
if (!hlink_list)
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
if (link_stat(f_name_to(file, hlink1), &st1, 0) < 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
if (!(file->flags & FLAG_HLINK_TOL)) {
|
||||
while (!(file->flags & FLAG_HLINK_EOL)) {
|
||||
ndx = file->F_NEXT;
|
||||
file = FPTR(ndx);
|
||||
}
|
||||
}
|
||||
do {
|
||||
ndx = file->F_NEXT;
|
||||
file = FPTR(ndx);
|
||||
if (file->F_HLINDEX != SKIPPED_LINK)
|
||||
continue;
|
||||
hlink2 = f_name(file);
|
||||
statret = link_stat(hlink2, &st2, 0);
|
||||
maybe_hard_link(file, ndx, hlink2, statret, &st2,
|
||||
hlink1, &st1, itemizing, code);
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
} while (!(file->flags & FLAG_HLINK_EOL));
|
||||
#endif
|
||||
}
|
||||
|
||||
462
io.c
462
io.c
@@ -43,17 +43,24 @@ extern int bwlimit;
|
||||
extern size_t bwlimit_writemax;
|
||||
extern int verbose;
|
||||
extern int io_timeout;
|
||||
extern int allowed_lull;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int eol_nulls;
|
||||
extern int read_batch;
|
||||
extern int csum_length;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
extern char *remote_filesfrom_file;
|
||||
extern int remove_sent_files;
|
||||
extern int preserve_hard_links;
|
||||
extern char *filesfrom_host;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *the_file_list;
|
||||
|
||||
const char phase_unknown[] = "unknown";
|
||||
int select_timeout = SELECT_TIMEOUT;
|
||||
int ignore_timeout = 0;
|
||||
int batch_fd = -1;
|
||||
int batch_gen_fd = -1;
|
||||
|
||||
@@ -73,18 +80,18 @@ int batch_gen_fd = -1;
|
||||
const char *io_write_phase = phase_unknown;
|
||||
const char *io_read_phase = phase_unknown;
|
||||
|
||||
/** Ignore EOF errors while reading a module listing if the remote
|
||||
version is 24 or less. */
|
||||
int kludge_around_eof = False;
|
||||
/* Ignore an EOF error if non-zero. See whine_about_eof(). */
|
||||
int kluge_around_eof = 0;
|
||||
|
||||
int msg_fd_in = -1;
|
||||
int msg_fd_out = -1;
|
||||
int sock_f_in = -1;
|
||||
int sock_f_out = -1;
|
||||
|
||||
static int io_multiplexing_out;
|
||||
static int io_multiplexing_in;
|
||||
static int sock_f_in = -1;
|
||||
static int sock_f_out = -1;
|
||||
static time_t last_io;
|
||||
static time_t last_io_in;
|
||||
static time_t last_io_out;
|
||||
static int no_flush;
|
||||
|
||||
static int write_batch_monitor_in = -1;
|
||||
@@ -96,16 +103,21 @@ static char io_filesfrom_buf[2048];
|
||||
static char *io_filesfrom_bp;
|
||||
static char io_filesfrom_lastchar;
|
||||
static int io_filesfrom_buflen;
|
||||
static size_t contiguous_write_len = 0;
|
||||
static int select_timeout = SELECT_TIMEOUT;
|
||||
|
||||
static void read_loop(int fd, char *buf, size_t len);
|
||||
|
||||
struct redo_list {
|
||||
struct redo_list *next;
|
||||
int num;
|
||||
struct flist_ndx_item {
|
||||
struct flist_ndx_item *next;
|
||||
int ndx;
|
||||
};
|
||||
|
||||
static struct redo_list *redo_list_head;
|
||||
static struct redo_list *redo_list_tail;
|
||||
struct flist_ndx_list {
|
||||
struct flist_ndx_item *head, *tail;
|
||||
};
|
||||
|
||||
static struct flist_ndx_list redo_list, hlink_list;
|
||||
|
||||
struct msg_list {
|
||||
struct msg_list *next;
|
||||
@@ -116,39 +128,57 @@ struct msg_list {
|
||||
static struct msg_list *msg_list_head;
|
||||
static struct msg_list *msg_list_tail;
|
||||
|
||||
static void redo_list_add(int num)
|
||||
static void flist_ndx_push(struct flist_ndx_list *lp, int ndx)
|
||||
{
|
||||
struct redo_list *rl;
|
||||
struct flist_ndx_item *item;
|
||||
|
||||
if (!(rl = new(struct redo_list)))
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
rl->next = NULL;
|
||||
rl->num = num;
|
||||
if (redo_list_tail)
|
||||
redo_list_tail->next = rl;
|
||||
if (!(item = new(struct flist_ndx_item)))
|
||||
out_of_memory("flist_ndx_push");
|
||||
item->next = NULL;
|
||||
item->ndx = ndx;
|
||||
if (lp->tail)
|
||||
lp->tail->next = item;
|
||||
else
|
||||
redo_list_head = rl;
|
||||
redo_list_tail = rl;
|
||||
lp->head = item;
|
||||
lp->tail = item;
|
||||
}
|
||||
|
||||
static int flist_ndx_pop(struct flist_ndx_list *lp)
|
||||
{
|
||||
struct flist_ndx_item *next;
|
||||
int ndx;
|
||||
|
||||
if (!lp->head)
|
||||
return -1;
|
||||
|
||||
ndx = lp->head->ndx;
|
||||
next = lp->head->next;
|
||||
free(lp->head);
|
||||
lp->head = next;
|
||||
if (!next)
|
||||
lp->tail = NULL;
|
||||
|
||||
return ndx;
|
||||
}
|
||||
|
||||
static void check_timeout(void)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
if (!io_timeout)
|
||||
if (!io_timeout || ignore_timeout)
|
||||
return;
|
||||
|
||||
if (!last_io) {
|
||||
last_io = time(NULL);
|
||||
if (!last_io_in) {
|
||||
last_io_in = time(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
if (t - last_io >= io_timeout) {
|
||||
if (t - last_io_in >= io_timeout) {
|
||||
if (!am_server && !am_daemon) {
|
||||
rprintf(FERROR, "io timeout after %d seconds - exiting\n",
|
||||
(int)(t-last_io));
|
||||
rprintf(FERROR, "io timeout after %d seconds -- exiting\n",
|
||||
(int)(t-last_io_in));
|
||||
}
|
||||
exit_cleanup(RERR_TIMEOUT);
|
||||
}
|
||||
@@ -162,17 +192,29 @@ void io_set_sock_fds(int f_in, int f_out)
|
||||
sock_f_out = f_out;
|
||||
}
|
||||
|
||||
/** Setup the fd used to receive MSG_* messages. Only needed when
|
||||
* we're the generator because the sender and receiver both use the
|
||||
* multiplexed I/O setup. */
|
||||
void set_io_timeout(int secs)
|
||||
{
|
||||
io_timeout = secs;
|
||||
|
||||
if (!io_timeout || io_timeout > SELECT_TIMEOUT)
|
||||
select_timeout = SELECT_TIMEOUT;
|
||||
else
|
||||
select_timeout = io_timeout;
|
||||
|
||||
allowed_lull = read_batch ? 0 : (io_timeout + 1) / 2;
|
||||
}
|
||||
|
||||
/* Setup the fd used to receive MSG_* messages. Only needed during the
|
||||
* early stages of being a local sender (up through the sending of the
|
||||
* file list) or when we're the generator (to fetch the messages from
|
||||
* the receiver). */
|
||||
void set_msg_fd_in(int fd)
|
||||
{
|
||||
msg_fd_in = fd;
|
||||
}
|
||||
|
||||
/** Setup the fd used to send our MSG_* messages. Only needed when
|
||||
* we're the receiver because the generator and the sender both use
|
||||
* the multiplexed I/O setup. */
|
||||
/* Setup the fd used to send our MSG_* messages. Only needed when
|
||||
* we're the receiver (to send our messages to the generator). */
|
||||
void set_msg_fd_out(int fd)
|
||||
{
|
||||
msg_fd_out = fd;
|
||||
@@ -185,10 +227,10 @@ static void msg_list_add(int code, char *buf, int len)
|
||||
struct msg_list *ml;
|
||||
|
||||
if (!(ml = new(struct msg_list)))
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
out_of_memory("msg_list_add");
|
||||
ml->next = NULL;
|
||||
if (!(ml->buf = new_array(char, len+4)))
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
out_of_memory("msg_list_add");
|
||||
SIVAL(ml->buf, 0, ((code+MPLEX_BASE)<<24) | len);
|
||||
memcpy(ml->buf+4, buf, len);
|
||||
ml->len = len+4;
|
||||
@@ -201,12 +243,18 @@ static void msg_list_add(int code, char *buf, int len)
|
||||
|
||||
void send_msg(enum msgcode code, char *buf, int len)
|
||||
{
|
||||
if (msg_fd_out < 0) {
|
||||
io_multiplex_write(code, buf, len);
|
||||
return;
|
||||
}
|
||||
msg_list_add(code, buf, len);
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
}
|
||||
|
||||
/** Read a message from the MSG_* fd and dispatch it. This is only
|
||||
* called by the generator. */
|
||||
/* Read a message from the MSG_* fd and handle it. This is called either
|
||||
* during the early stages of being a local sender (up through the sending
|
||||
* of the file list) or when we're the generator (to fetch the messages
|
||||
* from the receiver). */
|
||||
static void read_msg_fd(void)
|
||||
{
|
||||
char buf[2048];
|
||||
@@ -215,7 +263,7 @@ static void read_msg_fd(void)
|
||||
int tag, len;
|
||||
|
||||
/* Temporarily disable msg_fd_in. This is needed to avoid looping back
|
||||
* to this routine from read_timeout() and writefd_unbuffered(). */
|
||||
* to this routine from writefd_unbuffered(). */
|
||||
msg_fd_in = -1;
|
||||
|
||||
read_loop(fd, buf, 4);
|
||||
@@ -226,19 +274,38 @@ static void read_msg_fd(void)
|
||||
|
||||
switch (tag) {
|
||||
case MSG_DONE:
|
||||
if (len != 0) {
|
||||
if (len != 0 || !am_generator) {
|
||||
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
redo_list_add(-1);
|
||||
flist_ndx_push(&redo_list, -1);
|
||||
break;
|
||||
case MSG_REDO:
|
||||
if (len != 4) {
|
||||
if (len != 4 || !am_generator) {
|
||||
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, buf, 4);
|
||||
redo_list_add(IVAL(buf,0));
|
||||
flist_ndx_push(&redo_list, IVAL(buf,0));
|
||||
break;
|
||||
case MSG_DELETED:
|
||||
if (len >= (int)sizeof buf || !am_generator) {
|
||||
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, buf, len);
|
||||
io_multiplex_write(MSG_DELETED, buf, len);
|
||||
break;
|
||||
case MSG_SUCCESS:
|
||||
if (len != 4 || !am_generator) {
|
||||
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, buf, len);
|
||||
if (remove_sent_files)
|
||||
io_multiplex_write(MSG_SUCCESS, buf, len);
|
||||
if (preserve_hard_links)
|
||||
flist_ndx_push(&hlink_list, IVAL(buf,0));
|
||||
break;
|
||||
case MSG_INFO:
|
||||
case MSG_ERROR:
|
||||
@@ -300,22 +367,22 @@ int msg_list_push(int flush_it_all)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_redo_num(void)
|
||||
int get_redo_num(int itemizing, enum logcode code)
|
||||
{
|
||||
struct redo_list *next;
|
||||
int num;
|
||||
|
||||
while (!redo_list_head)
|
||||
while (1) {
|
||||
if (hlink_list.head)
|
||||
check_for_finished_hlinks(itemizing, code);
|
||||
if (redo_list.head)
|
||||
break;
|
||||
read_msg_fd();
|
||||
}
|
||||
|
||||
num = redo_list_head->num;
|
||||
next = redo_list_head->next;
|
||||
free(redo_list_head);
|
||||
redo_list_head = next;
|
||||
if (!next)
|
||||
redo_list_tail = NULL;
|
||||
return flist_ndx_pop(&redo_list);
|
||||
}
|
||||
|
||||
return num;
|
||||
int get_hlink_num(void)
|
||||
{
|
||||
return flist_ndx_pop(&hlink_list);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,20 +404,28 @@ void io_set_filesfrom_fds(int f_in, int f_out)
|
||||
io_filesfrom_buflen = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's almost always an error to get an EOF when we're trying to read
|
||||
* from the network, because the protocol is self-terminating.
|
||||
/* It's almost always an error to get an EOF when we're trying to read from the
|
||||
* network, because the protocol is (for the most part) self-terminating.
|
||||
*
|
||||
* However, there is one unfortunate cases where it is not, which is
|
||||
* rsync <2.4.6 sending a list of modules on a server, since the list
|
||||
* is terminated by closing the socket. So, for the section of the
|
||||
* program where that is a problem (start_socket_client),
|
||||
* kludge_around_eof is True and we just exit.
|
||||
*/
|
||||
* There is one case for the receiver when it is at the end of the transfer
|
||||
* (hanging around reading any keep-alive packets that might come its way): if
|
||||
* the sender dies before the generator's kill-signal comes through, we can end
|
||||
* up here needing to loop until the kill-signal arrives. In this situation,
|
||||
* kluge_around_eof will be < 0.
|
||||
*
|
||||
* There is another case for older protocol versions (< 24) where the module
|
||||
* listing was not terminated, so we must ignore an EOF error in that case and
|
||||
* exit. In this situation, kluge_around_eof will be > 0. */
|
||||
static void whine_about_eof(int fd)
|
||||
{
|
||||
if (kludge_around_eof && fd == sock_f_in)
|
||||
exit_cleanup(0);
|
||||
if (kluge_around_eof && fd == sock_f_in) {
|
||||
int i;
|
||||
if (kluge_around_eof > 0)
|
||||
exit_cleanup(0);
|
||||
/* If we're still here after 10 seconds, exit with an error. */
|
||||
for (i = 10*1000/20; i--; )
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed "
|
||||
"(%.0f bytes received so far) [%s]\n",
|
||||
@@ -387,11 +462,7 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
FD_ZERO(&r_fds);
|
||||
FD_ZERO(&w_fds);
|
||||
FD_SET(fd, &r_fds);
|
||||
if (msg_fd_in >= 0) {
|
||||
FD_SET(msg_fd_in, &r_fds);
|
||||
if (msg_fd_in > maxfd)
|
||||
maxfd = msg_fd_in;
|
||||
} else if (msg_list_head) {
|
||||
if (msg_list_head) {
|
||||
FD_SET(msg_fd_out, &w_fds);
|
||||
if (msg_fd_out > maxfd)
|
||||
maxfd = msg_fd_out;
|
||||
@@ -428,9 +499,7 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
|
||||
read_msg_fd();
|
||||
else if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds))
|
||||
if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds))
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
|
||||
if (io_filesfrom_f_out >= 0) {
|
||||
@@ -519,8 +588,8 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
len -= n;
|
||||
ret += n;
|
||||
|
||||
if (io_timeout && fd == sock_f_in)
|
||||
last_io = time(NULL);
|
||||
if (fd == sock_f_in && io_timeout)
|
||||
last_io_in = time(NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -534,7 +603,7 @@ int read_filesfrom_line(int fd, char *fname)
|
||||
{
|
||||
char ch, *s, *eob = fname + MAXPATHLEN - 1;
|
||||
int cnt;
|
||||
int reading_remotely = remote_filesfrom_file != NULL;
|
||||
int reading_remotely = filesfrom_host != NULL;
|
||||
int nulls = eol_nulls || reading_remotely;
|
||||
|
||||
start:
|
||||
@@ -610,6 +679,28 @@ void io_end_buffering(void)
|
||||
}
|
||||
|
||||
|
||||
void maybe_flush_socket(void)
|
||||
{
|
||||
if (iobuf_out && iobuf_out_cnt && time(NULL) - last_io_out >= 5)
|
||||
io_flush(NORMAL_FLUSH);
|
||||
}
|
||||
|
||||
|
||||
void maybe_send_keepalive(void)
|
||||
{
|
||||
if (time(NULL) - last_io_out >= allowed_lull) {
|
||||
if (!iobuf_out || !iobuf_out_cnt) {
|
||||
if (protocol_version < 29)
|
||||
return; /* there's nothing we can do */
|
||||
write_int(sock_f_out, the_file_list->count);
|
||||
write_shortint(sock_f_out, ITEM_IS_NEW);
|
||||
}
|
||||
if (iobuf_out)
|
||||
io_flush(NORMAL_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Continue trying to read len bytes - don't return until len has been
|
||||
* read.
|
||||
@@ -635,8 +726,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
{
|
||||
static size_t remaining;
|
||||
static size_t iobuf_in_ndx;
|
||||
size_t msg_bytes;
|
||||
int tag, ret = 0;
|
||||
char line[1024];
|
||||
#if MAXPATHLEN < 4096
|
||||
char line[4096+1024];
|
||||
#else
|
||||
char line[MAXPATHLEN+1024];
|
||||
#endif
|
||||
|
||||
if (!iobuf_in || fd != sock_f_in)
|
||||
return read_timeout(fd, buf, len);
|
||||
@@ -659,33 +755,56 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
read_loop(fd, line, 4);
|
||||
tag = IVAL(line, 0);
|
||||
|
||||
remaining = tag & 0xFFFFFF;
|
||||
msg_bytes = tag & 0xFFFFFF;
|
||||
tag = (tag >> 24) - MPLEX_BASE;
|
||||
|
||||
switch (tag) {
|
||||
case MSG_DATA:
|
||||
if (remaining > iobuf_in_siz) {
|
||||
if (msg_bytes > iobuf_in_siz) {
|
||||
if (!(iobuf_in = realloc_array(iobuf_in, char,
|
||||
remaining)))
|
||||
msg_bytes)))
|
||||
out_of_memory("readfd_unbuffered");
|
||||
iobuf_in_siz = remaining;
|
||||
iobuf_in_siz = msg_bytes;
|
||||
}
|
||||
read_loop(fd, iobuf_in, remaining);
|
||||
read_loop(fd, iobuf_in, msg_bytes);
|
||||
remaining = msg_bytes;
|
||||
iobuf_in_ndx = 0;
|
||||
break;
|
||||
case MSG_DELETED:
|
||||
if (msg_bytes >= sizeof line)
|
||||
goto overflow;
|
||||
read_loop(fd, line, msg_bytes);
|
||||
line[msg_bytes] = '\0';
|
||||
/* A directory name was sent with the trailing null */
|
||||
if (msg_bytes > 0 && !line[msg_bytes-1])
|
||||
log_delete(line, S_IFDIR);
|
||||
else
|
||||
log_delete(line, S_IFREG);
|
||||
break;
|
||||
case MSG_SUCCESS:
|
||||
if (msg_bytes != 4) {
|
||||
rprintf(FERROR, "invalid multi-message %d:%ld [%s]\n",
|
||||
tag, (long)msg_bytes, who_am_i());
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, line, msg_bytes);
|
||||
successful_send(IVAL(line, 0));
|
||||
break;
|
||||
case MSG_INFO:
|
||||
case MSG_ERROR:
|
||||
if (remaining >= sizeof line) {
|
||||
rprintf(FERROR, "multiplexing overflow %d:%ld\n\n",
|
||||
tag, (long)remaining);
|
||||
if (msg_bytes >= sizeof line) {
|
||||
overflow:
|
||||
rprintf(FERROR,
|
||||
"multiplexing overflow %d:%ld [%s]\n",
|
||||
tag, (long)msg_bytes, who_am_i());
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, line, remaining);
|
||||
rwrite((enum logcode)tag, line, remaining);
|
||||
remaining = 0;
|
||||
read_loop(fd, line, msg_bytes);
|
||||
rwrite((enum logcode)tag, line, msg_bytes);
|
||||
break;
|
||||
default:
|
||||
rprintf(FERROR, "unexpected tag %d\n", tag);
|
||||
rprintf(FERROR, "unexpected tag %d [%s]\n",
|
||||
tag, who_am_i());
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
}
|
||||
@@ -723,6 +842,14 @@ static void readfd(int fd, char *buffer, size_t N)
|
||||
}
|
||||
|
||||
|
||||
int read_shortint(int f)
|
||||
{
|
||||
uchar b[2];
|
||||
readfd(f, (char *)b, 2);
|
||||
return (b[1] << 8) + b[0];
|
||||
}
|
||||
|
||||
|
||||
int32 read_int(int f)
|
||||
{
|
||||
char b[4];
|
||||
@@ -744,14 +871,13 @@ int64 read_longint(int f)
|
||||
if ((int32)ret != (int32)0xffffffff)
|
||||
return ret;
|
||||
|
||||
#ifdef INT64_IS_OFF_T
|
||||
if (sizeof (int64) < 8) {
|
||||
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
#endif
|
||||
#if SIZEOF_INT64 < 8
|
||||
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
#else
|
||||
readfd(f,b,8);
|
||||
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -764,16 +890,77 @@ void read_buf(int f,char *buf,size_t len)
|
||||
void read_sbuf(int f,char *buf,size_t len)
|
||||
{
|
||||
readfd(f, buf, len);
|
||||
buf[len] = 0;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
unsigned char read_byte(int f)
|
||||
uchar read_byte(int f)
|
||||
{
|
||||
unsigned char c;
|
||||
uchar c;
|
||||
readfd(f, (char *)&c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
int read_vstring(int f, char *buf, int bufsize)
|
||||
{
|
||||
int len = read_byte(f);
|
||||
|
||||
if (len & 0x80)
|
||||
len = (len & ~0x80) * 0x100 + read_byte(f);
|
||||
|
||||
if (len >= bufsize) {
|
||||
rprintf(FERROR, "over-long vstring received (%d > %d)\n",
|
||||
len, bufsize - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len)
|
||||
readfd(f, buf, len);
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Populate a sum_struct with values from the socket. This is
|
||||
* called by both the sender and the receiver. */
|
||||
void read_sum_head(int f, struct sum_struct *sum)
|
||||
{
|
||||
sum->count = read_int(f);
|
||||
sum->blength = read_int(f);
|
||||
if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) {
|
||||
rprintf(FERROR, "Invalid block length %ld [%s]\n",
|
||||
(long)sum->blength, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f);
|
||||
if (sum->s2length < 0 || sum->s2length > MD4_SUM_LENGTH) {
|
||||
rprintf(FERROR, "Invalid checksum length %d [%s]\n",
|
||||
sum->s2length, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
sum->remainder = read_int(f);
|
||||
if (sum->remainder < 0 || sum->remainder > sum->blength) {
|
||||
rprintf(FERROR, "Invalid remainder length %ld [%s]\n",
|
||||
(long)sum->remainder, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the values from a sum_struct over the socket. Set sum to
|
||||
* NULL if there are no checksums to send. This is called by both
|
||||
* the generator and the sender. */
|
||||
void write_sum_head(int f, struct sum_struct *sum)
|
||||
{
|
||||
static struct sum_struct null_sum;
|
||||
|
||||
if (sum == NULL)
|
||||
sum = &null_sum;
|
||||
|
||||
write_int(f, sum->count);
|
||||
write_int(f, sum->blength);
|
||||
if (protocol_version >= 27)
|
||||
write_int(f, sum->s2length);
|
||||
write_int(f, sum->remainder);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sleep after writing to limit I/O bandwidth usage.
|
||||
@@ -832,8 +1019,8 @@ static void sleep_for_bwlimit(int bytes_written)
|
||||
|
||||
|
||||
/* Write len bytes to the file descriptor fd, looping as necessary to get
|
||||
* the job done and also (in the generator) reading any data on msg_fd_in
|
||||
* (to avoid deadlock).
|
||||
* the job done and also (in certain circumstnces) reading any data on
|
||||
* msg_fd_in to avoid deadlock.
|
||||
*
|
||||
* This function underlies the multiplexing system. The body of the
|
||||
* application never calls this function directly. */
|
||||
@@ -841,7 +1028,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
{
|
||||
size_t n, total = 0;
|
||||
fd_set w_fds, r_fds;
|
||||
int maxfd, count, ret;
|
||||
int maxfd, count, ret, using_r_fds;
|
||||
struct timeval tv;
|
||||
|
||||
no_flush++;
|
||||
@@ -851,18 +1038,20 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
FD_SET(fd,&w_fds);
|
||||
maxfd = fd;
|
||||
|
||||
if (msg_fd_in >= 0) {
|
||||
if (msg_fd_in >= 0 && len-total >= contiguous_write_len) {
|
||||
FD_ZERO(&r_fds);
|
||||
FD_SET(msg_fd_in,&r_fds);
|
||||
if (msg_fd_in > maxfd)
|
||||
maxfd = msg_fd_in;
|
||||
}
|
||||
using_r_fds = 1;
|
||||
} else
|
||||
using_r_fds = 0;
|
||||
|
||||
tv.tv_sec = select_timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
errno = 0;
|
||||
count = select(maxfd + 1, msg_fd_in >= 0 ? &r_fds : NULL,
|
||||
count = select(maxfd + 1, using_r_fds ? &r_fds : NULL,
|
||||
&w_fds, NULL, &tv);
|
||||
|
||||
if (count <= 0) {
|
||||
@@ -872,7 +1061,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
|
||||
if (using_r_fds && FD_ISSET(msg_fd_in, &r_fds))
|
||||
read_msg_fd();
|
||||
|
||||
if (!FD_ISSET(fd, &w_fds))
|
||||
@@ -902,7 +1091,8 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
/* If the other side is sending us error messages, try
|
||||
* to grab any messages they sent before they died. */
|
||||
while (fd == sock_f_out && io_multiplexing_in) {
|
||||
io_timeout = 30;
|
||||
set_io_timeout(30);
|
||||
ignore_timeout = 0;
|
||||
readfd_unbuffered(sock_f_in, io_filesfrom_buf,
|
||||
sizeof io_filesfrom_buf);
|
||||
}
|
||||
@@ -912,8 +1102,8 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
total += ret;
|
||||
|
||||
if (fd == sock_f_out) {
|
||||
if (io_timeout)
|
||||
last_io = time(NULL);
|
||||
if (io_timeout || am_generator)
|
||||
last_io_out = time(NULL);
|
||||
sleep_for_bwlimit(ret);
|
||||
}
|
||||
}
|
||||
@@ -933,6 +1123,13 @@ static void mplex_write(enum msgcode code, char *buf, size_t len)
|
||||
|
||||
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
|
||||
|
||||
/* When the generator reads messages from the msg_fd_in pipe, it can
|
||||
* cause output to occur down the socket. Setting contiguous_write_len
|
||||
* prevents the reading of msg_fd_in once we actually start to write
|
||||
* this sequence of data (though we might read it before the start). */
|
||||
if (am_generator && msg_fd_in >= 0)
|
||||
contiguous_write_len = len + 4;
|
||||
|
||||
if (n > sizeof buffer - 4)
|
||||
n = sizeof buffer - 4;
|
||||
|
||||
@@ -944,6 +1141,9 @@ static void mplex_write(enum msgcode code, char *buf, size_t len)
|
||||
|
||||
if (len)
|
||||
writefd_unbuffered(sock_f_out, buf, len);
|
||||
|
||||
if (am_generator && msg_fd_in >= 0)
|
||||
contiguous_write_len = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -997,6 +1197,15 @@ static void writefd(int fd,char *buf,size_t len)
|
||||
}
|
||||
|
||||
|
||||
void write_shortint(int f, int x)
|
||||
{
|
||||
uchar b[2];
|
||||
b[0] = x;
|
||||
b[1] = x >> 8;
|
||||
writefd(f, (char *)b, 2);
|
||||
}
|
||||
|
||||
|
||||
void write_int(int f,int32 x)
|
||||
{
|
||||
char b[4];
|
||||
@@ -1026,18 +1235,16 @@ void write_longint(int f, int64 x)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef INT64_IS_OFF_T
|
||||
if (sizeof (int64) < 8) {
|
||||
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SIZEOF_INT64 < 8
|
||||
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
#else
|
||||
write_int(f, (int32)0xFFFFFFFF);
|
||||
SIVAL(b,0,(x&0xFFFFFFFF));
|
||||
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
|
||||
|
||||
writefd(f,b,8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void write_buf(int f,char *buf,size_t len)
|
||||
@@ -1051,11 +1258,30 @@ void write_sbuf(int f, char *buf)
|
||||
writefd(f, buf, strlen(buf));
|
||||
}
|
||||
|
||||
void write_byte(int f,unsigned char c)
|
||||
void write_byte(int f, uchar c)
|
||||
{
|
||||
writefd(f, (char *)&c, 1);
|
||||
}
|
||||
|
||||
void write_vstring(int f, char *str, int len)
|
||||
{
|
||||
uchar lenbuf[3], *lb = lenbuf;
|
||||
|
||||
if (len > 0x7F) {
|
||||
if (len > 0x7FFF) {
|
||||
rprintf(FERROR,
|
||||
"attempting to send over-long vstring (%d > %d)\n",
|
||||
len, 0x7FFF);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
*lb++ = len / 0x100 + 0x80;
|
||||
}
|
||||
*lb = len;
|
||||
|
||||
writefd(f, (char*)lenbuf, lb - lenbuf + 1);
|
||||
if (len)
|
||||
writefd(f, str, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
{
|
||||
unsigned char *p = (unsigned char *)&ip.s_addr;
|
||||
static char buf[18];
|
||||
#if WORDS_BIGENDIAN
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
snprintf(buf, 18, "%d.%d.%d.%d",
|
||||
(int)p[0], (int)p[1], (int)p[2], (int)p[3]);
|
||||
#else
|
||||
@@ -196,7 +196,7 @@
|
||||
/* some systems don't take the 2nd argument */
|
||||
int sys_gettimeofday(struct timeval *tv)
|
||||
{
|
||||
#if HAVE_GETTIMEOFDAY_TZ
|
||||
#ifdef HAVE_GETTIMEOFDAY_TZ
|
||||
return gettimeofday(tv, NULL);
|
||||
#else
|
||||
return gettimeofday(tv);
|
||||
|
||||
10
lib/mdfour.c
10
lib/mdfour.c
@@ -206,9 +206,11 @@ void mdfour(unsigned char *out, unsigned char *in, int n)
|
||||
}
|
||||
|
||||
#ifdef TEST_MDFOUR
|
||||
int protocol_version = 28;
|
||||
|
||||
static void file_checksum1(char *fname)
|
||||
{
|
||||
int fd, i;
|
||||
int fd, i, was_multiple_of_64 = 1;
|
||||
struct mdfour md;
|
||||
unsigned char buf[64*1024], sum[16];
|
||||
|
||||
@@ -222,9 +224,13 @@ static void file_checksum1(char *fname)
|
||||
|
||||
while (1) {
|
||||
int n = read(fd, buf, sizeof(buf));
|
||||
if (n <= 0) break;
|
||||
if (n <= 0)
|
||||
break;
|
||||
was_multiple_of_64 = !(n % 64);
|
||||
mdfour_update(&md, buf, n);
|
||||
}
|
||||
if (was_multiple_of_64 && protocol_version >= 27)
|
||||
mdfour_update(&md, buf, 0);
|
||||
|
||||
close(fd);
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ struct alloc_pool
|
||||
/* 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 */
|
||||
int64 n_allocated; /* calls to alloc */
|
||||
int64 n_freed; /* calls to free */
|
||||
int64 b_allocated; /* cum. bytes allocated */
|
||||
int64 b_freed; /* cum. bytes freed */
|
||||
};
|
||||
|
||||
struct pool_extent
|
||||
@@ -34,7 +34,7 @@ struct pool_extent
|
||||
|
||||
struct align_test {
|
||||
void *foo;
|
||||
uint64 bar;
|
||||
int64 bar;
|
||||
};
|
||||
|
||||
#define MINALIGN offsetof(struct align_test, bar)
|
||||
|
||||
209
lib/snprintf.c
209
lib/snprintf.c
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
* NOTE: If you change this file, please merge it into rsync, samba, etc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell (papowell@astart.com)
|
||||
@@ -53,14 +57,57 @@
|
||||
* got rid of fcvt code (twas buggy and made testing harder)
|
||||
* added C99 semantics
|
||||
*
|
||||
* Paul Green (paulg@samba.org) April 9, 2003
|
||||
* fixed handling of %f when converting fractions with leading zeros.
|
||||
* (e.g., 0.025).
|
||||
* date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0
|
||||
* actually print args for %g and %e
|
||||
*
|
||||
* date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0
|
||||
* Since includes.h isn't included here, VA_COPY has to be defined here. I don't
|
||||
* see any include file that is guaranteed to be here, so I'm defining it
|
||||
* locally. Fixes AIX and Solaris builds.
|
||||
*
|
||||
* date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13
|
||||
* put the ifdef for HAVE_VA_COPY in one place rather than in lots of
|
||||
* functions
|
||||
*
|
||||
* date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4
|
||||
* Fix usage of va_list passed as an arg. Use __va_copy before using it
|
||||
* when it exists.
|
||||
*
|
||||
* date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14
|
||||
* Fix incorrect zpadlen handling in fmtfp.
|
||||
* Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
|
||||
* few mods to make it easier to compile the tests.
|
||||
* addedd the "Ollie" test to the floating point ones.
|
||||
*
|
||||
* Martin Pool (mbp@samba.org) April 2003
|
||||
* Remove NO_CONFIG_H so that the test case can be built within a source
|
||||
* tree with less trouble.
|
||||
* Remove unnecessary SAFE_FREE() definition.
|
||||
*
|
||||
* Martin Pool (mbp@samba.org) May 2003
|
||||
* Put in a prototype for dummy_snprintf() to quiet compiler warnings.
|
||||
*
|
||||
* Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
|
||||
* if the C library has some snprintf functions already.
|
||||
**************************************************************/
|
||||
|
||||
#ifndef NO_CONFIG_H /* for some tests */
|
||||
#ifndef NO_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#else
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifdef TEST_SNPRINTF /* need math library headers for testing */
|
||||
|
||||
/* In test mode, we pretend that this system doesn't have any snprintf
|
||||
* functions, regardless of what config.h says. */
|
||||
# undef HAVE_SNPRINTF
|
||||
# undef HAVE_VSNPRINTF
|
||||
# undef HAVE_C99_VSNPRINTF
|
||||
# undef HAVE_ASPRINTF
|
||||
# undef HAVE_VASPRINTF
|
||||
# include <math.h>
|
||||
#endif /* TEST_SNPRINTF */
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
@@ -82,8 +129,9 @@
|
||||
/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
|
||||
#include <stdio.h>
|
||||
/* make the compiler happy with an empty file */
|
||||
void dummy_snprintf(void);
|
||||
void dummy_snprintf(void) {}
|
||||
#else
|
||||
#endif /* HAVE_SNPRINTF, etc */
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#define LDOUBLE long double
|
||||
@@ -91,21 +139,22 @@
|
||||
#define LDOUBLE double
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
#if SIZEOF_LONG_LONG
|
||||
#define LLONG long long
|
||||
#else
|
||||
#define LLONG long
|
||||
#endif
|
||||
|
||||
static size_t dopr(char *buffer, size_t maxlen, const char *format,
|
||||
va_list args);
|
||||
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max);
|
||||
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
|
||||
long value, int base, int min, int max, int flags);
|
||||
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
|
||||
LDOUBLE fvalue, int min, int max, int flags);
|
||||
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
||||
#ifndef VA_COPY
|
||||
#ifdef HAVE_VA_COPY
|
||||
#define VA_COPY(dest, src) va_copy(dest, src)
|
||||
#else
|
||||
#ifdef HAVE___VA_COPY
|
||||
#define VA_COPY(dest, src) __va_copy(dest, src)
|
||||
#else
|
||||
#define VA_COPY(dest, src) (dest) = (src)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dopr(): poor man's version of doprintf
|
||||
@@ -141,7 +190,20 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
||||
#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
|
||||
#endif
|
||||
|
||||
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
/* yes this really must be a ||. Don't muck with this (tridge) */
|
||||
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
|
||||
|
||||
static size_t dopr(char *buffer, size_t maxlen, const char *format,
|
||||
va_list args_in);
|
||||
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max);
|
||||
static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
|
||||
long value, int base, int min, int max, int flags);
|
||||
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
|
||||
LDOUBLE fvalue, int min, int max, int flags);
|
||||
static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
||||
|
||||
static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
|
||||
{
|
||||
char ch;
|
||||
LLONG value;
|
||||
@@ -153,6 +215,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
|
||||
int flags;
|
||||
int cflags;
|
||||
size_t currlen;
|
||||
va_list args;
|
||||
|
||||
VA_COPY(args, args_in);
|
||||
|
||||
state = DP_S_DEFAULT;
|
||||
currlen = flags = cflags = min = 0;
|
||||
@@ -322,6 +387,7 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
|
||||
break;
|
||||
case 'G':
|
||||
flags |= DP_F_UP;
|
||||
@@ -330,12 +396,14 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
|
||||
break;
|
||||
case 'c':
|
||||
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
|
||||
break;
|
||||
case 's':
|
||||
strvalue = va_arg (args, char *);
|
||||
if (!strvalue) strvalue = "(NULL)";
|
||||
if (max == -1) {
|
||||
max = strlen(strvalue);
|
||||
}
|
||||
@@ -564,28 +632,26 @@ static double my_modf(double x0, double *iptr)
|
||||
|
||||
for (i=0;i<100;i++) {
|
||||
l = (long)x;
|
||||
if (l <= (x+1) && l >= (x-1)) break;
|
||||
if (l <= (x+1) && l >= (x-1)) {
|
||||
if (i != 0) {
|
||||
double i2;
|
||||
double ret;
|
||||
|
||||
ret = my_modf(x0-l*f, &i2);
|
||||
(*iptr) = l*f + i2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
(*iptr) = l;
|
||||
return x - (*iptr);
|
||||
}
|
||||
x *= 0.1;
|
||||
f *= 10.0;
|
||||
}
|
||||
|
||||
if (i == 100) {
|
||||
/* yikes! the number is beyond what we can handle. What do we do? */
|
||||
(*iptr) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
double i2;
|
||||
double ret;
|
||||
|
||||
ret = my_modf(x0-l*f, &i2);
|
||||
(*iptr) = l*f + i2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
(*iptr) = l;
|
||||
return x - (*iptr);
|
||||
/* yikes! the number is beyond what we can handle. What do we do? */
|
||||
(*iptr) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -601,7 +667,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
int padlen = 0; /* amount to pad */
|
||||
int zpadlen = 0;
|
||||
int caps = 0;
|
||||
int index;
|
||||
int idx;
|
||||
double intpart;
|
||||
double fracpart;
|
||||
double temp;
|
||||
@@ -658,14 +724,13 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
|
||||
/* Convert integer part */
|
||||
do {
|
||||
temp = intpart;
|
||||
my_modf(intpart*0.1, &intpart);
|
||||
temp = temp*0.1;
|
||||
index = (int) ((temp -intpart +0.05)* 10.0);
|
||||
/* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
|
||||
/* printf ("%llf, %f, %x\n", temp, intpart, index); */
|
||||
temp = intpart*0.1;
|
||||
my_modf(temp, &intpart);
|
||||
idx = (int) ((temp -intpart +0.05)* 10.0);
|
||||
/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
|
||||
/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
|
||||
iconvert[iplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
|
||||
} while (intpart && (iplace < 311));
|
||||
if (iplace == 311) iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
@@ -674,14 +739,13 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
if (fracpart)
|
||||
{
|
||||
do {
|
||||
temp = fracpart;
|
||||
my_modf(fracpart*0.1, &fracpart);
|
||||
temp = temp*0.1;
|
||||
index = (int) ((temp -fracpart +0.05)* 10.0);
|
||||
/* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
|
||||
/* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
|
||||
temp = fracpart*0.1;
|
||||
my_modf(temp, &fracpart);
|
||||
idx = (int) ((temp -fracpart +0.05)* 10.0);
|
||||
/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
|
||||
/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
|
||||
fconvert[fplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[index];
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
|
||||
} while(fracpart && (fplace < 311));
|
||||
if (fplace == 311) fplace--;
|
||||
}
|
||||
@@ -729,14 +793,14 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
dopr_outch (buffer, currlen, maxlen, '.');
|
||||
|
||||
while (zpadlen > 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
|
||||
while (fplace > 0)
|
||||
dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
|
||||
}
|
||||
|
||||
|
||||
while (padlen < 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
@@ -751,17 +815,21 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
(*currlen)++;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
|
||||
#define vsnprintf rsync_vsnprintf
|
||||
int vsnprintf(char *str, size_t count, const char *fmt, va_list args)
|
||||
int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
|
||||
{
|
||||
return dopr(str, count, fmt, args);
|
||||
}
|
||||
#define vsnprintf rsync_vsnprintf
|
||||
#endif
|
||||
|
||||
/* yes this really must be a ||. Don't muck with this (tridge)
|
||||
*
|
||||
* The logic for these two is that we need our own definition if the
|
||||
* OS *either* has no definition of *sprintf, or if it does have one
|
||||
* that doesn't work properly according to the autoconf test.
|
||||
*/
|
||||
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
|
||||
#define snprintf rsync_snprintf
|
||||
int snprintf(char *str,size_t count,const char *fmt,...)
|
||||
int rsync_snprintf(char *str,size_t count,const char *fmt,...)
|
||||
{
|
||||
size_t ret;
|
||||
va_list ap;
|
||||
@@ -771,6 +839,7 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
#define snprintf rsync_snprintf
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -779,13 +848,19 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
int vasprintf(char **ptr, const char *format, va_list ap)
|
||||
{
|
||||
int ret;
|
||||
va_list ap2;
|
||||
|
||||
VA_COPY(ap2, ap);
|
||||
|
||||
ret = vsnprintf(NULL, 0, format, ap);
|
||||
ret = vsnprintf(NULL, 0, format, ap2);
|
||||
if (ret <= 0) return ret;
|
||||
|
||||
(*ptr) = (char *)malloc(ret+1);
|
||||
if (!*ptr) return -1;
|
||||
ret = vsnprintf(*ptr, ret+1, format, ap);
|
||||
|
||||
VA_COPY(ap2, ap);
|
||||
|
||||
ret = vsnprintf(*ptr, ret+1, format, ap2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -798,6 +873,7 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
*ptr = NULL;
|
||||
va_start(ap, format);
|
||||
ret = vasprintf(ptr, format, ap);
|
||||
va_end(ap);
|
||||
@@ -832,8 +908,9 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
"-16.16f",
|
||||
NULL
|
||||
};
|
||||
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
|
||||
0.9996, 1.996, 4.136, 0};
|
||||
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
|
||||
0.9996, 1.996, 4.136, 5.030201, 0.00205,
|
||||
/* END LIST */ 0};
|
||||
char *int_fmt[] = {
|
||||
"%-1.5d",
|
||||
"%1.5d",
|
||||
@@ -928,8 +1005,10 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
{
|
||||
double v0 = 0.12345678901234567890123456789012345678901;
|
||||
for (x=0; x<100; x++) {
|
||||
snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x));
|
||||
sprintf(buf2, "%1.1f", v0*pow(10, x));
|
||||
double p = pow(10, x);
|
||||
double r = v0*p;
|
||||
snprintf(buf1, sizeof(buf1), "%1.1f", r);
|
||||
sprintf(buf2, "%1.1f", r);
|
||||
if (strcmp(buf1, buf2)) {
|
||||
printf("we seem to support %d digits\n", x-1);
|
||||
break;
|
||||
@@ -939,4 +1018,4 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* SNPRINTF_TEST */
|
||||
#endif /* TEST_SNPRINTF */
|
||||
|
||||
@@ -57,10 +57,10 @@
|
||||
int wildmatch_iteration_count;
|
||||
#endif
|
||||
|
||||
static int domatch(const unsigned char *p, const unsigned char *text)
|
||||
static int domatch(const uchar *p, const uchar *text)
|
||||
{
|
||||
int matched, special;
|
||||
unsigned char ch, prev;
|
||||
uchar ch, prev;
|
||||
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count++;
|
||||
@@ -141,9 +141,9 @@ static int domatch(const unsigned char *p, const unsigned char *text)
|
||||
ch = 0; /* This makes "prev" get set to 0. */
|
||||
}
|
||||
else if (ch == '[' && p[1] == ':') {
|
||||
const unsigned char *s = p += 2;
|
||||
const uchar *s;
|
||||
int i;
|
||||
while ((ch = *p) && ch != ']') p++;
|
||||
for (s = p += 2; (ch = *p) && ch != ']'; p++) {}
|
||||
if (!ch)
|
||||
return ABORT_ALL;
|
||||
i = p - s - 1;
|
||||
@@ -225,5 +225,5 @@ int wildmatch(const char *p, const char *t)
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
return domatch((const unsigned char*)p, (const unsigned char*)t) == TRUE;
|
||||
return domatch((const uchar*)p, (const uchar*)t) == TRUE;
|
||||
}
|
||||
|
||||
10
loadparm.c
10
loadparm.c
@@ -102,8 +102,10 @@ typedef struct
|
||||
char *log_file;
|
||||
char *pid_file;
|
||||
char *socket_options;
|
||||
char *bind_address;
|
||||
int syslog_facility;
|
||||
int max_verbosity;
|
||||
int rsync_port;
|
||||
} global;
|
||||
|
||||
static global Globals;
|
||||
@@ -131,6 +133,7 @@ typedef struct
|
||||
char *auth_users;
|
||||
char *secrets_file;
|
||||
BOOL strict_modes;
|
||||
char *filter;
|
||||
char *exclude;
|
||||
char *exclude_from;
|
||||
char *include;
|
||||
@@ -173,6 +176,7 @@ static service sDefault =
|
||||
NULL, /* auth users */
|
||||
NULL, /* secrets file */
|
||||
True, /* strict modes */
|
||||
NULL, /* filter */
|
||||
NULL, /* exclude */
|
||||
NULL, /* exclude from */
|
||||
NULL, /* include */
|
||||
@@ -271,6 +275,8 @@ static struct parm_struct parm_table[] =
|
||||
{"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},
|
||||
{"port", P_INTEGER, P_GLOBAL, &Globals.rsync_port, NULL, 0},
|
||||
{"address", P_STRING, P_GLOBAL, &Globals.bind_address, NULL, 0},
|
||||
|
||||
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
|
||||
{"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0},
|
||||
@@ -290,6 +296,7 @@ static struct parm_struct parm_table[] =
|
||||
{"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
|
||||
{"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
|
||||
{"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes,NULL, 0},
|
||||
{"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL, 0},
|
||||
{"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0},
|
||||
{"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0},
|
||||
{"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0},
|
||||
@@ -353,6 +360,8 @@ 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_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
|
||||
FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
|
||||
|
||||
FN_LOCAL_STRING(lp_name, name)
|
||||
FN_LOCAL_STRING(lp_comment, comment)
|
||||
@@ -372,6 +381,7 @@ FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
|
||||
FN_LOCAL_STRING(lp_auth_users, auth_users)
|
||||
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
|
||||
FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
|
||||
FN_LOCAL_STRING(lp_filter, filter)
|
||||
FN_LOCAL_STRING(lp_exclude, exclude)
|
||||
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
|
||||
FN_LOCAL_STRING(lp_include, include)
|
||||
|
||||
380
log.c
380
log.c
@@ -27,16 +27,24 @@
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int local_server;
|
||||
extern int quiet;
|
||||
extern int module_id;
|
||||
extern int msg_fd_out;
|
||||
extern int protocol_version;
|
||||
extern int preserve_times;
|
||||
extern int log_format_has_o_or_i;
|
||||
extern int daemon_log_format_has_o_or_i;
|
||||
extern char *auth_user;
|
||||
extern char *log_format;
|
||||
|
||||
static int log_initialised;
|
||||
static int logfile_was_closed;
|
||||
static char *logfname;
|
||||
static FILE *logfile;
|
||||
struct stats stats;
|
||||
@@ -65,8 +73,9 @@ struct {
|
||||
{ RERR_TIMEOUT , "timeout in data send/receive" },
|
||||
{ RERR_CMD_FAILED , "remote shell failed" },
|
||||
{ RERR_CMD_KILLED , "remote shell killed" },
|
||||
{ RERR_CMD_RUN, "remote command could not be run" },
|
||||
{ RERR_CMD_NOTFOUND, "remote command not found" },
|
||||
{ RERR_CMD_RUN , "remote command could not be run" },
|
||||
{ RERR_CMD_NOTFOUND,"remote command not found" },
|
||||
{ RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
@@ -88,9 +97,9 @@ static char const *rerr_name(int code)
|
||||
|
||||
static void logit(int priority, char *buf)
|
||||
{
|
||||
if (logfname) {
|
||||
if (!logfile)
|
||||
log_open();
|
||||
if (logfile_was_closed)
|
||||
logfile_reopen();
|
||||
if (logfile) {
|
||||
fprintf(logfile,"%s [%d] %s",
|
||||
timestring(time(NULL)), (int)getpid(), buf);
|
||||
fflush(logfile);
|
||||
@@ -99,9 +108,48 @@ static void logit(int priority, char *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static void syslog_init()
|
||||
{
|
||||
static int been_here = 0;
|
||||
int options = LOG_PID;
|
||||
|
||||
if (been_here)
|
||||
return;
|
||||
been_here = 1;
|
||||
|
||||
#ifdef LOG_NDELAY
|
||||
options |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
#ifdef LOG_DAEMON
|
||||
openlog("rsyncd", options, lp_syslog_facility());
|
||||
#else
|
||||
openlog("rsyncd", options);
|
||||
#endif
|
||||
|
||||
#ifndef LOG_NDELAY
|
||||
logit(LOG_INFO, "rsyncd started\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void logfile_open(void)
|
||||
{
|
||||
extern int orig_umask;
|
||||
int old_umask = umask(022 | orig_umask);
|
||||
logfile = fopen(logfname, "a");
|
||||
umask(old_umask);
|
||||
if (!logfile) {
|
||||
int fopen_errno = errno;
|
||||
/* Rsync falls back to using syslog on failure. */
|
||||
syslog_init();
|
||||
rsyserr(FERROR, fopen_errno,
|
||||
"failed to open log-file %s", logfname);
|
||||
rprintf(FINFO, "Ignoring \"log file\" setting.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void log_init(void)
|
||||
{
|
||||
int options = LOG_PID;
|
||||
time_t t;
|
||||
|
||||
if (log_initialised)
|
||||
@@ -116,47 +164,29 @@ void log_init(void)
|
||||
|
||||
/* optionally use a log file instead of syslog */
|
||||
logfname = lp_log_file();
|
||||
if (logfname) {
|
||||
if (*logfname) {
|
||||
log_open();
|
||||
return;
|
||||
}
|
||||
logfname = NULL;
|
||||
}
|
||||
|
||||
#ifdef LOG_NDELAY
|
||||
options |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
#ifdef LOG_DAEMON
|
||||
openlog("rsyncd", options, lp_syslog_facility());
|
||||
#else
|
||||
openlog("rsyncd", options);
|
||||
#endif
|
||||
|
||||
#ifndef LOG_NDELAY
|
||||
logit(LOG_INFO,"rsyncd started\n");
|
||||
#endif
|
||||
if (logfname && *logfname)
|
||||
logfile_open();
|
||||
else
|
||||
syslog_init();
|
||||
}
|
||||
|
||||
void log_open(void)
|
||||
{
|
||||
if (logfname && !logfile) {
|
||||
extern int orig_umask;
|
||||
int old_umask = umask(022 | orig_umask);
|
||||
logfile = fopen(logfname, "a");
|
||||
umask(old_umask);
|
||||
}
|
||||
}
|
||||
|
||||
void log_close(void)
|
||||
void logfile_close(void)
|
||||
{
|
||||
if (logfile) {
|
||||
logfile_was_closed = 1;
|
||||
fclose(logfile);
|
||||
logfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void logfile_reopen(void)
|
||||
{
|
||||
if (logfile_was_closed) {
|
||||
logfile_was_closed = 0;
|
||||
logfile_open();
|
||||
}
|
||||
}
|
||||
|
||||
/* this is the underlying (unformatted) rsync debugging function. Call
|
||||
* it with FINFO, FERROR or FLOG */
|
||||
void rwrite(enum logcode code, char *buf, int len)
|
||||
@@ -178,7 +208,9 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (am_daemon) {
|
||||
if (code == FCLIENT)
|
||||
code = FINFO;
|
||||
else if (am_daemon) {
|
||||
static int in_block;
|
||||
char msg[2048];
|
||||
int priority = code == FERROR ? LOG_WARNING : LOG_INFO;
|
||||
@@ -224,7 +256,7 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n')
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This is the rsync debugging function. Call it with FINFO, FERROR or
|
||||
* FLOG. */
|
||||
@@ -235,7 +267,7 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
size_t len;
|
||||
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
len = vsnprintf(buf, sizeof buf, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Deal with buffer overruns. Instead of panicking, just
|
||||
@@ -245,20 +277,20 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
const char ellipsis[] = "[...]";
|
||||
|
||||
/* Reset length, and zero-terminate the end of our buffer */
|
||||
len = sizeof(buf)-1;
|
||||
len = sizeof buf - 1;
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Copy the ellipsis to the end of the string, but give
|
||||
* us one extra character:
|
||||
*
|
||||
* v--- null byte at buf[sizeof(buf)-1]
|
||||
* v--- null byte at buf[sizeof buf - 1]
|
||||
* abcdefghij0
|
||||
* -> abcd[...]00 <-- now two null bytes at end
|
||||
*
|
||||
* If the input format string has a trailing newline,
|
||||
* we copy it into that extra null; if it doesn't, well,
|
||||
* all we lose is one byte. */
|
||||
strncpy(buf+len-sizeof(ellipsis), ellipsis, sizeof(ellipsis));
|
||||
strncpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis);
|
||||
if (format[strlen(format)-1] == '\n') {
|
||||
buf[len-1] = '\n';
|
||||
}
|
||||
@@ -304,7 +336,7 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
void rflush(enum logcode code)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
|
||||
|
||||
if (am_daemon) {
|
||||
return;
|
||||
}
|
||||
@@ -332,50 +364,96 @@ void rflush(enum logcode code)
|
||||
|
||||
/* a generic logging routine for send/recv, with parameter
|
||||
* substitiution */
|
||||
static void log_formatted(enum logcode code,
|
||||
char *format, char *op, struct file_struct *file,
|
||||
struct stats *initial_stats)
|
||||
static void log_formatted(enum logcode code, char *format, char *op,
|
||||
struct file_struct *file, struct stats *initial_stats,
|
||||
int iflags, char *hlink)
|
||||
{
|
||||
char buf[1024];
|
||||
char buf2[1024];
|
||||
char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
|
||||
char *p, *s, *n;
|
||||
size_t l;
|
||||
size_t len, total;
|
||||
int64 b;
|
||||
|
||||
/* We expand % codes one by one in place in buf. We don't
|
||||
* copy in the terminating nul of the inserted strings, but
|
||||
* 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. */
|
||||
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;
|
||||
s = p + 1;
|
||||
*fmt = '%';
|
||||
|
||||
switch (p[1]) {
|
||||
/* We expand % codes one by one in place in buf. We don't
|
||||
* copy in the terminating null of the inserted strings, but
|
||||
* rather keep going until we reach the null of the format. */
|
||||
total = strlcpy(buf, format, sizeof buf);
|
||||
if (total > MAXPATHLEN) {
|
||||
rprintf(FERROR, "log-format string is WAY too long!\n");
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
buf[total++] = '\n';
|
||||
buf[total] = '\0';
|
||||
|
||||
for (p = buf; (p = strchr(p, '%')) != NULL; ) {
|
||||
s = p++;
|
||||
n = fmt + 1;
|
||||
if (*p == '-')
|
||||
*n++ = *p++;
|
||||
while (isdigit(*(uchar*)p) && n - fmt < (int)(sizeof fmt) - 8)
|
||||
*n++ = *p++;
|
||||
if (!*p)
|
||||
break;
|
||||
*n = '\0';
|
||||
n = NULL;
|
||||
|
||||
switch (*p) {
|
||||
case 'h': if (am_daemon) n = client_name(0); break;
|
||||
case 'a': if (am_daemon) n = client_addr(0); break;
|
||||
case 'l':
|
||||
snprintf(buf2,sizeof(buf2),"%.0f",
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(double)file->length);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'p':
|
||||
snprintf(buf2,sizeof(buf2),"%d",
|
||||
(int)getpid());
|
||||
strlcat(fmt, "ld", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(long)getpid());
|
||||
n = buf2;
|
||||
break;
|
||||
case 'o': n = op; break;
|
||||
case 'f':
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
file->basedir ? file->basedir : "",
|
||||
f_name(file));
|
||||
clean_fname(buf2, 0);
|
||||
n = safe_fname(f_name(file));
|
||||
if (am_sender && file->dir.root) {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
file->dir.root, n);
|
||||
/* The buffer from safe_fname() has more
|
||||
* room than MAXPATHLEN, so this is safe. */
|
||||
if (fmt[1])
|
||||
strcpy(n, buf2);
|
||||
else
|
||||
n = buf2;
|
||||
}
|
||||
clean_fname(n, 0);
|
||||
if (*n == '/')
|
||||
n++;
|
||||
break;
|
||||
case 'n':
|
||||
n = safe_fname(f_name(file));
|
||||
if (S_ISDIR(file->mode)) {
|
||||
/* The buffer from safe_fname() has more
|
||||
* room than MAXPATHLEN, so this is safe. */
|
||||
strcat(n, "/");
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (hlink && *hlink) {
|
||||
n = safe_fname(hlink);
|
||||
strcpy(buf2, " => ");
|
||||
} else if (S_ISLNK(file->mode) && file->u.link) {
|
||||
n = safe_fname(file->u.link);
|
||||
strcpy(buf2, " -> ");
|
||||
} else {
|
||||
n = "";
|
||||
if (!fmt[1])
|
||||
break;
|
||||
strcpy(buf2, " ");
|
||||
}
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n);
|
||||
n = buf2;
|
||||
if (*n == '/') n++;
|
||||
break;
|
||||
case 'm': n = lp_name(module_id); break;
|
||||
case 't': n = timestring(time(NULL)); break;
|
||||
@@ -389,7 +467,8 @@ static void log_formatted(enum logcode code,
|
||||
b = stats.total_read -
|
||||
initial_stats->total_read;
|
||||
}
|
||||
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, (double)b);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'c':
|
||||
@@ -400,62 +479,165 @@ static void log_formatted(enum logcode code,
|
||||
b = stats.total_read -
|
||||
initial_stats->total_read;
|
||||
}
|
||||
snprintf(buf2,sizeof(buf2),"%.0f", (double)b);
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, (double)b);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'i':
|
||||
if (iflags & ITEM_DELETED) {
|
||||
n = "*deleting";
|
||||
break;
|
||||
}
|
||||
n = buf2 + MAXPATHLEN - 32;
|
||||
n[0] = iflags & ITEM_LOCAL_CHANGE
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
n[1] = S_ISDIR(file->mode) ? 'd'
|
||||
: IS_DEVICE(file->mode) ? 'D'
|
||||
: S_ISLNK(file->mode) ? 'L' : 'f';
|
||||
n[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
|
||||
n[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
|
||||
n[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_times || IS_DEVICE(file->mode)
|
||||
|| S_ISLNK(file->mode) ? 'T' : 't';
|
||||
n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
|
||||
n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
|
||||
n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
|
||||
n[8] = !(iflags & ITEM_REPORT_XATTRS) ? '.' : 'a';
|
||||
n[9] = '\0';
|
||||
|
||||
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
|
||||
char ch = iflags & ITEM_IS_NEW ? '+' : '?';
|
||||
int i;
|
||||
for (i = 2; n[i]; i++)
|
||||
n[i] = ch;
|
||||
} else if (!(iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE))) {
|
||||
int i;
|
||||
for (i = 2; n[i]; i++) {
|
||||
if (n[i] != '.')
|
||||
break;
|
||||
}
|
||||
if (!n[i]) {
|
||||
for (i = 2; n[i]; i++)
|
||||
n[i] = ' ';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* n is the string to be inserted in place of this %
|
||||
* code; l is its length not including the trailing
|
||||
* NUL */
|
||||
/* "n" is the string to be inserted in place of this % code. */
|
||||
if (!n)
|
||||
continue;
|
||||
if (n != buf2 && fmt[1]) {
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, n);
|
||||
n = buf2;
|
||||
}
|
||||
len = strlen(n);
|
||||
|
||||
l = strlen(n);
|
||||
/* Subtract the length of the escape from the string's size. */
|
||||
total -= p - s + 1;
|
||||
|
||||
if (l + ((int)(s - &buf[0])) >= sizeof(buf)) {
|
||||
rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n",
|
||||
if (len + total >= (size_t)sizeof buf) {
|
||||
rprintf(FERROR,
|
||||
"buffer overflow expanding %%%c -- exiting\n",
|
||||
p[0]);
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
/* Shuffle the rest of the string along to make space for n */
|
||||
if (l != 2) {
|
||||
memmove(s+(l-1), s+1, strlen(s+1)+1);
|
||||
}
|
||||
if (len != (size_t)(p - s + 1))
|
||||
memmove(s + len, p + 1, total - (s - buf) + 1);
|
||||
total += len;
|
||||
|
||||
/* Copy in n but NOT its nul, because the format sting
|
||||
* probably continues after this. */
|
||||
memcpy(p, n, l);
|
||||
/* Insert the contents of string "n", but NOT its null. */
|
||||
if (len)
|
||||
memcpy(s, n, len);
|
||||
|
||||
/* Skip over inserted string; continue looking */
|
||||
s = p+l;
|
||||
p = s + len;
|
||||
}
|
||||
|
||||
rprintf(code,"%s\n", buf);
|
||||
rwrite(code, buf, total);
|
||||
}
|
||||
|
||||
/* log the outgoing transfer of a file */
|
||||
void log_send(struct file_struct *file, struct stats *initial_stats)
|
||||
/* Return 1 if the format escape is in the log-format string (e.g. look for
|
||||
* the 'b' in the "%9b" format escape). */
|
||||
int log_format_has(const char *format, char esc)
|
||||
{
|
||||
if (lp_transfer_logging(module_id)) {
|
||||
log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats);
|
||||
} else if (log_format && !am_server) {
|
||||
log_formatted(FINFO, log_format, "send", file, initial_stats);
|
||||
const char *p;
|
||||
|
||||
if (!format)
|
||||
return 0;
|
||||
|
||||
for (p = format; (p = strchr(p, '%')) != NULL; ) {
|
||||
if (*++p == '-')
|
||||
p++;
|
||||
while (isdigit(*(uchar*)p))
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
if (*p == esc)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* log the incoming transfer of a file */
|
||||
void log_recv(struct file_struct *file, struct stats *initial_stats)
|
||||
/* log the transfer of a file */
|
||||
void log_item(struct file_struct *file, struct stats *initial_stats,
|
||||
int iflags, char *hlink)
|
||||
{
|
||||
char *s_or_r = am_sender ? "send" : "recv";
|
||||
|
||||
if (lp_transfer_logging(module_id)) {
|
||||
log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats);
|
||||
log_formatted(FLOG, lp_log_format(module_id), s_or_r,
|
||||
file, initial_stats, iflags, hlink);
|
||||
} else if (log_format && !am_server) {
|
||||
log_formatted(FINFO, log_format, "recv", file, initial_stats);
|
||||
log_formatted(FINFO, log_format, s_or_r,
|
||||
file, initial_stats, iflags, hlink);
|
||||
}
|
||||
}
|
||||
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
char *buf)
|
||||
{
|
||||
int see_item = itemizing && (iflags || verbose > 1);
|
||||
if (am_server) {
|
||||
if (am_daemon && !dry_run && see_item)
|
||||
log_item(file, &stats, iflags, buf);
|
||||
} else if (see_item || iflags & ITEM_LOCAL_CHANGE || *buf
|
||||
|| (S_ISDIR(file->mode) && iflags & SIGNIFICANT_ITEM_FLAGS))
|
||||
log_item(file, &stats, iflags, buf);
|
||||
}
|
||||
|
||||
void log_delete(char *fname, int mode)
|
||||
{
|
||||
static struct file_struct file;
|
||||
int len = strlen(fname);
|
||||
char *fmt;
|
||||
|
||||
file.mode = mode;
|
||||
file.basename = fname;
|
||||
|
||||
if (!verbose && !log_format)
|
||||
;
|
||||
else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
|
||||
if (S_ISDIR(mode))
|
||||
len++; /* directories include trailing null */
|
||||
send_msg(MSG_DELETED, fname, len);
|
||||
} else {
|
||||
fmt = log_format_has_o_or_i ? log_format : "deleting %n";
|
||||
log_formatted(FCLIENT, fmt, "del.", &file, &stats,
|
||||
ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
if (!am_daemon || dry_run || !lp_transfer_logging(module_id))
|
||||
return;
|
||||
|
||||
fmt = daemon_log_format_has_o_or_i ? lp_log_format(module_id) : "deleting %n";
|
||||
log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -467,7 +649,7 @@ void log_recv(struct file_struct *file, struct stats *initial_stats)
|
||||
void log_exit(int code, const char *file, int line)
|
||||
{
|
||||
if (code == 0) {
|
||||
rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
|
||||
rprintf(FLOG,"sent %.0f bytes received %.0f bytes total size %.0f\n",
|
||||
(double)stats.total_written,
|
||||
(double)stats.total_read,
|
||||
(double)stats.total_size);
|
||||
|
||||
455
main.c
455
main.c
@@ -20,26 +20,24 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
time_t starttime = 0;
|
||||
|
||||
extern struct stats stats;
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int list_only;
|
||||
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 remove_sent_files;
|
||||
extern int daemon_over_rsh;
|
||||
extern int need_messages_from_generator;
|
||||
extern int kluge_around_eof;
|
||||
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;
|
||||
@@ -48,8 +46,11 @@ extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int protocol_version;
|
||||
extern int recurse;
|
||||
extern int fuzzy_basis;
|
||||
extern int relative_paths;
|
||||
extern int rsync_port;
|
||||
extern int inplace;
|
||||
extern int make_backups;
|
||||
extern int whole_file;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
@@ -57,16 +58,19 @@ 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 struct stats stats;
|
||||
extern char *filesfrom_host;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[];
|
||||
extern char *rsync_path;
|
||||
extern char *shell_cmd;
|
||||
extern char *batch_name;
|
||||
|
||||
int local_server = 0;
|
||||
struct file_list *the_file_list;
|
||||
|
||||
/* there's probably never more than at most 2 outstanding child processes,
|
||||
* but set it higher just in case.
|
||||
*/
|
||||
/* There's probably never more than at most 2 outstanding child processes,
|
||||
* but set it higher, just in case. */
|
||||
#define MAXCHILDPROCS 5
|
||||
|
||||
struct pid_status {
|
||||
@@ -74,6 +78,9 @@ struct pid_status {
|
||||
int status;
|
||||
} pid_stat_table[MAXCHILDPROCS];
|
||||
|
||||
static time_t starttime, endtime;
|
||||
static int64 total_read, total_written;
|
||||
|
||||
static void show_malloc_stats(void);
|
||||
|
||||
/****************************************************************************
|
||||
@@ -118,12 +125,13 @@ void wait_process(pid_t pid, int *status)
|
||||
* 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)
|
||||
static void handle_stats(int f)
|
||||
{
|
||||
endtime = time(NULL);
|
||||
|
||||
/* 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);
|
||||
total_read = stats.total_read;
|
||||
total_written = stats.total_written;
|
||||
|
||||
if (do_stats && verbose > 1) {
|
||||
/* These come out from every process */
|
||||
@@ -145,26 +153,43 @@ static void report(int f)
|
||||
write_longint(f, total_read);
|
||||
write_longint(f, total_written);
|
||||
write_longint(f, stats.total_size);
|
||||
if (protocol_version >= 29) {
|
||||
write_longint(f, stats.flist_buildtime);
|
||||
write_longint(f, stats.flist_xfertime);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* this is the client */
|
||||
|
||||
if (!am_sender) {
|
||||
if (f < 0 && !am_sender) /* e.g. when we got an empty file list. */
|
||||
;
|
||||
else 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);
|
||||
if (protocol_version >= 29) {
|
||||
stats.flist_buildtime = read_longint(f);
|
||||
stats.flist_xfertime = read_longint(f);
|
||||
}
|
||||
} 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 (protocol_version >= 29) {
|
||||
write_longint(batch_fd, stats.flist_buildtime);
|
||||
write_longint(batch_fd, stats.flist_xfertime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void output_summary(void)
|
||||
{
|
||||
if (do_stats) {
|
||||
rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
|
||||
rprintf(FINFO,"Number of files transferred: %d\n",
|
||||
@@ -178,6 +203,14 @@ 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);
|
||||
if (stats.flist_buildtime) {
|
||||
rprintf(FINFO,
|
||||
"File list generation time: %.3f seconds\n",
|
||||
(double)stats.flist_buildtime / 1000);
|
||||
rprintf(FINFO,
|
||||
"File list transfer time: %.3f seconds\n",
|
||||
(double)stats.flist_xfertime / 1000);
|
||||
}
|
||||
rprintf(FINFO,"Total bytes sent: %.0f\n",
|
||||
(double)total_written);
|
||||
rprintf(FINFO,"Total bytes received: %.0f\n",
|
||||
@@ -188,7 +221,7 @@ static void report(int f)
|
||||
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)));
|
||||
(total_written + total_read)/(0.5 + (endtime - starttime)));
|
||||
rprintf(FINFO, "total size is %.0f speedup is %.2f\n",
|
||||
(double)stats.total_size,
|
||||
(double)stats.total_size / (total_written+total_read));
|
||||
@@ -210,22 +243,30 @@ static void show_malloc_stats(void)
|
||||
mi = mallinfo();
|
||||
|
||||
rprintf(FINFO, "\n" RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
|
||||
getpid(),
|
||||
am_server ? "server " : "",
|
||||
am_daemon ? "daemon " : "",
|
||||
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);
|
||||
rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks);
|
||||
rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost);
|
||||
getpid(), am_server ? "server " : "",
|
||||
am_daemon ? "daemon " : "", who_am_i());
|
||||
rprintf(FINFO, " arena: %10ld (bytes from sbrk)\n",
|
||||
(long)mi.arena);
|
||||
rprintf(FINFO, " ordblks: %10ld (chunks not in use)\n",
|
||||
(long)mi.ordblks);
|
||||
rprintf(FINFO, " smblks: %10ld\n",
|
||||
(long)mi.smblks);
|
||||
rprintf(FINFO, " hblks: %10ld (chunks from mmap)\n",
|
||||
(long)mi.hblks);
|
||||
rprintf(FINFO, " hblkhd: %10ld (bytes from mmap)\n",
|
||||
(long)mi.hblkhd);
|
||||
rprintf(FINFO, " allmem: %10ld (bytes from sbrk + mmap)\n",
|
||||
(long)mi.arena + mi.hblkhd);
|
||||
rprintf(FINFO, " usmblks: %10ld\n",
|
||||
(long)mi.usmblks);
|
||||
rprintf(FINFO, " fsmblks: %10ld\n",
|
||||
(long)mi.fsmblks);
|
||||
rprintf(FINFO, " uordblks: %10ld (bytes used)\n",
|
||||
(long)mi.uordblks);
|
||||
rprintf(FINFO, " fordblks: %10ld (bytes free)\n",
|
||||
(long)mi.fordblks);
|
||||
rprintf(FINFO, " keepcost: %10ld (bytes in releasable chunk)\n",
|
||||
(long)mi.keepcost);
|
||||
#endif /* HAVE_MALLINFO */
|
||||
}
|
||||
|
||||
@@ -252,7 +293,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
|
||||
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " ")) {
|
||||
/* Comparison leaves rooms for server_options(). */
|
||||
if (argc >= MAX_ARGS - 100) {
|
||||
if (argc >= MAX_ARGS - MAX_SERVER_ARGS) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
@@ -266,7 +307,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
dash_l_set = 1;
|
||||
}
|
||||
|
||||
#if HAVE_REMSH
|
||||
#ifdef HAVE_REMSH
|
||||
/* remsh (on HPUX) takes the arguments the other way around */
|
||||
args[argc++] = machine;
|
||||
if (user && !(daemon_over_rsh && dash_l_set)) {
|
||||
@@ -311,7 +352,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"cmd=");
|
||||
for (i = 0; i < argc; i++)
|
||||
rprintf(FINFO,"%s ",args[i]);
|
||||
rprintf(FINFO, "%s ", safe_fname(args[i]));
|
||||
rprintf(FINFO,"\n");
|
||||
}
|
||||
|
||||
@@ -381,7 +422,7 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "created directory %s\n", name);
|
||||
rprintf(FINFO, "created directory %s\n", safe_fname(name));
|
||||
|
||||
if (dry_run) {
|
||||
dry_run++;
|
||||
@@ -398,6 +439,30 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
}
|
||||
|
||||
|
||||
/* This is only called by the sender. */
|
||||
static void read_final_goodbye(int f_in, int f_out)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (protocol_version < 29)
|
||||
i = read_int(f_in);
|
||||
else {
|
||||
while ((i = read_int(f_in)) == the_file_list->count
|
||||
&& read_shortint(f_in) == ITEM_IS_NEW) {
|
||||
/* Forward the keep-alive (no-op) to the receiver. */
|
||||
write_int(f_out, the_file_list->count);
|
||||
write_shortint(f_out, ITEM_IS_NEW);
|
||||
}
|
||||
}
|
||||
|
||||
if (i != -1) {
|
||||
rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n",
|
||||
i, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
@@ -414,6 +479,12 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
if (am_daemon && lp_read_only(module_id) && remove_sent_files) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: --remove-sent-files cannot be used with a read-only module\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!relative_paths && !push_dir(dir)) {
|
||||
rsyserr(FERROR, errno, "push_dir#3 %s failed",
|
||||
@@ -431,7 +502,7 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
argv[i] += l+1;
|
||||
}
|
||||
|
||||
if (argc == 0 && recurse) {
|
||||
if (argc == 0 && (recurse || list_only)) {
|
||||
argc = 1;
|
||||
argv--;
|
||||
argv[0] = ".";
|
||||
@@ -441,17 +512,16 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
if (!flist || flist->count == 0) {
|
||||
exit_cleanup(0);
|
||||
}
|
||||
the_file_list = flist;
|
||||
|
||||
io_start_buffering_in();
|
||||
io_start_buffering_out();
|
||||
|
||||
send_files(flist,f_out,f_in);
|
||||
io_flush(FULL_FLUSH);
|
||||
report(f_out);
|
||||
if (protocol_version >= 24) {
|
||||
/* final goodbye message */
|
||||
read_int(f_in);
|
||||
}
|
||||
handle_stats(f_out);
|
||||
if (protocol_version >= 24)
|
||||
read_final_goodbye(f_in, f_out);
|
||||
io_flush(FULL_FLUSH);
|
||||
exit_cleanup(0);
|
||||
}
|
||||
@@ -468,22 +538,21 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
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)
|
||||
delete_files(flist);
|
||||
}
|
||||
init_hard_links();
|
||||
|
||||
if (fd_pair(error_pipe) < 0) {
|
||||
rprintf(FERROR,"error pipe failed in do_recv\n");
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
rsyserr(FERROR, errno, "pipe failed in do_recv");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
|
||||
if ((pid = do_fork()) == 0) {
|
||||
if ((pid = do_fork()) == -1) {
|
||||
rsyserr(FERROR, errno, "fork failed in do_recv");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
close(error_pipe[0]);
|
||||
if (f_in != f_out)
|
||||
close(f_out);
|
||||
@@ -494,22 +563,37 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
/* set place to send errors */
|
||||
set_msg_fd_out(error_pipe[1]);
|
||||
|
||||
recv_files(f_in,flist,local_name);
|
||||
recv_files(f_in, flist, local_name);
|
||||
io_flush(FULL_FLUSH);
|
||||
report(f_in);
|
||||
handle_stats(f_in);
|
||||
|
||||
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! */
|
||||
|
||||
/* Handle any keep-alive packets from the post-processing work
|
||||
* that the generator does. */
|
||||
if (protocol_version >= 29) {
|
||||
kluge_around_eof = -1;
|
||||
|
||||
/* This should only get stopped via a USR2 signal. */
|
||||
while (read_int(f_in) == flist->count
|
||||
&& read_shortint(f_in) == ITEM_IS_NEW) {}
|
||||
|
||||
rprintf(FERROR, "Invalid packet at end of run [%s]\n",
|
||||
who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
/* 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 (1)
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
am_generator = 1;
|
||||
close_multiplexing_in();
|
||||
if (write_batch)
|
||||
if (write_batch && !am_server)
|
||||
stop_write_batch();
|
||||
|
||||
close(error_pipe[1]);
|
||||
@@ -522,8 +606,7 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
|
||||
generate_files(f_out, flist, local_name);
|
||||
|
||||
get_redo_num(); /* Read final MSG_DONE and any prior messages. */
|
||||
report(-1);
|
||||
handle_stats(-1);
|
||||
io_flush(FULL_FLUSH);
|
||||
if (protocol_version >= 24) {
|
||||
/* send a final goodbye message */
|
||||
@@ -544,6 +627,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
struct file_list *flist;
|
||||
char *local_name = NULL;
|
||||
char *dir = NULL;
|
||||
int save_verbose = verbose;
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
/* We can't mix messages with files-from data on the socket,
|
||||
* so temporarily turn off verbose messages. */
|
||||
verbose = 0;
|
||||
}
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
|
||||
@@ -569,23 +659,25 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
}
|
||||
|
||||
io_start_buffering_in();
|
||||
if (delete_mode && !delete_excluded)
|
||||
recv_exclude_list(f_in);
|
||||
recv_filter_list(f_in);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
/* We're receiving the file info from the sender, so we need
|
||||
* the IO routines to automatically write out the names onto
|
||||
* our f_out socket as we read the list info from the sender.
|
||||
* This avoids both deadlock and extra delays/buffers. */
|
||||
/* We need to send the files-from names to the sender at the
|
||||
* same time that we receive the file-list from them, so we
|
||||
* need the IO routines to automatically write out the names
|
||||
* onto our f_out socket as we read the file-list. This
|
||||
* avoids both deadlock and extra delays/buffers. */
|
||||
io_set_filesfrom_fds(filesfrom_fd, f_out);
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
flist = recv_file_list(f_in);
|
||||
verbose = save_verbose;
|
||||
if (!flist) {
|
||||
rprintf(FERROR,"server_recv: recv_file_list error\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
the_file_list = flist;
|
||||
|
||||
if (argc > 0) {
|
||||
if (strcmp(dir,".")) {
|
||||
@@ -621,10 +713,10 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
|
||||
if (am_sender) {
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
if (need_messages_from_generator)
|
||||
io_start_multiplex_in();
|
||||
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
recv_filter_list(f_in);
|
||||
do_server_sender(f_in, f_out, argc, argv);
|
||||
} else {
|
||||
do_server_recv(f_in, f_out, argc, argv);
|
||||
@@ -644,9 +736,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
char *local_name = NULL;
|
||||
|
||||
cleanup_child_pid = pid;
|
||||
if (read_batch) {
|
||||
assert(am_sender == 0);
|
||||
} else {
|
||||
if (!read_batch) {
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
}
|
||||
@@ -670,63 +760,64 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (am_sender) {
|
||||
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)
|
||||
if (!filesfrom_host)
|
||||
set_msg_fd_in(f_in);
|
||||
send_filter_list(f_out);
|
||||
if (filesfrom_host)
|
||||
filesfrom_fd = f_in;
|
||||
|
||||
if (write_batch)
|
||||
if (write_batch && !am_server)
|
||||
start_write_batch(f_out);
|
||||
if (!read_batch) /* don't write to pipe */
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
flist = send_file_list(f_out, argc, argv);
|
||||
set_msg_fd_in(-1);
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"file list sent\n");
|
||||
the_file_list = flist;
|
||||
|
||||
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);
|
||||
}
|
||||
handle_stats(-1);
|
||||
if (protocol_version >= 24)
|
||||
read_final_goodbye(f_in, f_out);
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
|
||||
io_flush(FULL_FLUSH);
|
||||
wait_process(pid, &status);
|
||||
}
|
||||
report(-1);
|
||||
output_summary();
|
||||
io_flush(FULL_FLUSH);
|
||||
exit_cleanup(status);
|
||||
}
|
||||
|
||||
if (argc == 0)
|
||||
list_only = 1;
|
||||
if (need_messages_from_generator && !read_batch)
|
||||
io_start_multiplex_out();
|
||||
|
||||
if (!read_batch)
|
||||
send_exclude_list(f_out);
|
||||
if (argc == 0)
|
||||
list_only |= 1;
|
||||
|
||||
send_filter_list(read_batch ? -1 : f_out);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
io_set_filesfrom_fds(filesfrom_fd, f_out);
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
if (write_batch)
|
||||
if (write_batch && !am_server)
|
||||
start_write_batch(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist || flist->count == 0) {
|
||||
rprintf(FINFO, "client: nothing to do: "
|
||||
"perhaps you need to specify some filenames or "
|
||||
"the --recursive option?\n");
|
||||
exit_cleanup(0);
|
||||
the_file_list = flist;
|
||||
|
||||
if (flist && flist->count > 0) {
|
||||
local_name = get_local_name(flist, argv[0]);
|
||||
|
||||
status2 = do_recv(f_in, f_out, flist, local_name);
|
||||
} else {
|
||||
handle_stats(-1);
|
||||
output_summary();
|
||||
}
|
||||
|
||||
local_name = get_local_name(flist,argv[0]);
|
||||
|
||||
status2 = do_recv(f_in,f_out,flist,local_name);
|
||||
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
|
||||
@@ -777,134 +868,64 @@ static int start_client(int argc, char *argv[])
|
||||
if ((rc = copy_argv(argv)))
|
||||
return rc;
|
||||
|
||||
/* rsync:// always uses rsync server over direct socket connection */
|
||||
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';
|
||||
path = p+1;
|
||||
} else
|
||||
path = "";
|
||||
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';
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv+1);
|
||||
}
|
||||
|
||||
if (!read_batch) { /* for read_batch, NO source is specified */
|
||||
p = find_colon(argv[0]);
|
||||
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) {
|
||||
argc--;
|
||||
shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
|
||||
if (shell_path) { /* source is remote */
|
||||
argv++;
|
||||
if (filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (p[1] == ':') { /* double colon */
|
||||
*p = 0;
|
||||
if (rsync_port) {
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(argv[0], p+2,
|
||||
argc-1, argv+1);
|
||||
return start_socket_client(shell_machine,
|
||||
shell_path,
|
||||
argc, argv);
|
||||
}
|
||||
p++;
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
am_sender = 0;
|
||||
} else { /* source is local, check dest arg */
|
||||
am_sender = 1;
|
||||
|
||||
if (argc < 1) { /* destination required */
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
am_sender = 0;
|
||||
*p = 0;
|
||||
shell_machine = argv[0];
|
||||
shell_path = p+1;
|
||||
argv++;
|
||||
} else { /* source is local */
|
||||
am_sender = 1;
|
||||
|
||||
/* rsync:// destination uses rsync server over direct socket */
|
||||
if (strncasecmp(URL_PREFIX, argv[argc-1], strlen(URL_PREFIX)) == 0) {
|
||||
char *host, *path;
|
||||
|
||||
host = argv[argc-1] + strlen(URL_PREFIX);
|
||||
p = strchr(host,'/');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
path = p+1;
|
||||
} else
|
||||
path = "";
|
||||
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';
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv);
|
||||
}
|
||||
|
||||
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) {
|
||||
shell_path = check_for_hostspec(argv[argc], &shell_machine, &rsync_port);
|
||||
if (shell_path && filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (!p) { /* no colon found, so src & dest are local */
|
||||
if (!shell_path) { /* no hostspec found, so src & dest are local */
|
||||
local_server = 1;
|
||||
if (remote_filesfrom_file) {
|
||||
if (filesfrom_host) {
|
||||
rprintf(FERROR,
|
||||
"--files-from cannot be remote when the transfer is local\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
} else if (p[1] == ':') { /* double colon */
|
||||
*p = 0;
|
||||
shell_machine = NULL;
|
||||
shell_path = argv[argc];
|
||||
} else if (rsync_port) {
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(argv[argc-1], p+2,
|
||||
argc-1, argv);
|
||||
return start_socket_client(shell_machine,
|
||||
shell_path,
|
||||
argc, argv);
|
||||
}
|
||||
p++;
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (local_server) {
|
||||
shell_machine = NULL;
|
||||
shell_path = argv[argc-1];
|
||||
} else {
|
||||
*p = 0;
|
||||
shell_machine = argv[argc-1];
|
||||
shell_path = p+1;
|
||||
}
|
||||
}
|
||||
argc--;
|
||||
} else { /* read_batch */
|
||||
local_server = 1;
|
||||
shell_path = argv[argc-1];
|
||||
if (find_colon(shell_path)) {
|
||||
if (check_for_hostspec(shell_path, &shell_machine, &rsync_port)) {
|
||||
rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
@@ -921,10 +942,10 @@ static int start_client(int argc, char *argv[])
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
|
||||
shell_cmd?shell_cmd:"",
|
||||
shell_machine?shell_machine:"",
|
||||
shell_user?shell_user:"",
|
||||
shell_path?shell_path:"");
|
||||
shell_cmd ? safe_fname(shell_cmd) : "",
|
||||
shell_machine ? safe_fname(shell_machine) : "",
|
||||
shell_user ? safe_fname(shell_user) : "",
|
||||
shell_path ? safe_fname(shell_path) : "");
|
||||
}
|
||||
|
||||
/* for remote source, only single dest arg can remain ... */
|
||||
@@ -934,9 +955,8 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* ... or no dest at all */
|
||||
if (!am_sender && argc == 0) {
|
||||
list_only = 1;
|
||||
}
|
||||
if (!am_sender && argc == 0)
|
||||
list_only |= 1;
|
||||
|
||||
pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,
|
||||
&f_in,&f_out);
|
||||
@@ -967,7 +987,11 @@ static RETSIGTYPE sigusr1_handler(UNUSED(int val))
|
||||
|
||||
static RETSIGTYPE sigusr2_handler(UNUSED(int val))
|
||||
{
|
||||
if (log_got_error) _exit(RERR_PARTIAL);
|
||||
if (!am_server)
|
||||
output_summary();
|
||||
close_all();
|
||||
if (log_got_error)
|
||||
_exit(RERR_PARTIAL);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
@@ -1092,6 +1116,10 @@ int main(int argc,char *argv[])
|
||||
* see the EPIPE. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
|
||||
setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
/* Initialize push_dir here because on some old systems getcwd
|
||||
* (implemented by forking "pwd" and reading its output) doesn't
|
||||
* work when there are other child processes. Also, on all systems
|
||||
@@ -1100,7 +1128,7 @@ int main(int argc,char *argv[])
|
||||
|
||||
init_flist();
|
||||
|
||||
if (write_batch || read_batch) {
|
||||
if ((write_batch || read_batch) && !am_server) {
|
||||
if (write_batch)
|
||||
write_batch_shell_file(orig_argc, orig_argv, argc);
|
||||
|
||||
@@ -1113,12 +1141,14 @@ int main(int argc,char *argv[])
|
||||
}
|
||||
if (batch_fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
batch_name);
|
||||
full_fname(batch_name));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (read_batch)
|
||||
read_stream_flags(batch_fd);
|
||||
}
|
||||
if (write_batch < 0)
|
||||
dry_run = 1;
|
||||
|
||||
if (am_daemon && !am_server)
|
||||
return daemon_main();
|
||||
@@ -1128,9 +1158,6 @@ int main(int argc,char *argv[])
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (dry_run)
|
||||
verbose = MAX(verbose,1);
|
||||
|
||||
if (am_server) {
|
||||
set_nonblocking(STDIN_FILENO);
|
||||
set_nonblocking(STDOUT_FILENO);
|
||||
|
||||
99
match.c
99
match.c
@@ -23,13 +23,13 @@ extern int verbose;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
extern int make_backups;
|
||||
|
||||
int updating_basis_file;
|
||||
|
||||
typedef unsigned short tag;
|
||||
|
||||
#define TABLESIZE (1<<16)
|
||||
#define NULL_TAG ((size_t)-1)
|
||||
#define NULL_TAG (-1)
|
||||
|
||||
static int false_alarms;
|
||||
static int tag_hits;
|
||||
@@ -44,12 +44,12 @@ extern struct stats stats;
|
||||
|
||||
struct target {
|
||||
tag t;
|
||||
size_t i;
|
||||
int32 i;
|
||||
};
|
||||
|
||||
static struct target *targets;
|
||||
|
||||
static size_t *tag_table;
|
||||
static int32 *tag_table;
|
||||
|
||||
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
|
||||
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
|
||||
@@ -62,10 +62,10 @@ static int compare_targets(struct target *t1,struct target *t2)
|
||||
|
||||
static void build_hash_table(struct sum_struct *s)
|
||||
{
|
||||
size_t i;
|
||||
int32 i;
|
||||
|
||||
if (!tag_table)
|
||||
tag_table = new_array(size_t, TABLESIZE);
|
||||
tag_table = new_array(int32, TABLESIZE);
|
||||
|
||||
targets = new_array(struct target, s->count);
|
||||
if (!tag_table || !targets)
|
||||
@@ -101,17 +101,20 @@ static OFF_T last_match;
|
||||
* @param i If >0, the number of a matched token. If 0, indicates we
|
||||
* have only literal data.
|
||||
**/
|
||||
static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
OFF_T offset,int i)
|
||||
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
OFF_T offset, int32 i)
|
||||
{
|
||||
OFF_T n = offset - last_match;
|
||||
OFF_T j;
|
||||
int32 n = offset - last_match; /* max value: block_size (int32) */
|
||||
int32 j;
|
||||
|
||||
if (verbose > 2 && i >= 0)
|
||||
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);
|
||||
if (verbose > 2 && i >= 0) {
|
||||
rprintf(FINFO,
|
||||
"match at %.0f last_match=%.0f j=%d len=%ld n=%ld\n",
|
||||
(double)offset, (double)last_match, i,
|
||||
(long)s->sums[i].len, (long)n);
|
||||
}
|
||||
|
||||
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
|
||||
send_token(f, i, buf, last_match, n, i < 0 ? 0 : s->sums[i].len);
|
||||
data_transfer += n;
|
||||
|
||||
if (i >= 0) {
|
||||
@@ -120,8 +123,8 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
}
|
||||
|
||||
for (j = 0; j < n; j += CHUNK_SIZE) {
|
||||
int n1 = MIN(CHUNK_SIZE,n-j);
|
||||
sum_update(map_ptr(buf,last_match+j,n1),n1);
|
||||
int32 n1 = MIN(CHUNK_SIZE, n - j);
|
||||
sum_update(map_ptr(buf, last_match + j, n1), n1);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,12 +133,8 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
else
|
||||
last_match = offset;
|
||||
|
||||
if (buf && do_progress) {
|
||||
if (buf && do_progress)
|
||||
show_progress(last_match, buf->file_size);
|
||||
|
||||
if (i == -1)
|
||||
end_progress(buf->file_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,8 +142,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
OFF_T offset, end, backup;
|
||||
unsigned int k;
|
||||
size_t want_i;
|
||||
int32 k, want_i;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
@@ -155,11 +153,11 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
want_i = 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"hash search b=%u len=%.0f\n",
|
||||
s->blength, (double)len);
|
||||
rprintf(FINFO, "hash search b=%ld len=%.0f\n",
|
||||
(long)s->blength, (double)len);
|
||||
}
|
||||
|
||||
k = MIN(len, s->blength);
|
||||
k = (int32)MIN(len, (OFF_T)s->blength);
|
||||
|
||||
map = (schar *)map_ptr(buf, 0, k);
|
||||
|
||||
@@ -167,21 +165,21 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
s1 = sum & 0xFFFF;
|
||||
s2 = sum >> 16;
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "sum=%.8x k=%u\n", sum, k);
|
||||
rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k);
|
||||
|
||||
offset = 0;
|
||||
|
||||
end = len + 1 - s->sums[s->count-1].len;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "hash search s->blength=%u len=%.0f count=%.0f\n",
|
||||
s->blength, (double)len, (double)s->count);
|
||||
rprintf(FINFO, "hash search s->blength=%ld len=%.0f count=%.0f\n",
|
||||
(long)s->blength, (double)len, (double)s->count);
|
||||
}
|
||||
|
||||
do {
|
||||
tag t = gettag2(s1,s2);
|
||||
int done_csum2 = 0;
|
||||
size_t j = tag_table[t];
|
||||
int32 j = tag_table[t];
|
||||
|
||||
if (verbose > 4)
|
||||
rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum);
|
||||
@@ -192,20 +190,19 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
sum = (s1 & 0xffff) | (s2 << 16);
|
||||
tag_hits++;
|
||||
do {
|
||||
unsigned int l;
|
||||
size_t i = targets[j].i;
|
||||
int32 l, i = targets[j].i;
|
||||
|
||||
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);
|
||||
l = (int32)MIN((OFF_T)s->blength, len-offset);
|
||||
if (l != s->sums[i].len)
|
||||
continue;
|
||||
|
||||
/* inplace: ensure chunk's offset is either >= our
|
||||
/* in-place: ensure chunk's offset is either >= our
|
||||
* offset or that the data didn't move. */
|
||||
if (inplace && !make_backups && s->sums[i].offset < offset
|
||||
if (updating_basis_file && s->sums[i].offset < offset
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
|
||||
continue;
|
||||
|
||||
@@ -224,12 +221,12 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If inplace is enabled, the best possible match is
|
||||
/* When updating in-place, the best possible match is
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the following want_i optimization. */
|
||||
if (inplace && !make_backups) {
|
||||
if (updating_basis_file) {
|
||||
do {
|
||||
size_t i2 = targets[j].i;
|
||||
int32 i2 = targets[j].i;
|
||||
if (s->sums[i2].offset != offset)
|
||||
continue;
|
||||
if (i2 != i) {
|
||||
@@ -250,7 +247,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
/* 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
|
||||
&& (!updating_basis_file || 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) {
|
||||
@@ -263,7 +260,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
|
||||
matched(f,s,buf,offset,i);
|
||||
offset += s->sums[i].len - 1;
|
||||
k = MIN(s->blength, len-offset);
|
||||
k = (int32)MIN((OFF_T)s->blength, len-offset);
|
||||
map = (schar *)map_ptr(buf, offset, k);
|
||||
sum = get_checksum1((char *)map, k);
|
||||
s1 = sum & 0xFFFF;
|
||||
@@ -298,14 +295,12 @@ 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 (backup >= CHUNK_SIZE + s->blength
|
||||
&& end - offset > CHUNK_SIZE) {
|
||||
matched(f,s,buf,offset - s->blength, -2);
|
||||
}
|
||||
if (backup >= s->blength+CHUNK_SIZE && end-offset > CHUNK_SIZE)
|
||||
matched(f, s, buf, offset - s->blength, -2);
|
||||
} while (++offset < end);
|
||||
|
||||
matched(f,s,buf,len,-1);
|
||||
map_ptr(buf,len-1,1);
|
||||
matched(f, s, buf, len, -1);
|
||||
map_ptr(buf, len-1, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -335,7 +330,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (len > 0 && s->count>0) {
|
||||
if (len > 0 && s->count > 0) {
|
||||
build_hash_table(s);
|
||||
|
||||
if (verbose > 2)
|
||||
@@ -348,11 +343,9 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
} else {
|
||||
OFF_T j;
|
||||
/* by doing this in pieces we avoid too many seeks */
|
||||
for (j = 0; j < len-CHUNK_SIZE; j += CHUNK_SIZE) {
|
||||
int n1 = MIN(CHUNK_SIZE,(len-CHUNK_SIZE)-j);
|
||||
matched(f,s,buf,j+n1,-2);
|
||||
}
|
||||
matched(f,s,buf,len,-1);
|
||||
for (j = CHUNK_SIZE; j < len; j += CHUNK_SIZE)
|
||||
matched(f, s, buf, j, -2);
|
||||
matched(f, s, buf, len, -1);
|
||||
}
|
||||
|
||||
sum_end(file_sum);
|
||||
|
||||
@@ -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|^const/ {
|
||||
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^uchar|^short|^struct|^BOOL|^void|^time|^const/ {
|
||||
next;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,46 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Summary: A program for synchronizing files over a network.
|
||||
Name: rsync
|
||||
Version: 2.6.3
|
||||
Version: 2.6.5
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
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
|
||||
Group: Applications/Internet
|
||||
Source: ftp://rsync.samba.org/pub/rsync/rsync-%{version}.tar.gz
|
||||
URL: http://rsync.samba.org/
|
||||
|
||||
Prefix: %{_prefix}
|
||||
BuildRoot: /var/tmp/%{name}-root
|
||||
License: GPL
|
||||
|
||||
%description
|
||||
rsync is a replacement for rcp that has many more features.
|
||||
Rsync uses a reliable algorithm to bring remote and host files into
|
||||
sync very quickly. Rsync is fast because it just sends the differences
|
||||
in the files over the network instead of sending the complete
|
||||
files. Rsync is often used as a very powerful mirroring process or
|
||||
just as a more capable replacement for the rcp command. A technical
|
||||
report which describes the rsync algorithm is included in this
|
||||
package.
|
||||
|
||||
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.
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
A technical report describing the rsync algorithm is included with
|
||||
this package.
|
||||
%build
|
||||
%configure
|
||||
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%makeinstall
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc COPYING README tech_report.tex
|
||||
%{_prefix}/bin/rsync
|
||||
%{_mandir}/man1/rsync.1*
|
||||
%{_mandir}/man5/rsyncd.conf.5*
|
||||
|
||||
%changelog
|
||||
* Thu Jan 30 2003 Horst von Brand <vonbrand@inf.utfsm.cl>
|
||||
@@ -64,30 +86,3 @@ to '%build', removed '%prefix'.
|
||||
|
||||
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
|
||||
|
||||
2
params.c
2
params.c
@@ -492,7 +492,7 @@ static FILE *OpenConfFile( char *FileName )
|
||||
if( NULL == OpenedFile )
|
||||
{
|
||||
rsyserr(FERROR, errno, "rsync: unable to open configuration file \"%s\"",
|
||||
FileName);
|
||||
safe_fname(FileName));
|
||||
}
|
||||
|
||||
return( OpenedFile );
|
||||
|
||||
8
pipe.c
8
pipe.c
@@ -25,7 +25,6 @@ extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int blocking_io;
|
||||
extern int orig_umask;
|
||||
extern int write_batch;
|
||||
extern int filesfrom_fd;
|
||||
|
||||
/**
|
||||
@@ -79,7 +78,8 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
if (blocking_io > 0)
|
||||
set_blocking(STDOUT_FILENO);
|
||||
execvp(command[0], command);
|
||||
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
|
||||
rsyserr(FERROR, errno, "Failed to exec %s",
|
||||
safe_fname(command[0]));
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
@@ -127,10 +127,6 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
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;
|
||||
|
||||
|
||||
@@ -1128,7 +1128,7 @@ const char * poptBadOption(poptContext con, int flags)
|
||||
/*@=nullderef@*/
|
||||
}
|
||||
|
||||
const char *const poptStrerror(const int error)
|
||||
const char * poptStrerror(const int error)
|
||||
{
|
||||
switch (error) {
|
||||
case POPT_ERROR_NOARG:
|
||||
|
||||
@@ -373,7 +373,7 @@ int poptParseArgvString(const unsigned char * s,
|
||||
* @return error string
|
||||
*/
|
||||
/*@-redecl@*/
|
||||
/*@observer@*/ const char *const poptStrerror(const int error)
|
||||
/*@observer@*/ const char * poptStrerror(const int error)
|
||||
/*@*/;
|
||||
/*@=redecl@*/
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getArgDescrip(const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: wazzup? */
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
@@ -115,7 +115,7 @@ static /*@only@*/ /*@null@*/ char *
|
||||
singleOptionDefaultValue(int lineLength,
|
||||
const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
|
||||
32
progress.c
32
progress.c
@@ -26,6 +26,12 @@ extern int am_server;
|
||||
|
||||
#define PROGRESS_HISTORY_SECS 5
|
||||
|
||||
#ifdef GETPGRP_VOID
|
||||
#define GETPGRP_ARG
|
||||
#else
|
||||
#define GETPGRP_ARG 0
|
||||
#endif
|
||||
|
||||
struct progress_history {
|
||||
struct timeval time;
|
||||
OFF_T ofs;
|
||||
@@ -61,17 +67,18 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
|
||||
if (is_last) {
|
||||
/* Compute stats based on the starting info. */
|
||||
diff = msdiff(&ph_start.time, now);
|
||||
if (!diff)
|
||||
if (!ph_start.time.tv_sec
|
||||
|| !(diff = msdiff(&ph_start.time, now)))
|
||||
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;
|
||||
if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
|
||||
diff = 1;
|
||||
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
|
||||
/ diff / 1024.0;
|
||||
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
|
||||
}
|
||||
|
||||
@@ -115,10 +122,19 @@ void end_progress(OFF_T size)
|
||||
void show_progress(OFF_T ofs, OFF_T size)
|
||||
{
|
||||
struct timeval now;
|
||||
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
|
||||
static pid_t pgrp = -1;
|
||||
pid_t tc_pgrp;
|
||||
#endif
|
||||
|
||||
if (am_server)
|
||||
return;
|
||||
|
||||
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
|
||||
if (pgrp == -1)
|
||||
pgrp = getpgrp(GETPGRP_ARG);
|
||||
#endif
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
if (!ph_start.time.tv_sec) {
|
||||
@@ -150,5 +166,11 @@ void show_progress(OFF_T ofs, OFF_T size)
|
||||
ph_list[newest_hpos].ofs = ofs;
|
||||
}
|
||||
|
||||
#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
|
||||
tc_pgrp = tcgetpgrp(STDOUT_FILENO);
|
||||
if (tc_pgrp != pgrp && tc_pgrp != -1)
|
||||
return;
|
||||
#endif
|
||||
|
||||
rprint_progress(ofs, size, &now, False);
|
||||
}
|
||||
|
||||
484
receiver.c
484
receiver.c
@@ -21,122 +21,104 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int recurse;
|
||||
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 do_xfers;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int log_before_transfer;
|
||||
extern int log_format_has_i;
|
||||
extern int daemon_log_format_has_i;
|
||||
extern int csum_length;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int batch_gen_fd;
|
||||
extern int protocol_version;
|
||||
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 basis_dir_cnt;
|
||||
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 remove_sent_files;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int orig_umask;
|
||||
extern int keep_partial;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
extern int delay_updates;
|
||||
extern struct stats stats;
|
||||
extern char *log_format;
|
||||
extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[];
|
||||
extern struct file_list *the_file_list;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
#define SLOT_SIZE (16*1024) /* Desired size in bytes */
|
||||
#define PER_SLOT_BITS (SLOT_SIZE * 8) /* Number of bits per slot */
|
||||
#define PER_SLOT_INTS (SLOT_SIZE / 4) /* Number of int32s per slot */
|
||||
|
||||
static uint32 **delayed_bits = NULL;
|
||||
static int delayed_slot_cnt = 0;
|
||||
static int phase = 0;
|
||||
|
||||
static void delete_one(char *fn, int is_dir)
|
||||
static void init_delayed_bits(int max_ndx)
|
||||
{
|
||||
if (!is_dir) {
|
||||
if (robust_unlink(fn) != 0) {
|
||||
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) {
|
||||
rsyserr(FERROR, errno,
|
||||
"delete_one: rmdir %s failed",
|
||||
full_fname(fn));
|
||||
}
|
||||
} else if (verbose) {
|
||||
rprintf(FINFO, "deleting directory %s\n",
|
||||
safe_fname(fn));
|
||||
}
|
||||
}
|
||||
delayed_slot_cnt = (max_ndx + PER_SLOT_BITS - 1) / PER_SLOT_BITS;
|
||||
|
||||
if (!(delayed_bits = (uint32**)calloc(delayed_slot_cnt, sizeof (uint32*))))
|
||||
out_of_memory("set_delayed_bit");
|
||||
}
|
||||
|
||||
|
||||
static int is_backup_file(char *fn)
|
||||
static void set_delayed_bit(int ndx)
|
||||
{
|
||||
int k = strlen(fn) - backup_suffix_len;
|
||||
return k > 0 && strcmp(fn+k, backup_suffix) == 0;
|
||||
}
|
||||
int slot = ndx / PER_SLOT_BITS;
|
||||
ndx %= PER_SLOT_BITS;
|
||||
|
||||
|
||||
/* 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 *argv[1], fbuf[MAXPATHLEN];
|
||||
static int deletion_count;
|
||||
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
|
||||
if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
|
||||
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
|
||||
return;
|
||||
if (!delayed_bits[slot]) {
|
||||
if (!(delayed_bits[slot] = (uint32*)calloc(PER_SLOT_INTS, 4)))
|
||||
out_of_memory("set_delayed_bit");
|
||||
}
|
||||
|
||||
for (j = 0; j < flist->count; j++) {
|
||||
if (!(flist->files[j]->flags & FLAG_TOP_DIR)
|
||||
|| !S_ISDIR(flist->files[j]->mode))
|
||||
delayed_bits[slot][ndx/32] |= 1u << (ndx % 32);
|
||||
}
|
||||
|
||||
/* Call this with -1 to start checking from 0. Returns -1 at the end. */
|
||||
static int next_delayed_bit(int after)
|
||||
{
|
||||
uint32 bits, mask;
|
||||
int i, ndx = after + 1;
|
||||
int slot = ndx / PER_SLOT_BITS;
|
||||
ndx %= PER_SLOT_BITS;
|
||||
|
||||
mask = (1u << (ndx % 32)) - 1;
|
||||
for (i = ndx / 32; slot < delayed_slot_cnt; slot++, i = mask = 0) {
|
||||
if (!delayed_bits[slot])
|
||||
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", 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)
|
||||
for ( ; i < PER_SLOT_INTS; i++, mask = 0) {
|
||||
if (!(bits = delayed_bits[slot][i] & ~mask))
|
||||
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))) {
|
||||
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);
|
||||
}
|
||||
deletion_count++;
|
||||
/* The xor magic figures out the lowest enabled bit in
|
||||
* bits, and the switch quickly computes log2(bit). */
|
||||
switch (bits ^ (bits & (bits-1))) {
|
||||
#define LOG2(n) case 1u << n: return slot*PER_SLOT_BITS + i*32 + n
|
||||
LOG2(0); LOG2(1); LOG2(2); LOG2(3);
|
||||
LOG2(4); LOG2(5); LOG2(6); LOG2(7);
|
||||
LOG2(8); LOG2(9); LOG2(10); LOG2(11);
|
||||
LOG2(12); LOG2(13); LOG2(14); LOG2(15);
|
||||
LOG2(16); LOG2(17); LOG2(18); LOG2(19);
|
||||
LOG2(20); LOG2(21); LOG2(22); LOG2(23);
|
||||
LOG2(24); LOG2(25); LOG2(26); LOG2(27);
|
||||
LOG2(28); LOG2(29); LOG2(30); LOG2(31);
|
||||
}
|
||||
return -1; /* impossible... */
|
||||
}
|
||||
flist_free(local_file_list);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +171,8 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
maxname = MIN(MAXPATHLEN - 7 - length, NAME_MAX - 8);
|
||||
|
||||
if (maxname < 1) {
|
||||
rprintf(FERROR, "temporary filename too long: %s\n", fname);
|
||||
rprintf(FERROR, "temporary filename too long: %s\n",
|
||||
safe_fname(fname));
|
||||
fnametmp[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
@@ -208,18 +191,18 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
static char file_sum2[MD4_SUM_LENGTH];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
unsigned int len;
|
||||
int32 len;
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
int i;
|
||||
int32 i;
|
||||
char *map = NULL;
|
||||
|
||||
read_sum_head(f_in, &sum);
|
||||
|
||||
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);
|
||||
int32 read_size = MAX(sum.blength * 2, 16*1024);
|
||||
mapbuf = map_file(fd_r, size_r, read_size, sum.blength);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "recv mapped %s of size %.0f\n",
|
||||
safe_fname(fname_r), (double)size_r);
|
||||
@@ -242,7 +225,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
stats.literal_data += i;
|
||||
cleanup_got_literal = 1;
|
||||
|
||||
sum_update(data,i);
|
||||
sum_update(data, i);
|
||||
|
||||
if (fd != -1 && write_file(fd,data,i) != i)
|
||||
goto report_write_error;
|
||||
@@ -251,22 +234,24 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
}
|
||||
|
||||
i = -(i+1);
|
||||
offset2 = i*(OFF_T)sum.blength;
|
||||
offset2 = i * (OFF_T)sum.blength;
|
||||
len = sum.blength;
|
||||
if (i == (int)sum.count-1 && sum.remainder != 0)
|
||||
len = sum.remainder;
|
||||
|
||||
stats.matched_data += len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
|
||||
i,len,(double)offset2,(double)offset);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] of size %ld at %.0f offset=%.0f\n",
|
||||
i, (long)len, (double)offset2, (double)offset);
|
||||
}
|
||||
|
||||
if (mapbuf) {
|
||||
map = map_ptr(mapbuf,offset2,len);
|
||||
|
||||
see_token(map, len);
|
||||
sum_update(map,len);
|
||||
sum_update(map, len);
|
||||
}
|
||||
|
||||
if (inplace) {
|
||||
@@ -283,12 +268,13 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fd != -1 && write_file(fd, map, len) != (int)len)
|
||||
if (fd != -1 && map && write_file(fd, map, len) != (int)len)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
flush_write_file(fd);
|
||||
if (flush_write_file(fd) < 0)
|
||||
goto report_write_error;
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (inplace && fd != -1)
|
||||
@@ -324,6 +310,57 @@ static void discard_receive_data(int f_in, OFF_T length)
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
|
||||
}
|
||||
|
||||
static void handle_delayed_updates(struct file_list *flist, char *local_name)
|
||||
{
|
||||
char *fname, *partialptr, numbuf[4];
|
||||
int i;
|
||||
|
||||
for (i = -1; (i = next_delayed_bit(i)) >= 0; ) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
fname = local_name ? local_name : f_name(file);
|
||||
if ((partialptr = partial_dir_fname(fname)) != NULL) {
|
||||
if (make_backups && !make_backup(fname))
|
||||
continue;
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "renaming %s to %s\n",
|
||||
safe_fname(partialptr),
|
||||
safe_fname(fname));
|
||||
}
|
||||
if (do_rename(partialptr, fname) < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"rename failed for %s (from %s)",
|
||||
full_fname(fname),
|
||||
safe_fname(partialptr));
|
||||
} else {
|
||||
if (remove_sent_files
|
||||
|| (preserve_hard_links
|
||||
&& file->link_u.links)) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_SUCCESS,numbuf,4);
|
||||
}
|
||||
handle_partial_dir(partialptr,
|
||||
PDIR_DELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i)
|
||||
{
|
||||
while (next_gen_i < desired_i) {
|
||||
if (next_gen_i >= 0) {
|
||||
rprintf(FINFO,
|
||||
"(No batched update for%s \"%s\")\n",
|
||||
phase ? " resend of" : "",
|
||||
safe_fname(f_name(the_file_list->files[next_gen_i])));
|
||||
}
|
||||
next_gen_i = read_int(batch_gen_fd);
|
||||
if (next_gen_i == -1)
|
||||
next_gen_i = the_file_list->count;
|
||||
}
|
||||
return next_gen_i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* main routine for receiver process.
|
||||
@@ -334,15 +371,20 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
int next_gen_i = -1;
|
||||
int fd1,fd2;
|
||||
STRUCT_STAT st;
|
||||
int iflags, xlen;
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char template[MAXPATHLEN];
|
||||
char xname[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnamecmp, *partialptr;
|
||||
char *fnamecmp, *partialptr, numbuf[4];
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
uchar fnamecmp_type;
|
||||
struct file_struct *file;
|
||||
struct stats initial_stats;
|
||||
int save_make_backups = make_backups;
|
||||
int i, recv_ok, phase = 0;
|
||||
int itemizing = am_daemon ? daemon_log_format_has_i
|
||||
: !am_server && log_format_has_i;
|
||||
int max_phase = protocol_version >= 29 ? 2 : 1;
|
||||
int i, recv_ok;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
|
||||
@@ -352,107 +394,156 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
flist->hlink_pool = NULL;
|
||||
}
|
||||
|
||||
if (delay_updates)
|
||||
init_delayed_bits(flist->count);
|
||||
|
||||
while (1) {
|
||||
cleanup_disable();
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
if (read_batch) {
|
||||
if (next_gen_i != flist->count)
|
||||
while (read_int(batch_gen_fd) != -1) {}
|
||||
get_next_gen_i(batch_gen_fd, next_gen_i,
|
||||
flist->count);
|
||||
next_gen_i = -1;
|
||||
}
|
||||
|
||||
if (phase)
|
||||
if (++phase > max_phase)
|
||||
break;
|
||||
|
||||
phase = 1;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files phase=%d\n", phase);
|
||||
if (phase == 2 && delay_updates)
|
||||
handle_delayed_updates(flist, local_name);
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
if (keep_partial)
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = 0; /* prevents double backup */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= flist->count) {
|
||||
rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n",
|
||||
i, flist->count);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
iflags = read_item_attrs(f_in, -1, i, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (iflags == ITEM_IS_NEW) /* no-op packet */
|
||||
continue;
|
||||
|
||||
file = flist->files[i];
|
||||
fname = local_name ? local_name : f_name_to(file, fbuf);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
continue;
|
||||
}
|
||||
if (phase == 2) {
|
||||
rprintf(FERROR,
|
||||
"got transfer request in phase 2 [%s]\n",
|
||||
who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
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 the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname));
|
||||
continue;
|
||||
}
|
||||
|
||||
initial_stats = stats;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files(%s)\n", safe_fname(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) {
|
||||
if (server_filter_list.head
|
||||
&& check_filter(&server_filter_list, fname, 0) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (partial_dir) {
|
||||
if ((partialptr = partial_dir_fname(fname)) != NULL)
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
if (!am_server && log_format)
|
||||
log_item(file, &stats, iflags, NULL);
|
||||
if (read_batch)
|
||||
discard_receive_data(f_in, file->length);
|
||||
continue;
|
||||
}
|
||||
if (write_batch < 0) {
|
||||
log_item(file, &stats, iflags, NULL);
|
||||
if (!am_server)
|
||||
discard_receive_data(f_in, file->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
next_gen_i = get_next_gen_i(batch_gen_fd, next_gen_i, i);
|
||||
if (i < next_gen_i) {
|
||||
rprintf(FINFO, "(Skipping batched update for \"%s\")\n",
|
||||
safe_fname(fname));
|
||||
discard_receive_data(f_in, file->length);
|
||||
continue;
|
||||
}
|
||||
next_gen_i = -1;
|
||||
}
|
||||
|
||||
partialptr = partial_dir ? partial_dir_fname(fname) : fname;
|
||||
|
||||
if (protocol_version >= 29) {
|
||||
switch (fnamecmp_type) {
|
||||
case FNAMECMP_FNAME:
|
||||
fnamecmp = fname;
|
||||
break;
|
||||
case FNAMECMP_PARTIAL_DIR:
|
||||
fnamecmp = partialptr;
|
||||
break;
|
||||
case FNAMECMP_BACKUP:
|
||||
fnamecmp = get_backup_name(fname);
|
||||
break;
|
||||
case FNAMECMP_FUZZY:
|
||||
if (file->dirname) {
|
||||
pathjoin(fnamecmpbuf, MAXPATHLEN,
|
||||
file->dirname, xname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
} else
|
||||
fnamecmp = xname;
|
||||
break;
|
||||
default:
|
||||
if (fnamecmp_type >= basis_dir_cnt) {
|
||||
rprintf(FERROR,
|
||||
"invalid basis_dir index: %d.\n",
|
||||
fnamecmp_type);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
basis_dir[fnamecmp_type], fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
break;
|
||||
}
|
||||
if (!fnamecmp || (server_filter_list.head
|
||||
&& check_filter(&server_filter_list, fname, 0) < 0))
|
||||
fnamecmp = fname;
|
||||
} else {
|
||||
/* Reminder: --inplace && --partial-dir are never
|
||||
* enabled at the same time. */
|
||||
if (inplace && make_backups) {
|
||||
if (!(fnamecmp = get_backup_name(fname)))
|
||||
fnamecmp = fname;
|
||||
} else if (partial_dir && partialptr)
|
||||
fnamecmp = partialptr;
|
||||
else
|
||||
fnamecmp = fname;
|
||||
} else
|
||||
fnamecmp = partialptr = fname;
|
||||
|
||||
if (inplace && make_backups) {
|
||||
if (!(fnamecmp = get_backup_name(fname)))
|
||||
fnamecmp = partialptr;
|
||||
}
|
||||
|
||||
initial_stats = stats;
|
||||
|
||||
/* open the file */
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd1 == -1 && fnamecmp != fname) {
|
||||
fnamecmp = fname;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
if (fd1 == -1 && protocol_version < 29) {
|
||||
if (fnamecmp != fname) {
|
||||
fnamecmp = fname;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 == -1 && compare_dest != NULL) {
|
||||
/* try the file at compare_dest instead */
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
compare_dest, fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
if (fd1 == -1 && basis_dir[0]) {
|
||||
/* pre-29 allowed only one alternate basis */
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
basis_dir[0], fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
|
||||
@@ -507,8 +598,6 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
continue;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -522,7 +611,8 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
* 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);
|
||||
/* Get back to name with XXXXXX in it. */
|
||||
get_tmpname(fnametmp, fname);
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
@@ -538,14 +628,18 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
|
||||
}
|
||||
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
/* log the transfer */
|
||||
if (log_before_transfer)
|
||||
log_item(file, &initial_stats, iflags, NULL);
|
||||
else if (!am_server && verbose && do_progress)
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname));
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
fname, fd2, file->length);
|
||||
|
||||
log_recv(file, &initial_stats);
|
||||
if (!log_before_transfer)
|
||||
log_item(file, &initial_stats, iflags, NULL);
|
||||
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
@@ -555,26 +649,35 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
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 {
|
||||
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
|
||||
finish_transfer(fname, fnametmp, file, recv_ok, 1);
|
||||
if (partialptr != fname && fnamecmp == partialptr) {
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
} else if (keep_partial && partialptr
|
||||
&& handle_partial_dir(partialptr, PDIR_CREATE)) {
|
||||
finish_transfer(partialptr, fnametmp, file, recv_ok,
|
||||
!partial_dir);
|
||||
if (delay_updates && recv_ok) {
|
||||
set_delayed_bit(i);
|
||||
recv_ok = -1;
|
||||
}
|
||||
} else {
|
||||
partialptr = NULL;
|
||||
do_unlink(fnametmp);
|
||||
}
|
||||
|
||||
if (partialptr != fname && fnamecmp == partialptr && recv_ok) {
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
|
||||
cleanup_disable();
|
||||
|
||||
if (!recv_ok) {
|
||||
int msgtype = csum_length == SUM_LENGTH || read_batch ?
|
||||
FERROR : FINFO;
|
||||
if (recv_ok > 0) {
|
||||
if (remove_sent_files
|
||||
|| (preserve_hard_links && file->link_u.links)) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_SUCCESS, numbuf, 4);
|
||||
}
|
||||
} else if (!recv_ok) {
|
||||
int msgtype = phase || read_batch ? FERROR : FINFO;
|
||||
if (msgtype == FERROR || verbose) {
|
||||
char *errstr, *redostr, *keptstr;
|
||||
if (!(keep_partial && partialptr) && !inplace)
|
||||
@@ -595,17 +698,16 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
errstr, safe_fname(fname),
|
||||
keptstr, redostr);
|
||||
}
|
||||
if (csum_length != SUM_LENGTH) {
|
||||
char buf[4];
|
||||
SIVAL(buf, 0, i);
|
||||
send_msg(MSG_REDO, buf, 4);
|
||||
if (!phase) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_REDO, numbuf, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
|
||||
if (delete_after && recurse && !local_name && flist->count > 0)
|
||||
delete_files(flist);
|
||||
if (phase == 2 && delay_updates) /* for protocol_version < 29 */
|
||||
handle_delayed_updates(flist, local_name);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files finished\n");
|
||||
|
||||
138
rsync.c
138
rsync.c
@@ -24,18 +24,20 @@
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int daemon_log_format_has_i;
|
||||
extern int preserve_times;
|
||||
extern int omit_dir_times;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int am_starting_up;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int force_delete;
|
||||
extern int recurse;
|
||||
extern int inplace;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern char *backup_dir;
|
||||
extern int inplace;
|
||||
extern struct stats stats;
|
||||
|
||||
|
||||
/*
|
||||
@@ -48,81 +50,6 @@ void free_sums(struct sum_struct *s)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* delete a file or directory. If force_delete is set then delete
|
||||
* recursively
|
||||
*/
|
||||
int delete_file(char *fname)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *di;
|
||||
char buf[MAXPATHLEN];
|
||||
STRUCT_STAT st;
|
||||
int ret;
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
ret = do_lstat(fname, &st);
|
||||
#else
|
||||
ret = do_stat(fname, &st);
|
||||
#endif
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
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)) {
|
||||
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now we do a recsursive delete on the directory ... */
|
||||
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 (dname[0] == '.' && (dname[1] == '\0'
|
||||
|| (dname[1] == '.' && dname[2] == '\0')))
|
||||
continue;
|
||||
pathjoin(buf, sizeof buf, fname, dname);
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "deleting %s\n", safe_fname(buf));
|
||||
if (delete_file(buf) != 0) {
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (errno) {
|
||||
rsyserr(FERROR, errno, "delete_file: readdir %s failed",
|
||||
full_fname(fname));
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
if (do_rmdir(fname) != 0) {
|
||||
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
int flags)
|
||||
{
|
||||
@@ -130,10 +57,9 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
STRUCT_STAT st2;
|
||||
int change_uid, change_gid;
|
||||
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
if (!st) {
|
||||
if (dry_run)
|
||||
return 1;
|
||||
if (link_stat(fname, &st2, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
@@ -143,14 +69,11 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
}
|
||||
|
||||
if (!preserve_times || S_ISLNK(st->st_mode)
|
||||
|| (make_backups && !backup_dir && S_ISDIR(st->st_mode)))
|
||||
|| (S_ISDIR(st->st_mode) && omit_dir_times))
|
||||
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 */
|
||||
if (set_modtime(fname,file->modtime) != 0 &&
|
||||
!S_ISDIR(st->st_mode)) {
|
||||
if (set_modtime(fname,file->modtime) != 0) {
|
||||
rsyserr(FERROR, errno, "failed to set times on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
@@ -161,17 +84,24 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
change_uid = am_root && preserve_uid && st->st_uid != file->uid;
|
||||
change_gid = preserve_gid && file->gid != GID_NONE
|
||||
&& st->st_gid != file->gid;
|
||||
#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
|
||||
if (S_ISLNK(st->st_mode))
|
||||
;
|
||||
else
|
||||
#endif
|
||||
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);
|
||||
"set uid of %s from %ld to %ld\n",
|
||||
safe_fname(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);
|
||||
"set gid of %s from %ld to %ld\n",
|
||||
safe_fname(fname),
|
||||
(long)st->st_gid, (long)file->gid);
|
||||
}
|
||||
}
|
||||
if (do_lchown(fname,
|
||||
@@ -185,8 +115,8 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
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,
|
||||
keep_dirlinks && S_ISDIR(st->st_mode));
|
||||
@@ -208,10 +138,12 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
#endif
|
||||
|
||||
if (verbose > 1 && flags & PERMS_REPORT) {
|
||||
enum logcode code = daemon_log_format_has_i || dry_run
|
||||
? FCLIENT : FINFO;
|
||||
if (updated)
|
||||
rprintf(FINFO,"%s\n",fname);
|
||||
rprintf(code, "%s\n", safe_fname(fname));
|
||||
else
|
||||
rprintf(FINFO,"%s is uptodate\n",fname);
|
||||
rprintf(code, "%s is uptodate\n", safe_fname(fname));
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
@@ -235,30 +167,32 @@ 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,
|
||||
int ok_to_set_time)
|
||||
int ok_to_set_time, int overwriting_basis)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inplace) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "finishing %s\n", fname);
|
||||
rprintf(FINFO, "finishing %s\n", safe_fname(fname));
|
||||
goto do_set_perms;
|
||||
}
|
||||
|
||||
if (make_backups && !make_backup(fname))
|
||||
if (make_backups && overwriting_basis && !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 (verbose > 2)
|
||||
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "renaming %s to %s\n",
|
||||
safe_fname(fnametmp), safe_fname(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);
|
||||
full_fname(fnametmp), safe_fname(fname));
|
||||
do_unlink(fnametmp);
|
||||
return;
|
||||
}
|
||||
@@ -272,5 +206,7 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
|
||||
|
||||
const char *who_am_i(void)
|
||||
{
|
||||
if (am_starting_up)
|
||||
return am_server ? "server" : "client";
|
||||
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
|
||||
}
|
||||
|
||||
362
rsync.h
362
rsync.h
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) by Andrew Tridgell 1996, 2000
|
||||
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.
|
||||
@@ -58,11 +58,15 @@
|
||||
/* 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 */
|
||||
#define FLAG_HLINK_EOL (1<<1) /* receiver/generator */
|
||||
#define FLAG_MOUNT_POINT (1<<2) /* sender */
|
||||
#define FLAG_NO_FUZZY (1<<2) /* generator */
|
||||
#define FLAG_DEL_HERE (1<<3) /* receiver/generator */
|
||||
#define FLAG_SENT (1<<3) /* sender */
|
||||
#define FLAG_HLINK_TOL (1<<4) /* receiver/generator */
|
||||
|
||||
/* update this if you make incompatible changes */
|
||||
#define PROTOCOL_VERSION 28
|
||||
#define PROTOCOL_VERSION 29
|
||||
|
||||
/* 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
|
||||
@@ -92,23 +96,25 @@
|
||||
#define CHUNK_SIZE (32*1024)
|
||||
#define MAX_MAP_SIZE (256*1024)
|
||||
#define IO_BUFFER_SIZE (4092)
|
||||
#define MAX_BLOCK_SIZE ((int32)1 << 29)
|
||||
|
||||
#define IOERR_GENERAL (1<<0) /* For backward compatibility, this must == 1 */
|
||||
#define IOERR_VANISHED (1<<1)
|
||||
#define IOERR_DEL_LIMIT (1<<2)
|
||||
|
||||
#define MAX_ARGS 1000
|
||||
#define MAX_BASIS_DIRS 20
|
||||
#define MAX_SERVER_ARGS (MAX_BASIS_DIRS*2 + 100)
|
||||
|
||||
#define MPLEX_BASE 7
|
||||
|
||||
#define NO_EXCLUDES 0
|
||||
#define SERVER_EXCLUDES 1
|
||||
#define ALL_EXCLUDES 2
|
||||
#define NO_FILTERS 0
|
||||
#define SERVER_FILTERS 1
|
||||
#define ALL_FILTERS 2
|
||||
|
||||
#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 XFLG_OLD_PREFIXES (1<<1)
|
||||
#define XFLG_ANCHORED2ABS (1<<2)
|
||||
|
||||
#define PERMS_REPORT (1<<0)
|
||||
#define PERMS_SKIP_MTIME (1<<1)
|
||||
@@ -119,18 +125,55 @@
|
||||
#define PDIR_CREATE 1
|
||||
#define PDIR_DELETE 0
|
||||
|
||||
/* Note: 0x00 - 0x7F are used for basis_dir[] indexes! */
|
||||
#define FNAMECMP_BASIS_DIR_LOW 0x00 /* Must remain 0! */
|
||||
#define FNAMECMP_BASIS_DIR_HIGH 0x7F
|
||||
#define FNAMECMP_FNAME 0x80
|
||||
#define FNAMECMP_PARTIAL_DIR 0x81
|
||||
#define FNAMECMP_BACKUP 0x82
|
||||
#define FNAMECMP_FUZZY 0x83
|
||||
|
||||
/* 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 };
|
||||
/* For calling delete_file() */
|
||||
#define DEL_NO_RECURSE (1<<1)
|
||||
#define DEL_FORCE_RECURSE (1<<2) /* recurse even w/o --force */
|
||||
#define DEL_TERSE (1<<3)
|
||||
|
||||
/* For use by the itemize_changes code */
|
||||
#define ITEM_REPORT_CHECKSUM (1<<1)
|
||||
#define ITEM_REPORT_SIZE (1<<2)
|
||||
#define ITEM_REPORT_TIME (1<<3)
|
||||
#define ITEM_REPORT_PERMS (1<<4)
|
||||
#define ITEM_REPORT_OWNER (1<<5)
|
||||
#define ITEM_REPORT_GROUP (1<<6)
|
||||
#define ITEM_REPORT_XATTRS (1<<7)
|
||||
#define ITEM_BASIS_TYPE_FOLLOWS (1<<11)
|
||||
#define ITEM_XNAME_FOLLOWS (1<<12)
|
||||
#define ITEM_IS_NEW (1<<13)
|
||||
#define ITEM_LOCAL_CHANGE (1<<14)
|
||||
#define ITEM_TRANSFER (1<<15)
|
||||
/* These are outside the range of the transmitted flags. */
|
||||
#define ITEM_NO_DEST_AND_NO_UPDATE (1<<16) /* used by itemize() */
|
||||
#define ITEM_MISSING_DATA (1<<16) /* used by log_formatted() */
|
||||
#define ITEM_DELETED (1<<17) /* used by log_formatted() */
|
||||
|
||||
#define SIGNIFICANT_ITEM_FLAGS (~(\
|
||||
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
|
||||
|
||||
|
||||
/* Log-message categories. FLOG and FCLIENT are only used on the daemon
|
||||
* side for custom logging -- they don't get sent over the socket. */
|
||||
enum logcode { FERROR=1, FINFO=2, FLOG=3, FCLIENT=4 };
|
||||
|
||||
/* 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 */
|
||||
MSG_DATA=0, /* raw data on the multiplexed stream */
|
||||
MSG_ERROR=FERROR, MSG_INFO=FINFO, /* remote logging */
|
||||
MSG_LOG=FLOG, MSG_FCLIENT=FCLIENT, /* sibling logging */
|
||||
MSG_REDO=9, /* reprocess indicated flist index */
|
||||
MSG_SUCCESS=100,/* successfully updated indicated flist index */
|
||||
MSG_DELETED=101,/* successfully deleted a file on receiving side */
|
||||
MSG_DONE=86 /* current phase is done */
|
||||
};
|
||||
|
||||
#include "errcode.h"
|
||||
@@ -139,23 +182,39 @@ enum msgcode {
|
||||
|
||||
/* The default RSYNC_RSH is always set in config.h. */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MALLOC_H) && (defined(HAVE_MALLINFO) || !defined(HAVE_STDLIB_H))
|
||||
#if defined HAVE_MALLOC_H && (defined HAVE_MALLINFO || !defined HAVE_STDLIB_H)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
@@ -163,10 +222,6 @@ enum msgcode {
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
@@ -186,8 +241,6 @@ enum msgcode {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
@@ -238,24 +291,27 @@ enum msgcode {
|
||||
#include <syslog.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#if HAVE_DIRENT_H
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
#else
|
||||
# define dirent direct
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if MAJOR_IN_MKDEV
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#elif MAJOR_IN_SYSMACROS
|
||||
# if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__)
|
||||
# define makedev mkdev
|
||||
# endif
|
||||
#elif defined MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
@@ -273,61 +329,85 @@ enum msgcode {
|
||||
#define uchar unsigned char
|
||||
#endif
|
||||
|
||||
#if HAVE_UNSIGNED_CHAR
|
||||
#ifdef SIGNED_CHAR_OK
|
||||
#define schar signed char
|
||||
#else
|
||||
#define schar char
|
||||
#endif
|
||||
|
||||
/* Find a variable that is either exactly 32-bits or longer.
|
||||
* If some code depends on 32-bit truncation, it will need to
|
||||
* take special action in a "#if SIZEOF_INT32 > 4" section. */
|
||||
#ifndef int32
|
||||
#if (SIZEOF_INT == 4)
|
||||
#define int32 int
|
||||
#elif (SIZEOF_LONG == 4)
|
||||
#define int32 long
|
||||
#elif (SIZEOF_SHORT == 4)
|
||||
#define int32 short
|
||||
#if SIZEOF_INT == 4
|
||||
# define int32 int
|
||||
# define SIZEOF_INT32 4
|
||||
#elif SIZEOF_LONG == 4
|
||||
# define int32 long
|
||||
# define SIZEOF_INT32 4
|
||||
#elif SIZEOF_SHORT == 4
|
||||
# define int32 short
|
||||
# define SIZEOF_INT32 4
|
||||
#elif SIZEOF_INT > 4
|
||||
# define int32 int
|
||||
# define SIZEOF_INT32 SIZEOF_INT
|
||||
#elif SIZEOF_LONG > 4
|
||||
# define int32 long
|
||||
# define SIZEOF_INT32 SIZEOF_LONG
|
||||
#else
|
||||
/* I hope this works */
|
||||
#define int32 int
|
||||
#define LARGE_INT32
|
||||
# error Could not find a 32-bit integer variable
|
||||
#endif
|
||||
#else
|
||||
# define SIZEOF_INT32 4
|
||||
#endif
|
||||
|
||||
#ifndef uint32
|
||||
#define uint32 unsigned int32
|
||||
#endif
|
||||
|
||||
#if HAVE_OFF64_T
|
||||
#define OFF_T off64_t
|
||||
#define STRUCT_STAT struct stat64
|
||||
#else
|
||||
#if SIZEOF_OFF_T == 8 || !SIZEOF_OFF64_T || !defined HAVE_STRUCT_STAT64
|
||||
#define OFF_T off_t
|
||||
#define STRUCT_STAT struct stat
|
||||
#else
|
||||
#define OFF_T off64_t
|
||||
#define STRUCT_STAT struct stat64
|
||||
#define USE_STAT64_FUNCS 1
|
||||
#endif
|
||||
|
||||
#if HAVE_OFF64_T
|
||||
#define int64 off64_t
|
||||
#elif (SIZEOF_LONG == 8)
|
||||
#define int64 long
|
||||
#elif (SIZEOF_INT == 8)
|
||||
#define int64 int
|
||||
#elif HAVE_LONGLONG
|
||||
#define int64 long long
|
||||
/* CAVEAT: on some systems, int64 will really be a 32-bit integer IFF
|
||||
* that's the maximum size the file system can handle and there is no
|
||||
* 64-bit type available. The rsync source must therefore take steps
|
||||
* to ensure that any code that really requires a 64-bit integer has
|
||||
* it (e.g. the checksum code uses two 32-bit integers for its 64-bit
|
||||
* counter). */
|
||||
#if SIZEOF_OFF64_T == 8
|
||||
# define int64 off64_t
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_LONG == 8
|
||||
# define int64 long
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_INT == 8
|
||||
# define int64 int
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_LONG_LONG == 8
|
||||
# define int64 long long
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_OFF_T == 8
|
||||
# define int64 off_t
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_INT > 8
|
||||
# define int64 int
|
||||
# define SIZEOF_INT64 SIZEOF_INT
|
||||
#elif SIZEOF_LONG > 8
|
||||
# define int64 long
|
||||
# define SIZEOF_INT64 SIZEOF_LONG
|
||||
#elif SIZEOF_LONG_LONG > 8
|
||||
# define int64 long long
|
||||
# define SIZEOF_INT64 SIZEOF_LONG_LONG
|
||||
#else
|
||||
/* As long as it gets... */
|
||||
#define int64 off_t
|
||||
#define INT64_IS_OFF_T
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_LONG == 8)
|
||||
#define uint64 unsigned long
|
||||
#elif (SIZEOF_INT == 8)
|
||||
#define uint64 unsigned int
|
||||
#elif HAVE_LONGLONG
|
||||
#define uint64 unsigned long long
|
||||
#else
|
||||
/* As long as it gets... */
|
||||
#define uint64 unsigned off_t
|
||||
# define int64 off_t
|
||||
# define SIZEOF_INT64 SIZEOF_OFF_T
|
||||
#endif
|
||||
|
||||
/* Starting from protocol version 26, we always use 64-bit
|
||||
@@ -354,11 +434,11 @@ enum msgcode {
|
||||
*
|
||||
* FIXME: I don't think the code in flist.c has ever worked on a system
|
||||
* where dev_t is a struct.
|
||||
*/
|
||||
*/
|
||||
|
||||
struct idev {
|
||||
uint64 inode;
|
||||
uint64 dev;
|
||||
int64 inode;
|
||||
int64 dev;
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
@@ -401,8 +481,8 @@ struct idev {
|
||||
#define HL_SKIP 1
|
||||
|
||||
struct hlink {
|
||||
int next;
|
||||
int hlindex;
|
||||
struct file_struct *next;
|
||||
};
|
||||
|
||||
#define F_DEV link_u.idev->dev
|
||||
@@ -418,9 +498,12 @@ struct file_struct {
|
||||
char *link; /* Points to symlink string, if a symlink */
|
||||
} u;
|
||||
OFF_T length;
|
||||
char *basename;
|
||||
char *dirname;
|
||||
char *basedir;
|
||||
char *basename; /* The current item's name (AKA filename) */
|
||||
char *dirname; /* The directory info inside the transfer */
|
||||
union {
|
||||
char *root; /* Sender-side dir info outside transfer */
|
||||
int depth; /* Receiver-side directory depth info */
|
||||
} dir;
|
||||
union {
|
||||
struct idev *idev;
|
||||
struct hlink *links;
|
||||
@@ -455,18 +538,19 @@ struct file_struct {
|
||||
#define WITHOUT_HLINK 0
|
||||
|
||||
struct file_list {
|
||||
int count;
|
||||
int malloced;
|
||||
struct file_struct **files;
|
||||
alloc_pool_t file_pool;
|
||||
alloc_pool_t hlink_pool;
|
||||
struct file_struct **files;
|
||||
int count;
|
||||
int malloced;
|
||||
int low, high;
|
||||
};
|
||||
|
||||
#define SUMFLG_SAME_OFFSET (1<<0)
|
||||
|
||||
struct sum_buf {
|
||||
OFF_T offset; /**< offset in file of this chunk */
|
||||
unsigned int len; /**< length of chunk of file */
|
||||
int32 len; /**< length of chunk of file */
|
||||
uint32 sum1; /**< simple checksum */
|
||||
short flags; /**< flag bits */
|
||||
char sum2[SUM_LENGTH]; /**< checksum */
|
||||
@@ -474,23 +558,23 @@ struct sum_buf {
|
||||
|
||||
struct sum_struct {
|
||||
OFF_T flength; /**< total file length */
|
||||
size_t count; /**< how many chunks */
|
||||
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 */
|
||||
int32 count; /**< how many chunks */
|
||||
int32 blength; /**< block_length */
|
||||
int32 remainder; /**< flength % block_length */
|
||||
int s2length; /**< sum2_length */
|
||||
};
|
||||
|
||||
struct map_struct {
|
||||
char *p; /* Window pointer */
|
||||
int fd; /* File Descriptor */
|
||||
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 */
|
||||
OFF_T p_fd_offset; /* offset of cursor in fd ala lseek */
|
||||
char *p; /* Window pointer */
|
||||
int32 p_size; /* Largest window size we allocated */
|
||||
int32 p_len; /* Latest (rounded) window size */
|
||||
int32 def_window_size; /* Default window size */
|
||||
int fd; /* File Descriptor */
|
||||
int status; /* first errno from read errors */
|
||||
};
|
||||
|
||||
#define MATCHFLG_WILD (1<<0) /* pattern has '*', '[', and/or '?' */
|
||||
@@ -500,16 +584,35 @@ struct map_struct {
|
||||
#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;
|
||||
#define MATCHFLG_WORD_SPLIT (1<<7) /* split rules on whitespace */
|
||||
#define MATCHFLG_NO_INHERIT (1<<8) /* don't inherit these rules */
|
||||
#define MATCHFLG_NO_PREFIXES (1<<9) /* parse no prefixes from patterns */
|
||||
#define MATCHFLG_MERGE_FILE (1<<10)/* specifies a file to merge */
|
||||
#define MATCHFLG_PERDIR_MERGE (1<<11)/* merge-file is searched per-dir */
|
||||
#define MATCHFLG_EXCLUDE_SELF (1<<12)/* merge-file name should be excluded */
|
||||
#define MATCHFLG_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */
|
||||
#define MATCHFLG_NEGATE (1<<14)/* rule matches when pattern does not */
|
||||
#define MATCHFLG_CVS_IGNORE (1<<15)/* rule was -C or :C */
|
||||
#define MATCHFLG_SENDER_SIDE (1<<16)/* rule applies to the sending side */
|
||||
#define MATCHFLG_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */
|
||||
|
||||
#define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \
|
||||
| MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \
|
||||
| MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE)
|
||||
|
||||
struct filter_struct {
|
||||
struct filter_struct *next;
|
||||
char *pattern;
|
||||
unsigned int match_flags;
|
||||
int slash_cnt;
|
||||
uint32 match_flags;
|
||||
union {
|
||||
int slash_cnt;
|
||||
struct filter_list_struct *mergelist;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct exclude_list_struct {
|
||||
struct exclude_struct *head;
|
||||
struct exclude_struct *tail;
|
||||
struct filter_list_struct {
|
||||
struct filter_struct *head;
|
||||
struct filter_struct *tail;
|
||||
char *debug_type;
|
||||
};
|
||||
|
||||
@@ -520,6 +623,8 @@ struct stats {
|
||||
int64 total_read;
|
||||
int64 literal_data;
|
||||
int64 matched_data;
|
||||
int64 flist_buildtime;
|
||||
int64 flist_xfertime;
|
||||
int flist_size;
|
||||
int num_files;
|
||||
int num_transferred_files;
|
||||
@@ -527,15 +632,6 @@ struct stats {
|
||||
};
|
||||
|
||||
|
||||
/* we need this function because of the silly way in which duplicate
|
||||
entries are handled in the file lists - we can't change this
|
||||
without breaking existing versions */
|
||||
static inline int flist_up(struct file_list *flist, int i)
|
||||
{
|
||||
while (!flist->files[i]->basename) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "lib/mdfour.h"
|
||||
#include "lib/wildmatch.h"
|
||||
@@ -553,18 +649,18 @@ int asprintf(char **ptr, const char *format, ...);
|
||||
int vasprintf(char **ptr, const char *format, va_list ap);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
|
||||
#if !defined HAVE_VSNPRINTF || !defined HAVE_C99_VSNPRINTF
|
||||
#define vsnprintf rsync_vsnprintf
|
||||
int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
|
||||
#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF
|
||||
#define snprintf rsync_snprintf
|
||||
int snprintf(char *str,size_t count,const char *fmt,...);
|
||||
#endif
|
||||
|
||||
|
||||
#if !HAVE_STRERROR
|
||||
#ifndef HAVE_STRERROR
|
||||
extern char *sys_errlist[];
|
||||
#define strerror(i) sys_errlist[i]
|
||||
#endif
|
||||
@@ -578,14 +674,11 @@ extern char *sys_errlist[];
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define SUPPORT_LINKS HAVE_READLINK
|
||||
#define SUPPORT_HARD_LINKS HAVE_LINK
|
||||
|
||||
/* This could be bad on systems which have no lchown and where chown
|
||||
* follows symbollic links. On such systems it might be better not to
|
||||
* try to chown symlinks at all. */
|
||||
#ifndef HAVE_LCHOWN
|
||||
#define lchown chown
|
||||
#ifdef HAVE_READLINK
|
||||
#define SUPPORT_LINKS 1
|
||||
#endif
|
||||
#ifdef HAVE_LINK
|
||||
#define SUPPORT_HARD_LINKS 1
|
||||
#endif
|
||||
|
||||
#define SIGNAL_CAST (RETSIGTYPE (*)())
|
||||
@@ -671,9 +764,9 @@ extern int errno;
|
||||
/* work out what fcntl flag to use for non-blocking */
|
||||
#ifdef O_NONBLOCK
|
||||
# define NONBLOCK_FLAG O_NONBLOCK
|
||||
#elif defined(SYSV)
|
||||
#elif defined SYSV
|
||||
# define NONBLOCK_FLAG O_NDELAY
|
||||
#else
|
||||
#else
|
||||
# define NONBLOCK_FLAG FNDELAY
|
||||
#endif
|
||||
|
||||
@@ -693,13 +786,13 @@ extern int errno;
|
||||
#define INITACCESSPERMS 0700
|
||||
|
||||
/* handler for null strings in printf format */
|
||||
#define NS(s) ((s)?(s):"<NULL>")
|
||||
#define NS(s) ((s)?safe_fname(s):"<NULL>")
|
||||
|
||||
#if !defined(__GNUC__) || defined(APPLE)
|
||||
#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)
|
||||
#define __attribute__(x)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -757,9 +850,8 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
|
||||
extern int verbose;
|
||||
|
||||
#ifndef HAVE_INET_NTOP
|
||||
const char *
|
||||
inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||
#endif /* !HAVE_INET_NTOP */
|
||||
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_INET_PTON
|
||||
int inet_pton(int af, const char *src, void *dst);
|
||||
|
||||
248
rsyncd.conf.yo
248
rsyncd.conf.yo
@@ -1,6 +1,6 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(30 Sep 2004)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync server)
|
||||
manpage(rsyncd.conf)(5)(1 Jun 2005)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
|
||||
manpagesynopsis()
|
||||
|
||||
rsyncd.conf
|
||||
@@ -8,7 +8,7 @@ rsyncd.conf
|
||||
manpagedescription()
|
||||
|
||||
The rsyncd.conf file is the runtime configuration file for rsync when
|
||||
run as an rsync server.
|
||||
run as an rsync daemon.
|
||||
|
||||
The rsyncd.conf file controls authentication, access, logging and
|
||||
available modules.
|
||||
@@ -19,7 +19,7 @@ The file consists of modules and parameters. A module begins with the
|
||||
name of the module in square brackets and continues until the next
|
||||
module begins. Modules contain parameters of the form 'name = value'.
|
||||
|
||||
The file is line-based - that is, each newline-terminated line represents
|
||||
The file is line-based -- that is, each newline-terminated line represents
|
||||
either a comment, a module name or a parameter.
|
||||
|
||||
Only the first equals sign in a parameter is significant. Whitespace before
|
||||
@@ -41,7 +41,7 @@ in string values.
|
||||
|
||||
manpagesection(LAUNCHING THE RSYNC DAEMON)
|
||||
|
||||
The rsync daemon is launched by specifying the --daemon option to
|
||||
The rsync daemon is launched by specifying the bf(--daemon) option to
|
||||
rsync.
|
||||
|
||||
The daemon must run with root privileges if you wish to use chroot, to
|
||||
@@ -51,24 +51,24 @@ write the appropriate data, log, and lock files.
|
||||
|
||||
You can launch it either via inetd, as a stand-alone daemon, or from
|
||||
an rsync client via a remote shell. If run as a stand-alone daemon then
|
||||
just run the command "rsync --daemon" from a suitable startup script.
|
||||
just run the command "bf(rsync --daemon)" from a suitable startup script.
|
||||
If run from an rsync client via a remote shell (by specifying both the
|
||||
"-e/--rsh" option and server mode with "::" or "rsync://"), the --daemon
|
||||
bf(--rsh) (bf(-e)) option and daemon mode with "::" or "rsync://"), the bf(--daemon)
|
||||
option is automatically passed to the remote side.
|
||||
|
||||
When run via inetd you should add a line like this to /etc/services:
|
||||
|
||||
quote(rsync 873/tcp)
|
||||
verb( rsync 873/tcp)
|
||||
|
||||
and a single line something like this to /etc/inetd.conf:
|
||||
|
||||
quote(rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
|
||||
verb( rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
|
||||
|
||||
Replace "/usr/bin/rsync" with the path to where you have rsync installed on
|
||||
your system. You will then need to send inetd a HUP signal to tell it to
|
||||
reread its config file.
|
||||
|
||||
Note that you should not send the rsync server a HUP signal to force
|
||||
Note that you should bf(not) send the rsync daemon a HUP signal to force
|
||||
it to reread the tt(rsyncd.conf) file. The file is re-read on each client
|
||||
connection.
|
||||
|
||||
@@ -90,19 +90,30 @@ is no motd file.
|
||||
dit(bf(log file)) The "log file" option tells the rsync daemon to log
|
||||
messages to that file rather than using syslog. This is particularly
|
||||
useful on systems (such as AIX) where syslog() doesn't work for
|
||||
chrooted programs.
|
||||
chrooted programs. If the daemon fails to open to specified file, it
|
||||
will fall back to using syslog and output an error about the failure.
|
||||
(Note that a failure to open the specified log file used to be a fatal
|
||||
error.)
|
||||
|
||||
dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
|
||||
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
|
||||
rsync server. You may use any standard syslog facility name which is
|
||||
rsync daemon. You may use any standard syslog facility name which is
|
||||
defined on your system. Common names are auth, authpriv, cron, daemon,
|
||||
ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0,
|
||||
local1, local2, local3, local4, local5, local6 and local7. The default
|
||||
is daemon.
|
||||
|
||||
dit(bf(port)) You can override the default port the daemon will listen on
|
||||
by specifying this value (defaults to 873). This is ignored if the daemon
|
||||
is being run by inetd, and is superseded by the bf(--port) command-line option.
|
||||
|
||||
dit(bf(address)) You can override the default IP address the daemon
|
||||
will listen on by specifying this value. This is ignored if the daemon is
|
||||
being run by inetd, and is superseded by the bf(--address) command-line option.
|
||||
|
||||
dit(bf(socket options)) This option can provide endless fun for people
|
||||
who like to tune their systems to the utmost degree. You can set all
|
||||
sorts of socket options which may make transfers faster (or
|
||||
@@ -126,11 +137,11 @@ dit(bf(comment)) The "comment" option specifies a description string
|
||||
that is displayed next to the module name when clients obtain a list
|
||||
of available modules. The default is no comment.
|
||||
|
||||
dit(bf(path)) The "path" option specifies the directory in the servers
|
||||
dit(bf(path)) The "path" option specifies the directory in the daemon's
|
||||
filesystem to make available in this module. You must specify this option
|
||||
for each module in tt(rsyncd.conf).
|
||||
|
||||
dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
|
||||
dit(bf(use chroot)) If "use chroot" is true, the rsync daemon 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,
|
||||
@@ -139,7 +150,7 @@ of the new root path, and of complicating the preservation of usernames and grou
|
||||
(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 most absolute paths (options
|
||||
such as --backup-dir, --compare-dest, etc. interpret an absolute path as
|
||||
such as bf(--backup-dir), bf(--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.
|
||||
|
||||
@@ -149,16 +160,21 @@ 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
|
||||
able to copy the IDs, just as if the bf(--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.
|
||||
(e.g. "exclude = /etc/**"). Note that having the exclusion affect uploads
|
||||
is a relatively new feature in rsync, so make sure your daemon is
|
||||
at least 2.6.3 to effect this. Also note that it is safest to exclude a
|
||||
directory and all its contents combining the rule "/some/dir/" with the
|
||||
rule "/some/dir/**" just to be sure that rsync will not allow deeper
|
||||
access to some of the excluded files inside the directory (rsync tries to
|
||||
do this automatically, but you might as well specify both to be extra
|
||||
sure).
|
||||
|
||||
dit(bf(max connections)) The "max connections" option allows you to
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
@@ -166,8 +182,13 @@ Any clients connecting when the maximum has been reached will receive a
|
||||
message telling them to try later. The default is 0 which means no limit.
|
||||
See also the "lock file" option.
|
||||
|
||||
dit(bf(max verbosity)) The "max verbosity" option allows you to control
|
||||
the maximum amount of verbose information that you'll allow the daemon to
|
||||
generate (since the information goes into the log file). The default is 1,
|
||||
which allows the client to request one level of verbosity.
|
||||
|
||||
dit(bf(lock file)) The "lock file" option specifies the file to use to
|
||||
support the "max connections" option. The rsync server uses record
|
||||
support the "max connections" option. The rsync daemon uses record
|
||||
locking on this file to ensure that the max connections limit is not
|
||||
exceeded for the modules sharing the lock file.
|
||||
The default is tt(/var/run/rsyncd.lock).
|
||||
@@ -175,13 +196,13 @@ The default is tt(/var/run/rsyncd.lock).
|
||||
dit(bf(read only)) The "read only" option determines whether clients
|
||||
will be able to upload files or not. If "read only" is true then any
|
||||
attempted uploads will fail. If "read only" is false then uploads will
|
||||
be possible if file permissions on the server allow them. The default
|
||||
be possible if file permissions on the daemon side 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
|
||||
will be possible if file permissions on the daemon side allow them. The
|
||||
default is for this option to be disabled.
|
||||
|
||||
dit(bf(list)) The "list" option determines if this module should be
|
||||
@@ -200,38 +221,48 @@ 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(filter)) The "filter" option allows you to specify a space-separated
|
||||
list of filter rules that the daemon will not allow to be read or written.
|
||||
This is only superficially equivalent to the client specifying these
|
||||
patterns with the bf(--filter) option. Only one "filter" option may be
|
||||
specified, but it may contain as many rules as you like, including
|
||||
merge-file rules. Note that per-directory merge-file rules do not provide
|
||||
as much protection as global rules, but they can be used to make bf(--delete)
|
||||
work better when a client downloads the daemon's files (if the per-dir
|
||||
merge files are included in the transfer).
|
||||
|
||||
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
|
||||
space-separated list of patterns that the daemon 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"
|
||||
specifying these patterns with the bf(--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
|
||||
the daemon: that is, it excludes files received by a client when receiving
|
||||
from a daemon and files deleted on a daemon when sending to a daemon, but
|
||||
it doesn't exclude files from being deleted on a client when receiving
|
||||
from a server.
|
||||
from a daemon.
|
||||
|
||||
dit(bf(exclude from)) The "exclude from" option specifies a filename
|
||||
on the server that contains exclude patterns, one per line.
|
||||
on the daemon that contains exclude patterns, one per line.
|
||||
This is only superficially equivalent
|
||||
to the client specifying the --exclude-from option with an equivalent file.
|
||||
to the client specifying the bf(--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
|
||||
the bf(--include) option because it applies only on the daemon. 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
|
||||
on the daemon that contains include patterns, one per line. This is
|
||||
only superficially equivalent to the client specifying the
|
||||
--include-from option with a equivalent file.
|
||||
bf(--include-from) option with a equivalent file.
|
||||
See the "exclude" option above.
|
||||
|
||||
dit(bf(auth users)) The "auth users" option specifies a comma and
|
||||
@@ -245,10 +276,10 @@ usernames are passwords are stored in the file specified by the
|
||||
"secrets file" option. The default is for all users to be able to
|
||||
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
|
||||
See also the "CONNECTING TO AN RSYNC DAEMON 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 an rsync server.
|
||||
username when using a remote shell to connect to an rsync daemon.
|
||||
|
||||
dit(bf(secrets file)) The "secrets file" option specifies the name of
|
||||
a file that contains the username:password pairs used for
|
||||
@@ -278,34 +309,32 @@ connection is rejected.
|
||||
|
||||
Each pattern can be in one of five forms:
|
||||
|
||||
itemize(
|
||||
quote(itemize(
|
||||
it() a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address
|
||||
of the form a:b:c::d:e:f. In this case the incoming machine's IP address
|
||||
must match exactly.
|
||||
|
||||
it() an address/mask in the form ipaddr/n where ipaddr is the IP address
|
||||
and n is the number of one bits in the netmask. All IP addresses which
|
||||
match the masked IP address will be allowed in.
|
||||
|
||||
it() an address/mask in the form ipaddr/maskaddr where ipaddr is the
|
||||
IP address and maskaddr is the netmask in dotted decimal notation for IPv4,
|
||||
or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP
|
||||
addresses which match the masked IP address will be allowed in.
|
||||
|
||||
it() a hostname. The hostname as determined by a reverse lookup will
|
||||
be matched (case insensitive) against the pattern. Only an exact
|
||||
match is allowed in.
|
||||
|
||||
it() a hostname pattern using wildcards. These are matched using the
|
||||
same rules as normal unix filename matching. If the pattern matches
|
||||
then the client is allowed in.
|
||||
)
|
||||
))
|
||||
|
||||
Note IPv6 link-local addresses can have a scope in the address specification:
|
||||
|
||||
quote(fe80::1%link1)
|
||||
quote(fe80::%link1/64)
|
||||
quote(fe80::%link1/ffff:ffff:ffff:ffff::)
|
||||
quote(
|
||||
tt( fe80::1%link1)nl()
|
||||
tt( fe80::%link1/64)nl()
|
||||
tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl()
|
||||
)
|
||||
|
||||
You can also combine "hosts allow" with a separate "hosts deny"
|
||||
option. If both options are specified then the "hosts allow" option s
|
||||
@@ -325,37 +354,51 @@ 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 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
|
||||
I/O errors have occurred in order to prevent disasterous deletion due
|
||||
ignore I/O errors on the daemon when deciding whether to run the delete
|
||||
phase of the transfer. Normally rsync skips the bf(--delete) step if any
|
||||
I/O errors have occurred in order to prevent disastrous 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.
|
||||
behavior.
|
||||
|
||||
dit(bf(ignore nonreadable)) This tells the rsync server to completely
|
||||
dit(bf(ignore nonreadable)) This tells the rsync daemon to completely
|
||||
ignore files that are not readable by the user. This is useful for
|
||||
public archives that may have some non-readable files among the
|
||||
directories, and the sysadmin doesn't want those files to be seen at all.
|
||||
|
||||
dit(bf(transfer logging)) The "transfer logging" option enables per-file
|
||||
logging of downloads and uploads in a format somewhat similar to that
|
||||
used by ftp daemons. If you want to customize the log formats look at
|
||||
the log format option.
|
||||
used by ftp daemons. The daemon always logs the transfer at the end, so
|
||||
if a transfer is aborted, no mention will be made in the log file.
|
||||
|
||||
If you want to customize the log lines, see the "log format" option.
|
||||
|
||||
dit(bf(log format)) The "log format" option allows you to specify the
|
||||
format used for logging file transfers when transfer logging is
|
||||
enabled. The format is a text string containing embedded single
|
||||
character escape sequences prefixed with a percent (%) character.
|
||||
format used for logging file transfers when transfer logging is enabled.
|
||||
The format is a text string containing embedded single-character escape
|
||||
sequences prefixed with a percent (%) character. An optional numeric
|
||||
field width may also be specified between the percent and the escape
|
||||
letter (e.g. "%-50n %8l %07p").
|
||||
|
||||
The prefixes that are understood are:
|
||||
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
|
||||
is always prefixed when using the "log file" option.
|
||||
(A perl script that will summarize this default log format is included
|
||||
in the rsync source code distribution in the "support" subdirectory:
|
||||
rsyncstats.)
|
||||
|
||||
itemize(
|
||||
The single-character escapes that are understood are as follows:
|
||||
|
||||
quote(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() %o for the operation, which is either "send" or "recv"
|
||||
it() %f for the filename
|
||||
it() %o for the operation, which is "send", "recv", or "del."
|
||||
(the latter includes the trailing period)
|
||||
it() %f for the filename (long form on sender; no trailing "/")
|
||||
it() %n for the filename (short form; trailing "/" on dir)
|
||||
it() %L either the string " -> SYMLINK", or " => HARDLINK" or an
|
||||
empty string (where bf(SYMLINK) or bf(HARDLINK) is a filename)
|
||||
it() %P for the module path
|
||||
it() %m for the module name
|
||||
it() %t for the current date time
|
||||
@@ -363,32 +406,41 @@ itemize(
|
||||
it() %b for the number of bytes actually transferred
|
||||
it() %c when sending files this gives the number of checksum bytes
|
||||
received for this file
|
||||
)
|
||||
it() %i an itemized list of what is being updated
|
||||
))
|
||||
|
||||
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
|
||||
is always added to the beginning when using the "log file" option.
|
||||
For a list of what the characters mean that are output by "%i", see the
|
||||
bf(--itemize-changes) option in the rsync manpage.
|
||||
|
||||
A perl script called rsyncstats to summarize this format is included
|
||||
in the rsync source code distribution.
|
||||
Note that some of the logged output changes when talking with older
|
||||
rsync versions. For instance, deleted files were only output as verbose
|
||||
messages prior to rsync 2.6.4.
|
||||
|
||||
dit(bf(timeout)) The "timeout" option allows you to override the
|
||||
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
|
||||
default. A good choice for anonymous rsync daemons 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.
|
||||
be refused by your rsync daemon.
|
||||
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":
|
||||
For example, this would refuse bf(--checksum) (bf(-c)) and all the various
|
||||
delete options:
|
||||
|
||||
quote(refuse options = c delete*)
|
||||
quote(tt( refuse options = c delete))
|
||||
|
||||
When an option is refused, the server prints an error message and exits.
|
||||
The reason the above refuses all delete options is that the options imply
|
||||
bf(--delete), and implied options are refused just like explicit options.
|
||||
As an additional safety feature, the refusal of "delete" also refuses
|
||||
bf(remove-sent-files) when the daemon is the sender; if you want the latter
|
||||
without the former, instead refuse "delete-*" -- that refuses all the
|
||||
delete modes without affecting bf(--remove-sent-files).
|
||||
|
||||
When an option is refused, the daemon 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
|
||||
client that requests compression.
|
||||
@@ -403,7 +455,7 @@ 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.
|
||||
|
||||
The default setting is verb(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
|
||||
The default setting is tt(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
|
||||
|
||||
enddit()
|
||||
|
||||
@@ -416,7 +468,7 @@ realize that this is not a "military strength" authentication system.
|
||||
It should be good enough for most purposes but if you want really top
|
||||
quality security then I recommend that you run rsync over ssh.
|
||||
|
||||
Also note that the rsync server protocol does not currently provide any
|
||||
Also note that the rsync daemon protocol does not currently provide any
|
||||
encryption of the data that is transferred over the connection. Only
|
||||
authentication is provided. Use ssh as the transport if you want
|
||||
encryption.
|
||||
@@ -424,31 +476,31 @@ encryption.
|
||||
Future versions of rsync may support SSL for better authentication and
|
||||
encryption, but that is still being investigated.
|
||||
|
||||
manpagesection(RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM)
|
||||
manpagesection(RUNNING AN RSYNC DAEMON OVER A REMOTE SHELL PROGRAM)
|
||||
|
||||
If rsync is run with both the --daemon and --rsh (-e) options, it will
|
||||
If rsync is run with both the bf(--daemon) and bf(--rsh) (bf(-e)) options, it will
|
||||
spawn an rsync daemon using a remote shell connection. Several
|
||||
configuration options will not be available unless the remote user is
|
||||
root (e.g. chroot, setuid/setgid, etc.). There is no need to configure
|
||||
inetd or the services map to include the rsync server port if you run an
|
||||
rsync server only via a remote shell program.
|
||||
inetd or the services map to include the rsync daemon port if you run an
|
||||
rsync daemon only via a remote shell program.
|
||||
|
||||
ADVANCED: To run an rsync server out of a single-use ssh key, use the
|
||||
ADVANCED: To run an rsync daemon out of a single-use ssh key, use the
|
||||
"command=em(COMMAND)" syntax in the remote user's authorized_keys entry,
|
||||
where command would be
|
||||
|
||||
quote(rsync --server --daemon .)
|
||||
quote(tt(rsync --server --daemon .))
|
||||
|
||||
NOTE: rsync's argument parsing expects the trailing ".", so make sure
|
||||
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):
|
||||
bf(--config) option to the em(command):
|
||||
|
||||
quote(rsync --server --daemon --config=em(file) .)
|
||||
quote(tt(rsync --server --daemon --config=em(file) .))
|
||||
|
||||
Note that the "--server" here is the internal option that rsync uses to
|
||||
run the remote version of rsync that it communicates with, and thus you
|
||||
should not be using the --server option under normal circumstances.
|
||||
should not be using the bf(--server) option under normal circumstances.
|
||||
|
||||
manpagesection(EXAMPLES)
|
||||
|
||||
@@ -461,17 +513,17 @@ verb(
|
||||
comment = ftp export area
|
||||
)
|
||||
|
||||
|
||||
A more sophisticated example would be:
|
||||
|
||||
uid = nobody nl()
|
||||
gid = nobody nl()
|
||||
use chroot = no nl()
|
||||
max connections = 4 nl()
|
||||
syslog facility = local5 nl()
|
||||
verb(
|
||||
uid = nobody
|
||||
gid = nobody
|
||||
use chroot = no
|
||||
max connections = 4
|
||||
syslog facility = local5
|
||||
pid file = /var/run/rsyncd.pid
|
||||
|
||||
verb([ftp]
|
||||
[ftp]
|
||||
path = /var/ftp/pub
|
||||
comment = whole ftp area (approx 6.1 GB)
|
||||
|
||||
@@ -496,8 +548,10 @@ verb([ftp]
|
||||
|
||||
The /etc/rsyncd.secrets file would look something like this:
|
||||
|
||||
tridge:mypass nl()
|
||||
susan:herpass
|
||||
quote(
|
||||
tt(tridge:mypass)nl()
|
||||
tt(susan:herpass)nl()
|
||||
)
|
||||
|
||||
manpagefiles()
|
||||
|
||||
@@ -511,15 +565,12 @@ manpagediagnostics()
|
||||
|
||||
manpagebugs()
|
||||
|
||||
The rsync server does not send all types of error messages to the
|
||||
client. this means a client may be mystified as to why a transfer
|
||||
failed. The error will have been logged by syslog on the server.
|
||||
|
||||
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.x of rsync.
|
||||
|
||||
This man page is current for version 2.6.5 of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
@@ -540,12 +591,13 @@ Gailly and Mark Adler.
|
||||
manpagesection(THANKS)
|
||||
|
||||
Thanks to Warren Stanley for his original idea and patch for the rsync
|
||||
server. Thanks to Karsten Thygesen for his many suggestions and
|
||||
daemon. Thanks to Karsten Thygesen for his many suggestions and
|
||||
documentation!
|
||||
|
||||
manpageauthor()
|
||||
|
||||
rsync was written by Andrew Tridgell and Paul Mackerras. They may be
|
||||
contacted via email at tridge@samba.org and
|
||||
Paul.Mackerras@cs.anu.edu.au
|
||||
rsync was written by Andrew Tridgell and Paul Mackerras.
|
||||
Many people have later contributed to it.
|
||||
|
||||
Mailing lists for support and development are available at
|
||||
url(http://lists.samba.org)(lists.samba.org)
|
||||
|
||||
36
runtests.sh
36
runtests.sh
@@ -126,12 +126,10 @@ set -e
|
||||
RUNSHFLAGS='-e'
|
||||
|
||||
# for Solaris
|
||||
PATH="/usr/xpg4/bin/:$PATH"
|
||||
[ -d /usr/xpg4/bin ] && PATH="/usr/xpg4/bin/:$PATH"
|
||||
|
||||
if [ -n "$loglevel" ] && [ "$loglevel" -gt 8 ]
|
||||
then
|
||||
if set -x
|
||||
then
|
||||
if [ "x$loglevel" != x ] && [ "$loglevel" -gt 8 ]; then
|
||||
if set -x; then
|
||||
# If it doesn't work the first time, don't keep trying.
|
||||
RUNSHFLAGS="$RUNSHFLAGS -x"
|
||||
fi
|
||||
@@ -142,33 +140,39 @@ echo "$0 running in `pwd`"
|
||||
echo " rsync_bin=$rsync_bin"
|
||||
echo " srcdir=$srcdir"
|
||||
|
||||
testuser=`id -un || whoami || echo UNKNOWN`
|
||||
if [ -f /usr/bin/whoami ]; then
|
||||
testuser=`/usr/bin/whoami`
|
||||
elif [ -f /usr/ucb/whoami ]; then
|
||||
testuser=`/usr/ucb/whoami`
|
||||
elif [ -f /bin/whoami ]; then
|
||||
testuser=`/bin/whoami`
|
||||
else
|
||||
testuser=`id -un 2>/dev/null || echo ${LOGNAME:-${USERNAME:-${USER:-'UNKNOWN'}}}`
|
||||
fi
|
||||
|
||||
echo " testuser=$testuser"
|
||||
echo " os=`uname -a`"
|
||||
|
||||
# It must be "yes", not just nonnull
|
||||
if test "x$preserve_scratch" = xyes
|
||||
then
|
||||
if [ "x$preserve_scratch" = xyes ]; then
|
||||
echo " preserve_scratch=yes"
|
||||
else
|
||||
echo " preserve_scratch=no"
|
||||
fi
|
||||
|
||||
|
||||
if test ! -f $rsync_bin
|
||||
then
|
||||
if [ ! -f "$rsync_bin" ]; then
|
||||
echo "rsync_bin $rsync_bin is not a file" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if test ! -d $srcdir
|
||||
then
|
||||
if [ ! -d "$srcdir" ]; then
|
||||
echo "srcdir $srcdir is not a directory" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
RSYNC="$rsync_bin"
|
||||
#RSYNC="valgrind --tool=addrcheck $rsync_bin"
|
||||
|
||||
export rsync_bin RSYNC
|
||||
|
||||
@@ -198,14 +202,13 @@ maybe_discard_scratch() {
|
||||
return 0
|
||||
}
|
||||
|
||||
if [ "x$whichtests" = x ]
|
||||
then
|
||||
if [ "x$whichtests" = x ]; then
|
||||
whichtests="*.test"
|
||||
fi
|
||||
|
||||
for testscript in $suitedir/$whichtests
|
||||
do
|
||||
testbase=`echo $testscript | sed 's!.*/!!' | sed -e 's/.test\$//'`
|
||||
testbase=`echo $testscript | sed -e 's!.*/!!' -e 's/.test\$//'`
|
||||
scratchdir="$scratchbase.$testbase"
|
||||
|
||||
prep_scratch
|
||||
@@ -250,8 +253,7 @@ do
|
||||
*)
|
||||
echo "FAIL $testbase"
|
||||
failed=`expr $failed + 1`
|
||||
if [ "x$nopersist" = "xyes" ]
|
||||
then
|
||||
if [ "x$nopersist" = xyes ]; then
|
||||
exit 1
|
||||
fi
|
||||
esac
|
||||
|
||||
237
sender.c
237
sender.c
@@ -20,15 +20,26 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int csum_length;
|
||||
extern struct stats stats;
|
||||
extern int io_error;
|
||||
extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int log_before_transfer;
|
||||
extern int log_format_has_i;
|
||||
extern int daemon_log_format_has_i;
|
||||
extern int csum_length;
|
||||
extern int io_error;
|
||||
extern int allowed_lull;
|
||||
extern int protocol_version;
|
||||
extern int remove_sent_files;
|
||||
extern int updating_basis_file;
|
||||
extern int make_backups;
|
||||
extern int do_progress;
|
||||
extern int inplace;
|
||||
extern int batch_fd;
|
||||
extern int write_batch;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *the_file_list;
|
||||
extern char *log_format;
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,22 +49,6 @@ extern struct stats stats;
|
||||
* 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)
|
||||
{
|
||||
sum->count = read_int(f);
|
||||
sum->blength = read_int(f);
|
||||
if (protocol_version < 27) {
|
||||
sum->s2length = csum_length;
|
||||
} else {
|
||||
sum->s2length = read_int(f);
|
||||
if (sum->s2length > MD4_SUM_LENGTH) {
|
||||
rprintf(FERROR, "Invalid checksum length %ld\n",
|
||||
(long)sum->s2length);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
sum->remainder = read_int(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive the checksums for a buffer
|
||||
@@ -61,7 +56,8 @@ void read_sum_head(int f, struct sum_struct *sum)
|
||||
static struct sum_struct *receive_sums(int f)
|
||||
{
|
||||
struct sum_struct *s;
|
||||
int i;
|
||||
int32 i;
|
||||
int lull_mod = allowed_lull * 5;
|
||||
OFF_T offset = 0;
|
||||
|
||||
if (!(s = new(struct sum_struct)))
|
||||
@@ -72,8 +68,8 @@ static struct sum_struct *receive_sums(int f)
|
||||
s->sums = NULL;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "count=%ld n=%u rem=%u\n",
|
||||
(long)s->count, s->blength, s->remainder);
|
||||
rprintf(FINFO, "count=%.0f n=%ld rem=%ld\n",
|
||||
(double)s->count, (long)s->blength, (long)s->remainder);
|
||||
}
|
||||
|
||||
if (s->count == 0)
|
||||
@@ -82,19 +78,22 @@ static struct sum_struct *receive_sums(int f)
|
||||
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 < 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].flags = 0;
|
||||
|
||||
if (i == (int)s->count-1 && s->remainder != 0)
|
||||
if (i == s->count-1 && s->remainder != 0)
|
||||
s->sums[i].len = s->remainder;
|
||||
else
|
||||
s->sums[i].len = s->blength;
|
||||
offset += s->sums[i].len;
|
||||
|
||||
if (allowed_lull && !(i % lull_mod))
|
||||
maybe_send_keepalive();
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
@@ -108,7 +107,93 @@ static struct sum_struct *receive_sums(int f)
|
||||
return s;
|
||||
}
|
||||
|
||||
void successful_send(int ndx)
|
||||
{
|
||||
char fname[MAXPATHLEN];
|
||||
struct file_struct *file;
|
||||
unsigned int offset;
|
||||
|
||||
if (ndx < 0 || ndx >= the_file_list->count)
|
||||
return;
|
||||
|
||||
file = the_file_list->files[ndx];
|
||||
/* The generator might tell us about symlinks we didn't send. */
|
||||
if (!(file->flags & FLAG_SENT) && !S_ISLNK(file->mode))
|
||||
return;
|
||||
if (file->dir.root) {
|
||||
offset = stringjoin(fname, sizeof fname,
|
||||
file->dir.root, "/", NULL);
|
||||
} else
|
||||
offset = 0;
|
||||
f_name_to(file, fname + offset);
|
||||
if (remove_sent_files && do_unlink(fname) == 0 && verbose > 1) {
|
||||
rprintf(FINFO, "sender removed %s\n",
|
||||
safe_fname(fname + offset));
|
||||
}
|
||||
}
|
||||
|
||||
static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
|
||||
uchar fnamecmp_type, char *buf, int len)
|
||||
{
|
||||
write_int(f_out, ndx);
|
||||
if (protocol_version < 29)
|
||||
return;
|
||||
write_shortint(f_out, iflags);
|
||||
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
|
||||
write_byte(f_out, fnamecmp_type);
|
||||
if (iflags & ITEM_XNAME_FOLLOWS)
|
||||
write_vstring(f_out, buf, len);
|
||||
}
|
||||
|
||||
/* This is also used by receive.c with f_out = -1. */
|
||||
int read_item_attrs(int f_in, int f_out, int ndx, uchar *type_ptr,
|
||||
char *buf, int *len_ptr)
|
||||
{
|
||||
int len;
|
||||
uchar fnamecmp_type = FNAMECMP_FNAME;
|
||||
int iflags = protocol_version >= 29 ? read_shortint(f_in)
|
||||
: ITEM_TRANSFER | ITEM_MISSING_DATA;
|
||||
|
||||
/* Handle the new keep-alive (no-op) packet. */
|
||||
if (ndx == the_file_list->count && iflags == ITEM_IS_NEW)
|
||||
;
|
||||
else if (ndx < 0 || ndx >= the_file_list->count) {
|
||||
rprintf(FERROR, "Invalid file index: %d (count=%d) [%s]\n",
|
||||
ndx, the_file_list->count, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else if (iflags == ITEM_IS_NEW) {
|
||||
rprintf(FERROR, "Invalid itemized flag word: %x [%s]\n",
|
||||
iflags, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
|
||||
fnamecmp_type = read_byte(f_in);
|
||||
*type_ptr = fnamecmp_type;
|
||||
|
||||
if (iflags & ITEM_XNAME_FOLLOWS) {
|
||||
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else {
|
||||
*buf = '\0';
|
||||
len = -1;
|
||||
}
|
||||
*len_ptr = len;
|
||||
|
||||
if (iflags & ITEM_TRANSFER) {
|
||||
if (!S_ISREG(the_file_list->files[ndx]->mode)) {
|
||||
rprintf(FERROR,
|
||||
"received request to transfer non-regular file: %d [%s]\n",
|
||||
ndx, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
} else if (f_out >= 0) {
|
||||
write_ndx_and_attrs(f_out, ndx, iflags,
|
||||
fnamecmp_type, buf, len);
|
||||
}
|
||||
|
||||
return iflags;
|
||||
}
|
||||
|
||||
void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
{
|
||||
@@ -117,12 +202,17 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
struct map_struct *mbuf = NULL;
|
||||
STRUCT_STAT st;
|
||||
char *fname2, fname[MAXPATHLEN];
|
||||
int i;
|
||||
char xname[MAXPATHLEN];
|
||||
uchar fnamecmp_type;
|
||||
int iflags, xlen;
|
||||
struct file_struct *file;
|
||||
int phase = 0;
|
||||
int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1;
|
||||
struct stats initial_stats;
|
||||
int save_make_backups = make_backups;
|
||||
int j;
|
||||
int itemizing = am_daemon ? daemon_log_format_has_i
|
||||
: !am_server && log_format_has_i;
|
||||
int f_xfer = write_batch < 0 ? batch_fd : f_out;
|
||||
int i, j;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files starting\n");
|
||||
@@ -132,35 +222,27 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
if (phase == 0) {
|
||||
phase++;
|
||||
csum_length = SUM_LENGTH;
|
||||
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;
|
||||
if (++phase > max_phase)
|
||||
break;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files phase=%d\n", phase);
|
||||
write_int(f_out, -1);
|
||||
/* For inplace: redo phase turns off the backup
|
||||
* flag so that we do a regular inplace send. */
|
||||
make_backups = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= flist->count) {
|
||||
rprintf(FERROR, "Invalid file index %d (count=%d)\n",
|
||||
i, flist->count);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
iflags = read_item_attrs(f_in, f_out, i, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (iflags == ITEM_IS_NEW) /* no-op packet */
|
||||
continue;
|
||||
|
||||
file = flist->files[i];
|
||||
|
||||
stats.current_file_index = i;
|
||||
stats.num_transferred_files++;
|
||||
stats.total_transferred_size += file->length;
|
||||
|
||||
if (file->basedir) {
|
||||
if (file->dir.root) {
|
||||
/* N.B. We're sure that this fits, so offset is OK. */
|
||||
offset = strlcpy(fname, file->basedir, sizeof fname);
|
||||
offset = strlcpy(fname, file->dir.root, sizeof fname);
|
||||
if (!offset || fname[offset-1] != '/')
|
||||
fname[offset++] = '/';
|
||||
} else
|
||||
@@ -170,10 +252,29 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
|
||||
|
||||
if (dry_run) {
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname2));
|
||||
write_int(f_out, i);
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
continue;
|
||||
}
|
||||
if (phase == 2) {
|
||||
rprintf(FERROR,
|
||||
"got transfer request in phase 2 [%s]\n",
|
||||
who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
updating_basis_file = inplace && (protocol_version >= 29
|
||||
? fnamecmp_type == FNAMECMP_FNAME : !make_backups);
|
||||
|
||||
stats.current_file_index = i;
|
||||
stats.num_transferred_files++;
|
||||
stats.total_transferred_size += file->length;
|
||||
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
if (!am_server && log_format)
|
||||
log_item(file, &stats, iflags, NULL);
|
||||
write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
|
||||
xname, xlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -214,8 +315,8 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
}
|
||||
|
||||
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);
|
||||
int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE);
|
||||
mbuf = map_file(fd, st.st_size, read_size, s->blength);
|
||||
} else
|
||||
mbuf = NULL;
|
||||
|
||||
@@ -224,21 +325,28 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
safe_fname(fname), (double)st.st_size);
|
||||
}
|
||||
|
||||
write_int(f_out, i);
|
||||
write_sum_head(f_out, s);
|
||||
write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
|
||||
xname, xlen);
|
||||
write_sum_head(f_xfer, s);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "calling match_sums %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
if (log_before_transfer)
|
||||
log_item(file, &initial_stats, iflags, NULL);
|
||||
else if (!am_server && verbose && do_progress)
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname2));
|
||||
|
||||
set_compression(fname);
|
||||
|
||||
match_sums(f_out, s, mbuf, st.st_size);
|
||||
log_send(file, &initial_stats);
|
||||
match_sums(f_xfer, s, mbuf, st.st_size);
|
||||
if (do_progress)
|
||||
end_progress(st.st_size);
|
||||
|
||||
if (!log_before_transfer)
|
||||
log_item(file, &initial_stats, iflags, NULL);
|
||||
|
||||
if (mbuf) {
|
||||
j = unmap_file(mbuf);
|
||||
@@ -257,6 +365,9 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
rprintf(FINFO, "sender finished %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
|
||||
/* Flag that we actually sent this entry. */
|
||||
file->flags |= FLAG_SENT;
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
|
||||
|
||||
53
socket.c
53
socket.c
@@ -90,7 +90,7 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
if (*cp == '\r')
|
||||
*cp = '\0';
|
||||
if (strncmp(buffer, "HTTP/", 5) != 0) {
|
||||
rprintf(FERROR, "bad response from proxy - %s\n",
|
||||
rprintf(FERROR, "bad response from proxy -- %s\n",
|
||||
buffer);
|
||||
return -1;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
while (*cp == ' ')
|
||||
cp++;
|
||||
if (*cp != '2') {
|
||||
rprintf(FERROR, "bad response from proxy - %s\n",
|
||||
rprintf(FERROR, "bad response from proxy -- %s\n",
|
||||
buffer);
|
||||
return -1;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
* if this fails.
|
||||
**/
|
||||
int try_bind_local(int s, int ai_family, int ai_socktype,
|
||||
const char *bind_address)
|
||||
const char *bind_addr)
|
||||
{
|
||||
int error;
|
||||
struct addrinfo bhints, *bres_all, *r;
|
||||
@@ -136,9 +136,9 @@ int try_bind_local(int s, int ai_family, int ai_socktype,
|
||||
bhints.ai_family = ai_family;
|
||||
bhints.ai_socktype = ai_socktype;
|
||||
bhints.ai_flags = AI_PASSIVE;
|
||||
if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) {
|
||||
if ((error = getaddrinfo(bind_addr, NULL, &bhints, &bres_all))) {
|
||||
rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
|
||||
bind_address, gai_strerror(error));
|
||||
bind_addr, gai_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -172,12 +172,12 @@ int try_bind_local(int s, int ai_family, int ai_socktype,
|
||||
* reachable, perhaps because we can't e.g. route ipv6 to that network
|
||||
* but we can get ip4 packets through.
|
||||
*
|
||||
* @param bind_address Local address to use. Normally NULL to bind
|
||||
* @param bind_addr Local address to use. Normally NULL to bind
|
||||
* the wildcard address.
|
||||
*
|
||||
* @param af_hint Address family, e.g. AF_INET or AF_INET6.
|
||||
**/
|
||||
int open_socket_out(char *host, int port, const char *bind_address,
|
||||
int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
int type = SOCK_STREAM;
|
||||
@@ -198,7 +198,7 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
strlcpy(buffer, h, sizeof buffer);
|
||||
|
||||
/* Is the USER:PASS@ prefix present? */
|
||||
if ((cp = strchr(buffer, '@')) != NULL) {
|
||||
if ((cp = strrchr(buffer, '@')) != NULL) {
|
||||
*cp++ = '\0';
|
||||
/* The remainder is the HOST:PORT part. */
|
||||
h = cp;
|
||||
@@ -253,9 +253,9 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
if (s < 0)
|
||||
continue;
|
||||
|
||||
if (bind_address
|
||||
if (bind_addr
|
||||
&& try_bind_local(s, res->ai_family, type,
|
||||
bind_address) == -1) {
|
||||
bind_addr) == -1) {
|
||||
close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
@@ -293,9 +293,9 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
*
|
||||
* This is based on the Samba LIBSMB_PROG feature.
|
||||
*
|
||||
* @param bind_address Local address to use. Normally NULL to get the stack default.
|
||||
* @param bind_addr 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 open_socket_out_wrapped(char *host, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
char *prog = getenv("RSYNC_CONNECT_PROG");
|
||||
@@ -307,7 +307,7 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
|
||||
}
|
||||
if (prog)
|
||||
return sock_exec(prog);
|
||||
return open_socket_out(host, port, bind_address, af_hint);
|
||||
return open_socket_out(host, port, bind_addr, af_hint);
|
||||
}
|
||||
|
||||
|
||||
@@ -322,10 +322,10 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
|
||||
* We return an array of file-descriptors to the sockets, with a trailing
|
||||
* -1 value to indicate the end of the list.
|
||||
*
|
||||
* @param bind_address Local address to bind, or NULL to allow it to
|
||||
* @param bind_addr Local address to bind, or NULL to allow it to
|
||||
* default.
|
||||
**/
|
||||
static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
int one = 1;
|
||||
@@ -339,10 +339,10 @@ static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
hints.ai_socktype = type;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
snprintf(portbuf, sizeof portbuf, "%d", port);
|
||||
error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
|
||||
error = getaddrinfo(bind_addr, portbuf, &hints, &all_ai);
|
||||
if (error) {
|
||||
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
|
||||
bind_address, gai_strerror(error));
|
||||
bind_addr, gai_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
#ifdef INET6
|
||||
if (errno == EADDRINUSE && i > 0) {
|
||||
rprintf(FINFO,
|
||||
"Try using --ipv4 or --ipv6 to avoid this listen() error.");
|
||||
"Try using --ipv4 or --ipv6 to avoid this listen() error.\n");
|
||||
}
|
||||
#endif
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
@@ -478,7 +478,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
/* close log file before the potentially very long select so
|
||||
* file can be trimmed by another process instead of growing
|
||||
* forever */
|
||||
log_close();
|
||||
logfile_close();
|
||||
|
||||
#ifdef FD_COPY
|
||||
FD_COPY(&deffds, &fds);
|
||||
@@ -506,9 +506,9 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
int ret;
|
||||
for (i = 0; sp[i] >= 0; i++)
|
||||
close(sp[i]);
|
||||
/* open log file in child before possibly giving
|
||||
* up privileges */
|
||||
log_open();
|
||||
/* Re-open log file in child before possibly giving
|
||||
* up privileges (see logfile_close() above). */
|
||||
logfile_reopen();
|
||||
ret = fn(fd, fd);
|
||||
close_all();
|
||||
_exit(ret);
|
||||
@@ -525,7 +525,6 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
|
||||
@@ -620,7 +619,7 @@ void set_socket_options(int fd, char *options)
|
||||
|
||||
case OPT_ON:
|
||||
if (got_value)
|
||||
rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
|
||||
rprintf(FERROR,"syntax error -- %s does not take a value\n",tok);
|
||||
|
||||
{
|
||||
int on = socket_options[i].value;
|
||||
@@ -654,14 +653,12 @@ void become_daemon(void)
|
||||
/* detach from the terminal */
|
||||
#ifdef HAVE_SETSID
|
||||
setsid();
|
||||
#else
|
||||
#ifdef TIOCNOTTY
|
||||
#elif defined TIOCNOTTY
|
||||
i = open("/dev/tty", O_RDWR);
|
||||
if (i >= 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) */
|
||||
@@ -697,7 +694,7 @@ static int socketpair_tcp(int fd[2])
|
||||
goto failed;
|
||||
|
||||
memset(&sock2, 0, sizeof sock2);
|
||||
#if HAVE_SOCKADDR_IN_LEN
|
||||
#ifdef HAVE_SOCKADDR_IN_LEN
|
||||
sock2.sin_len = sizeof sock2;
|
||||
#endif
|
||||
sock2.sin_family = PF_INET;
|
||||
|
||||
6
support/Makefile
Normal file
6
support/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
all: savetransfer
|
||||
|
||||
savetransfer: savetransfer.o
|
||||
|
||||
clean:
|
||||
rm -f *.o savetransfer
|
||||
90
support/atomic-rsync
Executable file
90
support/atomic-rsync
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# This script lets you update a hierarchy of files in an atomic way by
|
||||
# first creating a new hierarchy using rsync's --link-dest option, and
|
||||
# then swapping the hierarchy into place. **See the usage message for
|
||||
# more details and some important caveats!**
|
||||
|
||||
use strict;
|
||||
use Cwd 'abs_path';
|
||||
|
||||
my $RSYNC_PROG = '/usr/bin/rsync';
|
||||
my $RM_PROG = '/bin/rm';
|
||||
|
||||
my $dest_dir = $ARGV[-1];
|
||||
usage(1) if $dest_dir eq '' || $dest_dir =~ /^--/;
|
||||
|
||||
if (!-d $dest_dir) {
|
||||
print STDERR "$dest_dir is not a directory.\n\n";
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if (@_ = grep(/^--(link|compare)-dest/, @ARGV)) {
|
||||
$_ = join(' or ', @_);
|
||||
print STDERR "You may not use $_ as an rsync option.\n\n";
|
||||
usage(1);
|
||||
}
|
||||
|
||||
$dest_dir = abs_path($dest_dir);
|
||||
if ($dest_dir eq '/') {
|
||||
print STDERR 'You must not use "/" as the destination directory.', "\n\n";
|
||||
usage(1);
|
||||
}
|
||||
|
||||
my $old_dir = "$dest_dir~old~";
|
||||
my $new_dir = $ARGV[-1] = "$dest_dir~new~";
|
||||
|
||||
system($RM_PROG, '-rf', $old_dir) if -d $old_dir;
|
||||
|
||||
if (system($RSYNC_PROG, "--link-dest=$dest_dir", @ARGV)) {
|
||||
if ($? == -1) {
|
||||
print "failed to execute $RSYNC_PROG: $!\n";
|
||||
} elsif ($? & 127) {
|
||||
printf "child died with signal %d, %s coredump\n",
|
||||
($? & 127), ($? & 128) ? 'with' : 'without';
|
||||
} else {
|
||||
printf "child exited with value %d\n", $? >> 8;
|
||||
}
|
||||
exit $?;
|
||||
}
|
||||
|
||||
rename($dest_dir, $old_dir) or die "Unable to rename $new_dir to $old_dir: $!";
|
||||
rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!";
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
my($ret) = @_;
|
||||
my $fh = $ret ? *STDERR : *STDOUT;
|
||||
print $fh <<EOT;
|
||||
Usage: atomic-rsync [RSYNC-OPTIONS] HOST:/SOURCE/DIR/ /DEST/DIR/
|
||||
atomic-rsync [RSYNC-OPTIONS] HOST::MOD/DIR/ /DEST/DIR/
|
||||
|
||||
This script lets you update a hierarchy of files in an atomic way by first
|
||||
creating a new hierarchy (using hard-links to leverage the existing files),
|
||||
and then swapping the new hierarchy into place. You must be pulling files
|
||||
to a local directory, and that directory must already exist. For example:
|
||||
|
||||
atomic-rsync -av host:/remote/files/ /local/files/
|
||||
|
||||
This would make the transfer to the directory /local/files~new~ and then
|
||||
swap out /local/files at the end of the transfer by renaming it to
|
||||
/local/files~old~ and putting the new directory into its place. The
|
||||
/local/files~old~ directory will be preserved until the next update, at
|
||||
which point it will be deleted.
|
||||
|
||||
Do NOT specify this command:
|
||||
|
||||
atomic-rsync -av host:/remote/files /local/
|
||||
|
||||
... UNLESS you want the entire /local dir to be swapped out!
|
||||
|
||||
See the "rsync" command for its list of options. You may not use the
|
||||
--link-dest or --compare-dest options (since this script uses --link-dest
|
||||
to make the transfer efficient). Also, the destination directory cannot
|
||||
be "/".
|
||||
EOT
|
||||
exit $ret;
|
||||
}
|
||||
42
support/cvs2includes
Executable file
42
support/cvs2includes
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# This script finds all CVS/Entries files in the current directory and below
|
||||
# and creates a local .cvsinclude file with non-inherited rules including each
|
||||
# checked-in file. Then, use this option whenever using --cvs-exclude (-C):
|
||||
#
|
||||
# -f ': .cvsinclude'
|
||||
#
|
||||
# That ensures that all checked-in files/dirs are included in the transfer.
|
||||
# (You could alternately put ": .cvsinclude" into an .rsync-filter file and
|
||||
# use the -F option, which is easier to type.)
|
||||
#
|
||||
# The downside is that you need to remember to re-run cvs2includes whenever
|
||||
# You add a new file to the project.
|
||||
use strict;
|
||||
|
||||
open(FIND, 'find . -name CVS -type d |') or die $!;
|
||||
while (<FIND>) {
|
||||
chomp;
|
||||
s#^\./##;
|
||||
|
||||
my $entries = "$_/Entries";
|
||||
s/CVS$/.cvsinclude/;
|
||||
my $filter = $_;
|
||||
|
||||
open(ENTRIES, $entries) or die "Unable to open $entries: $!\n";
|
||||
my @includes;
|
||||
while (<ENTRIES>) {
|
||||
push(@includes, $1) if m#/(.+?)/#;
|
||||
}
|
||||
close ENTRIES;
|
||||
if (@includes) {
|
||||
open(FILTER, ">$filter") or die "Unable to write $filter: $!\n";
|
||||
print FILTER '+ /', join("\n+ /", @includes), "\n";
|
||||
close FILTER;
|
||||
print "Updated $filter\n";
|
||||
} elsif (-f $filter) {
|
||||
unlink($filter);
|
||||
print "Removed $filter\n";
|
||||
}
|
||||
}
|
||||
close FIND;
|
||||
44
support/mnt-excl
Executable file
44
support/mnt-excl
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/perl -w
|
||||
# This script takes a command-line arg of a source directory
|
||||
# that will be passed to rsync, and generates a set of excludes
|
||||
# that will exclude all mount points from the list. This is
|
||||
# useful if you have "bind" mounts since the --one-file-system
|
||||
# option won't notice the transition to a different spot on
|
||||
# the same disk. For example:
|
||||
#
|
||||
# mnt-excl /dir | rsync --exclude-from=- ... /dir /dest/
|
||||
# mnt-excl /dir/ | rsync --exclude-from=- ... /dir/ /dest/
|
||||
# ssh host mnt-excl /dir | rsync --exclude-from=- ... host:/dir /dest/
|
||||
#
|
||||
# Imagine that /dir/foo is a mount point: the first invocation of
|
||||
# mnt-excl would have output /dir/foo, while the second would have
|
||||
# output /foo (which are the properly anchored excludes).
|
||||
#
|
||||
# NOTE: This script expects /proc/mounts to exist, but could be
|
||||
# easily adapted to read /etc/mtab or similar.
|
||||
#
|
||||
# ADDENDUM: The addition of the --filter option (which has support for
|
||||
# absolute-anchored excludes) has made this script less useful than it
|
||||
# was. Beginning with 2.6.4, you can achieve the effect of this script
|
||||
# through this command:
|
||||
#
|
||||
# awk '{print $2}' /proc/mounts | rsync -f 'merge,/- -' host:/dir /dest/
|
||||
|
||||
use strict;
|
||||
use Cwd 'abs_path';
|
||||
|
||||
my $file = '/proc/mounts';
|
||||
my $dir = shift || '/';
|
||||
$dir = abs_path($dir);
|
||||
$dir =~ s#([^/]*)$##;
|
||||
my $trailing = $1;
|
||||
$trailing = '' if $trailing eq '.' || !-d "$dir$trailing";
|
||||
$trailing .= '/' if $trailing ne '';
|
||||
|
||||
open(IN, $file) or die "Unable to open $file: $!\n";
|
||||
while (<IN>) {
|
||||
$_ = (split)[1];
|
||||
next unless s#^\Q$dir$trailing\E##o && $_ ne '';
|
||||
print "- /$trailing$_\n";
|
||||
}
|
||||
close IN;
|
||||
74
support/rrsync
Normal file
74
support/rrsync
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/perl
|
||||
# Name: /usr/local/bin/rrsync (should also have a symlink in /usr/bin)
|
||||
# Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys
|
||||
# Author: Joe Smith <js-cgi@inwap.com> 30-Sep-2004
|
||||
# Modified by Wayne Davison <wayned@samba.org> 12-Jan-2005
|
||||
|
||||
use Socket;
|
||||
use constant LOGFILE => 'rrsync.log';
|
||||
my $Usage = <<EOM;
|
||||
Use 'command="$0 [-ro] SUBDIR"'
|
||||
in front of lines in $ENV{HOME}/.ssh/authorized_keys
|
||||
EOM
|
||||
|
||||
my $ro = (@ARGV and $ARGV[0] eq '-ro') ? shift : ''; # -ro = Read-Only
|
||||
my $subdir = shift;
|
||||
die "No subdirectory specified\n$Usage" unless defined $subdir;
|
||||
|
||||
# The client uses "rsync -av -e ssh src/ server:dir/", and sshd on the server
|
||||
# executes this program when .ssh/authorized_keys has 'command="..."'.
|
||||
# For example:
|
||||
# command="rrsync logs/client" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzGhEeNlPr...
|
||||
# command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmkHG1WCjC...
|
||||
#
|
||||
# Format of the envrionment variables set by sshd:
|
||||
# SSH_ORIGINAL_COMMAND=rsync --server -vlogDtpr --partial . dir # push
|
||||
# SSH_ORIGINAL_COMMAND=rsync --server --sender -vlogDtpr --partial . dir # pull
|
||||
# SSH_CONNECTION=client_addr client_port server_port
|
||||
|
||||
my $command = $ENV{SSH_ORIGINAL_COMMAND};
|
||||
die "Not invoked via sshd\n$Usage" unless defined $command;
|
||||
die "SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $command =~ /^rsync\s/;
|
||||
die "$0 -ro: sending to read-only server not allowed\n"
|
||||
if $ro and $command !~ /^rsync --server --sender /;
|
||||
die "$0 -ro: use of $1 with read-only server not allowed\n"
|
||||
if $ro and $command =~ /\s(--remove-\S+)/;
|
||||
|
||||
my ($cmd,$dir) = $command =~ /^(rsync\s+(?:-[-a-zA-Z]+\s+)+\.) ?("[^"]*"|[^\s"]*)$/;
|
||||
die "$0: invalid rsync-command syntax or options\n" if !defined $cmd;
|
||||
|
||||
# Enforce default of $subdir instead of the normal $HOME default.
|
||||
my $orig = $dir;
|
||||
my @dirs;
|
||||
$dir =~ s/^"(.*?)"$/$1/;
|
||||
$dir =~ s/^\s+//;
|
||||
$dir =~ s/\s+$//;
|
||||
foreach (split(/(?<!\\)\s+/, $dir)) {
|
||||
s/\\(\s)/$1/g; # Unescape any escaped whitespace
|
||||
if ($subdir eq '/') { # Less checking for '/' access
|
||||
$dir = '/' if $dir eq '';
|
||||
} else {
|
||||
s#^/##; # Don't allow absolute paths
|
||||
$_ = "$subdir/$_" unless m#^\Q$subdir\E(/|$)#;
|
||||
1 while s#/\.\.(/|$)#/__/#g; # Don't allow foo/../../etc
|
||||
}
|
||||
tr#-_/a-zA-Z0-9.,+@^%: #_#c; # Don't allow '"&;|!=()[]{}<>*?#\$
|
||||
s/(\s)/\\$1/g; # Re-escape whitespace
|
||||
push(@dirs, $_);
|
||||
}
|
||||
push(@dirs, $subdir) unless @dirs;
|
||||
$dir = join(' ', @dirs);
|
||||
|
||||
if (-f LOGFILE and open LOG,'>>',LOGFILE) {
|
||||
my ($mm,$hh) = (localtime)[1,2];
|
||||
my $host = $ENV{SSH_CONNECTION} || 'unknown';
|
||||
$host =~ s/ .*//; # Keep only the client's IP addr
|
||||
$host =~ s/^::ffff://;
|
||||
$host = gethostbyaddr(inet_aton($host),AF_INET) || $host;
|
||||
my $dir_result = $dir eq $orig ? " OK" : "> \"$dir\"";
|
||||
printf LOG "%02d:%02d %-13s [%s] =%s\n", $hh, $mm, $host, $command, $dir_result;
|
||||
close LOG;
|
||||
}
|
||||
|
||||
exec "$cmd \"$dir\"" or die "exec($cmd \"$dir\") failed: $? $!";
|
||||
# Note: This assumes that the rsync protocol will not be maliciously hijacked.
|
||||
@@ -1,72 +1,67 @@
|
||||
#! /usr/bin/perl
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# USAGE: rsyncstats <options>
|
||||
#
|
||||
# OPTIONS:
|
||||
# -f <filename> Use <filename> for the log file
|
||||
# -h include report on hourly traffic
|
||||
# -d include report on domain traffic
|
||||
# -t report on total traffic by section
|
||||
# -D <domain> report only on traffic from <domain>
|
||||
# -l <depth> Depth of path detail for sections
|
||||
# -s <section> Section to report on, For example: -s /pub will report
|
||||
# only on paths under /pub
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# This script parses the default logfile format produced by rsync when running
|
||||
# as a daemon with transfer logging enabled. It is derived from the xferstats
|
||||
# script that comes with wuftpd
|
||||
# as a daemon with transfer logging enabled. It also parses a slightly tweaked
|
||||
# version of the default format where %o has been replaced with %i.
|
||||
#
|
||||
# This script is derived from the xferstats script that comes with wuftpd. See
|
||||
# the usage message at the bottom for the options it takes.
|
||||
#
|
||||
# Andrew Tridgell, October 1998
|
||||
# rsync-bugs@samba.org
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# edit the next line to customize for your default log file
|
||||
use Getopt::Long;
|
||||
|
||||
# You may wish to edit the next line to customize for your default log file.
|
||||
$usage_file = "/var/adm/rsyncd.log";
|
||||
|
||||
# Edit the following lines for default report settings.
|
||||
# Entries defined here will be over-ridden by the command line.
|
||||
|
||||
$opt_h = 1;
|
||||
$opt_d = 0;
|
||||
$opt_t = 1;
|
||||
$opt_l = 2;
|
||||
$hourly_report = 0;
|
||||
$domain_report = 0;
|
||||
$total_report = 0;
|
||||
$depth_limit = 9999;
|
||||
$only_section = '';
|
||||
|
||||
require 'getopts.pl';
|
||||
&Getopts('f:rahdD:l:s:');
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'hourly-report|h' => \$hourly_report,
|
||||
'domain-report|d' => \$domain_report,
|
||||
'domain|D:s' => \$only_domain,
|
||||
'total-report|t' => \$total_report,
|
||||
'depth-limit|l:i' => \$depth_limit,
|
||||
'real|r' => \$real,
|
||||
'anon|a' => \$anon,
|
||||
'section|s:s' => \$only_section,
|
||||
'file|f:s' => \$usage_file,
|
||||
);
|
||||
|
||||
if ($opt_r) { $real = 1;}
|
||||
if ($opt_a) { $anon = 1;}
|
||||
if ($real == 0 && $anon == 0) { $anon = 1; }
|
||||
if ($opt_f) {$usage_file = $opt_f;}
|
||||
$anon = 1 if !$real && !$anon;
|
||||
|
||||
open (LOG,$usage_file) || die "Error opening usage log file: $usage_file\n";
|
||||
open(LOG, $usage_file) || die "Error opening usage log file: $usage_file\n";
|
||||
|
||||
if ($opt_D) {print "Transfer Totals include the '$opt_D' domain only.\n";
|
||||
print "All other domains are filtered out for this report.\n\n";}
|
||||
if ($only_domain) {
|
||||
print "Transfer Totals include the '$only_domain' domain only.\n";
|
||||
print "All other domains are filtered out for this report.\n\n";
|
||||
}
|
||||
|
||||
if ($opt_s) {print "Transfer Totals include the '$opt_s' section only.\n";
|
||||
print "All other sections are filtered out for this report.\n\n";}
|
||||
if ($only_section) {
|
||||
print "Transfer Totals include the '$only_section' section only.\n";
|
||||
print "All other sections are filtered out for this report.\n\n";
|
||||
}
|
||||
|
||||
line: while (<LOG>) {
|
||||
|
||||
@line = split;
|
||||
next unless ($day,$time,$op,$host,$module,$file,$bytes)
|
||||
= m#^ (\d+/\d\d/\d\d)\s+(\d\d:\d\d:\d\d)\s+\[\d+\]\s+(send|recv|[<>]f\S+)\s+
|
||||
(\S+)\s+\[\d+\.\d+\.\d+\.\d+\]\s+(\S+)\s+\(\S*\)\s+(.*)\s+(\d+) $ #x;
|
||||
|
||||
$day = $line[0];
|
||||
$time = $line[1];
|
||||
$pid = $line[2];
|
||||
$op = $line[3];
|
||||
$host = $line[4];
|
||||
$ip = $line[5];
|
||||
$module = $line[6];
|
||||
$user = $line[7];
|
||||
$file = $line[8];
|
||||
$bytes = $line[9];
|
||||
|
||||
next if ($#line != 9);
|
||||
|
||||
next if ($op != "send" && $op != "recv");
|
||||
# TODO actually divide the data by into send/recv categories
|
||||
if ($op =~ /^>/) {
|
||||
$op = 'send';
|
||||
} elsif ($op =~ /^</) {
|
||||
$op = 'recv';
|
||||
}
|
||||
|
||||
$daytime = $day;
|
||||
$hour = substr($time,0,2);
|
||||
@@ -78,11 +73,13 @@ line: while (<LOG>) {
|
||||
@path = split(/\//, $file);
|
||||
|
||||
$pathkey = "";
|
||||
for ($i=0; $i <= $#path && $i <= $opt_l;$i++) {
|
||||
for ($i=0; $i <= $#path && $i <= $depth_limit; $i++) {
|
||||
$pathkey = $pathkey . "/" . $path[$i];
|
||||
}
|
||||
|
||||
next if (substr($pathkey,0,length("$opt_s")) ne "$opt_s");
|
||||
if ($only_section ne '') {
|
||||
next unless (substr($pathkey,0,length($only_section)) eq $only_section);
|
||||
}
|
||||
|
||||
$host =~ tr/A-Z/a-z/;
|
||||
|
||||
@@ -92,12 +89,12 @@ line: while (<LOG>) {
|
||||
if ( int($address[0]) > 0 || $#address < 2 )
|
||||
{ $domain = "unresolved"; }
|
||||
|
||||
if ($opt_D) {
|
||||
next unless (substr($domain,0,length("$opt_D")) eq "$opt_D");
|
||||
if ($only_domain ne '') {
|
||||
next unless (substr($domain,0,length($only_domain)) eq $only_domain);
|
||||
}
|
||||
|
||||
|
||||
# printf ("c=%d day=%s bytes=%d file=%s path=%s\n",
|
||||
# printf("c=%d day=%s bytes=%d file=%s path=%s\n",
|
||||
# $#line, $daytime, $bytes, $file, $pathkey);
|
||||
|
||||
$xferfiles++; # total files sent
|
||||
@@ -117,20 +114,20 @@ line: while (<LOG>) {
|
||||
}
|
||||
close LOG;
|
||||
|
||||
@syslist = keys(systemfiles);
|
||||
@dates = sort datecompare keys(xferbytes);
|
||||
#@syslist = keys %systemfiles;
|
||||
@dates = sort datecompare keys %xferbytes;
|
||||
|
||||
if ($xferfiles == 0) {die "There was no data to process.\n";}
|
||||
|
||||
|
||||
print "TOTALS FOR SUMMARY PERIOD ", $dates[0], " TO ", $dates[$#dates], "\n\n";
|
||||
printf ("Files Transmitted During Summary Period %12.0f\n", $xferfiles);
|
||||
printf ("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes);
|
||||
printf ("Systems Using Archives %12.0f\n\n", $#syslist+1);
|
||||
printf("Files Transmitted During Summary Period %12.0f\n", $xferfiles);
|
||||
printf("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes);
|
||||
#printf("Systems Using Archives %12.0f\n\n", $#syslist+1);
|
||||
|
||||
printf ("Average Files Transmitted Daily %12.0f\n",
|
||||
printf("Average Files Transmitted Daily %12.0f\n",
|
||||
$xferfiles / ($#dates + 1));
|
||||
printf ("Average Bytes Transmitted Daily %12.0f\n",
|
||||
printf("Average Bytes Transmitted Daily %12.0f\n",
|
||||
$xferbytes / ($#dates + 1));
|
||||
|
||||
format top1 =
|
||||
@@ -150,7 +147,7 @@ $date, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes
|
||||
$^ = top1;
|
||||
$~ = line1;
|
||||
|
||||
foreach $date ( sort datecompare keys(xferbytes) ) {
|
||||
foreach $date (sort datecompare keys %xferbytes) {
|
||||
|
||||
$nfiles = $xferfiles{$date};
|
||||
$nbytes = $xferbytes{$date};
|
||||
@@ -159,7 +156,7 @@ foreach $date ( sort datecompare keys(xferbytes) ) {
|
||||
write;
|
||||
}
|
||||
|
||||
if ($opt_t) {
|
||||
if ($total_report) {
|
||||
format top2 =
|
||||
|
||||
Total Transfers from each Archive Section (By bytes)
|
||||
@@ -179,7 +176,7 @@ $- = 0;
|
||||
$^ = top2;
|
||||
$~ = line2;
|
||||
|
||||
foreach $section ( sort bytecompare keys(groupfiles) ) {
|
||||
foreach $section (sort bytecompare keys %groupfiles) {
|
||||
|
||||
$files = $groupfiles{$section};
|
||||
$bytes = $groupbytes{$section};
|
||||
@@ -193,7 +190,7 @@ if ( $xferfiles < 1 ) { $xferfiles = 1; }
|
||||
if ( $xferbytes < 1 ) { $xferbytes = 1; }
|
||||
}
|
||||
|
||||
if ($opt_d) {
|
||||
if ($domain_report) {
|
||||
format top3 =
|
||||
|
||||
Total Transfer Amount By Domain
|
||||
@@ -212,7 +209,7 @@ $- = 0;
|
||||
$^ = top3;
|
||||
$~ = line3;
|
||||
|
||||
foreach $domain ( sort domnamcompare keys(domainfiles) ) {
|
||||
foreach $domain (sort domnamcompare keys %domainfiles) {
|
||||
|
||||
if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; }
|
||||
|
||||
@@ -226,7 +223,7 @@ foreach $domain ( sort domnamcompare keys(domainfiles) ) {
|
||||
|
||||
}
|
||||
|
||||
if ($opt_h) {
|
||||
if ($hourly_report) {
|
||||
|
||||
format top8 =
|
||||
|
||||
@@ -248,7 +245,7 @@ $- = 0;
|
||||
$^ = top8;
|
||||
$~ = line8;
|
||||
|
||||
foreach $hour ( sort keys(xfertbytes) ) {
|
||||
foreach $hour (sort keys %xfertbytes) {
|
||||
|
||||
$nfiles = $xfertfiles{$hour};
|
||||
$nbytes = $xfertbytes{$hour};
|
||||
@@ -284,3 +281,19 @@ sub faccompare {
|
||||
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
USAGE: rsyncstats [options]
|
||||
|
||||
OPTIONS:
|
||||
-f FILENAME Use FILENAME for the log file.
|
||||
-h Include report on hourly traffic.
|
||||
-d Include report on domain traffic.
|
||||
-t Report on total traffic by section.
|
||||
-D DOMAIN Report only on traffic from DOMAIN.
|
||||
-l DEPTH Set DEPTH of path detail for sections.
|
||||
-s SECTION Set SECTION to report on. For example, "-s /pub"
|
||||
will report only on paths under "/pub".
|
||||
EOT
|
||||
}
|
||||
|
||||
178
support/savetransfer.c
Normal file
178
support/savetransfer.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/* This program can record the stream of data flowing to or from a program.
|
||||
* This allows it to be used to check that rsync's data that is flowing
|
||||
* through a remote shell is not being corrupted (for example).
|
||||
*
|
||||
* Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]
|
||||
* -i Save the input going to PROGRAM to the OUTPUT_FILE
|
||||
* -o Save the output coming from PROGRAM to the OUTPUT_FILE
|
||||
*
|
||||
* If you want to capture the flow of data for an rsync command, use one of
|
||||
* the following commands (the first two are push commands, the last two are
|
||||
* pull commands):
|
||||
*
|
||||
* rsync -av --rsh="savetransfer -i /tmp/from.sender ssh"
|
||||
* --rsync-path="savetransfer -i /tmp/to.receiver rsync" FILES HOST:DEST
|
||||
*
|
||||
* rsync -av --rsh="savetransfer -o /tmp/to.sender ssh"
|
||||
* --rsync-path="savetransfer -o /tmp/from.generator rsync" FILES HOST:DEST
|
||||
*
|
||||
* rsync -av --rsh="savetransfer -i /tmp/from.generator ssh"
|
||||
* --rsync-path="savetransfer -i /tmp/to.sender rsync" HOST:FILES DEST
|
||||
*
|
||||
* rsync -av --rsh="savetransfer -o /tmp/to.receiver ssh"
|
||||
* --rsync-path="savetransfer -o /tmp/from.sender rsync" HOST:FILES DEST
|
||||
*
|
||||
* Note that this program aborts after 30 seconds of inactivity, so you'll need
|
||||
* to change it if that is not enough dead time for your transfer. Also, some
|
||||
* of the above commands will not notice that the transfer is done (if we're
|
||||
* saving the input to a PROGRAM and the PROGRAM goes away: we won't notice
|
||||
* that it's gone unless more data comes in) -- when this happens it will delay
|
||||
* at the end of the transfer until the timeout period expires.
|
||||
*/
|
||||
|
||||
#include "../rsync.h"
|
||||
|
||||
#define TIMEOUT_SECONDS 30
|
||||
|
||||
void run_program(char **command);
|
||||
|
||||
char buf[4096];
|
||||
int save_data_from_program = 0;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int fd_file, len;
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
|
||||
argv++;
|
||||
if (--argc && argv[0][0] == '-') {
|
||||
if (argv[0][1] == 'o')
|
||||
save_data_from_program = 1;
|
||||
else if (argv[0][1] == 'i')
|
||||
save_data_from_program = 0;
|
||||
else {
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]\n");
|
||||
fprintf(stderr, "-i Save the input going to PROGRAM to the OUTPUT_FILE\n");
|
||||
fprintf(stderr, "-o Save the output coming from PROGRAM to the OUTPUT_FILE\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((fd_file = open(*argv, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0644)) < 0) {
|
||||
fprintf(stderr, "Unable to write to `%s': %s\n", *argv, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
set_blocking(fd_file);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
run_program(argv + 1);
|
||||
|
||||
#if defined HAVE_SETMODE && O_BINARY
|
||||
setmode(STDIN_FILENO, O_BINARY);
|
||||
setmode(STDOUT_FILENO, O_BINARY);
|
||||
#endif
|
||||
set_nonblocking(STDIN_FILENO);
|
||||
set_blocking(STDOUT_FILENO);
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
tv.tv_sec = TIMEOUT_SECONDS;
|
||||
tv.tv_usec = 0;
|
||||
if (!select(STDIN_FILENO+1, &fds, NULL, NULL, &tv))
|
||||
break;
|
||||
if (!FD_ISSET(STDIN_FILENO, &fds))
|
||||
break;
|
||||
if ((len = read(STDIN_FILENO, buf, sizeof buf)) <= 0)
|
||||
break;
|
||||
if (write(STDOUT_FILENO, buf, len) != len) {
|
||||
fprintf(stderr, "Failed to write data to stdout: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (write(fd_file, buf, len) != len) {
|
||||
fprintf(stderr, "Failed to write data to fd_file: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
run_program(char **command)
|
||||
{
|
||||
int pipe_fds[2], ret;
|
||||
pid_t pid;
|
||||
|
||||
if (pipe(pipe_fds) < 0) {
|
||||
fprintf(stderr, "pipe failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((pid = fork()) < 0) {
|
||||
fprintf(stderr, "fork failed: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (save_data_from_program)
|
||||
ret = dup2(pipe_fds[1], STDOUT_FILENO);
|
||||
else
|
||||
ret = dup2(pipe_fds[0], STDIN_FILENO);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to dup (in child): %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(pipe_fds[0]);
|
||||
close(pipe_fds[1]);
|
||||
set_blocking(STDIN_FILENO);
|
||||
set_blocking(STDOUT_FILENO);
|
||||
execvp(command[0], command);
|
||||
fprintf(stderr, "Failed to exec %s: %s\n", command[0], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (save_data_from_program)
|
||||
ret = dup2(pipe_fds[0], STDIN_FILENO);
|
||||
else
|
||||
ret = dup2(pipe_fds[1], STDOUT_FILENO);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to dup (in parent): %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(pipe_fds[0]);
|
||||
close(pipe_fds[1]);
|
||||
}
|
||||
|
||||
void
|
||||
set_nonblocking(int fd)
|
||||
{
|
||||
int val;
|
||||
|
||||
if ((val = fcntl(fd, F_GETFL, 0)) == -1)
|
||||
return;
|
||||
if (!(val & NONBLOCK_FLAG)) {
|
||||
val |= NONBLOCK_FLAG;
|
||||
fcntl(fd, F_SETFL, val);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_blocking(int fd)
|
||||
{
|
||||
int val;
|
||||
|
||||
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
|
||||
return;
|
||||
if (val & NONBLOCK_FLAG) {
|
||||
val &= ~NONBLOCK_FLAG;
|
||||
fcntl(fd, F_SETFL, val);
|
||||
}
|
||||
}
|
||||
78
syscall.c
78
syscall.c
@@ -26,6 +26,10 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
extern int dry_run;
|
||||
extern int read_only;
|
||||
extern int list_only;
|
||||
@@ -55,7 +59,7 @@ int do_symlink(char *fname1, char *fname2)
|
||||
return symlink(fname1, fname2);
|
||||
}
|
||||
|
||||
#if HAVE_LINK
|
||||
#ifdef HAVE_LINK
|
||||
int do_link(char *fname1, char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
@@ -68,17 +72,47 @@ int do_lchown(const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
#ifndef HAVE_LCHOWN
|
||||
#define lchown chown
|
||||
#endif
|
||||
return lchown(path, owner, group);
|
||||
}
|
||||
|
||||
#if HAVE_MKNOD
|
||||
int do_mknod(char *pathname, mode_t mode, dev_t dev)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return mknod(pathname, mode, dev);
|
||||
}
|
||||
#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
|
||||
if (S_ISFIFO(mode))
|
||||
return mkfifo(pathname, mode);
|
||||
#endif
|
||||
#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
|
||||
if (S_ISSOCK(mode)) {
|
||||
int sock;
|
||||
struct sockaddr_un saddr;
|
||||
unsigned int len;
|
||||
|
||||
saddr.sun_family = AF_UNIX;
|
||||
len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
|
||||
#ifdef HAVE_SOCKADDR_UN_LEN
|
||||
saddr.sun_len = len >= sizeof saddr.sun_path
|
||||
? sizeof saddr.sun_path : len + 1;
|
||||
#endif
|
||||
|
||||
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0
|
||||
|| (unlink(pathname) < 0 && errno != ENOENT)
|
||||
|| (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0)
|
||||
return -1;
|
||||
close(sock);
|
||||
return do_chmod(pathname, mode);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_MKNOD
|
||||
return mknod(pathname, mode, dev);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int do_rmdir(char *pathname)
|
||||
{
|
||||
@@ -97,7 +131,7 @@ int do_open(char *pathname, int flags, mode_t mode)
|
||||
return open(pathname, flags | O_BINARY, mode);
|
||||
}
|
||||
|
||||
#if HAVE_CHMOD
|
||||
#ifdef HAVE_CHMOD
|
||||
int do_chmod(const char *path, mode_t mode)
|
||||
{
|
||||
int code;
|
||||
@@ -152,7 +186,7 @@ int do_mkstemp(char *template, mode_t perms)
|
||||
RETURN_ERROR_IF(dry_run, 0);
|
||||
RETURN_ERROR_IF(read_only, EROFS);
|
||||
|
||||
#if HAVE_SECURE_MKSTEMP && HAVE_FCHMOD && (!HAVE_OPEN64 || HAVE_MKSTEMP64)
|
||||
#if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
|
||||
{
|
||||
int fd = mkstemp(template);
|
||||
if (fd == -1)
|
||||
@@ -164,6 +198,9 @@ int do_mkstemp(char *template, mode_t perms)
|
||||
errno = errno_save;
|
||||
return -1;
|
||||
}
|
||||
#if defined HAVE_SETMODE && O_BINARY
|
||||
setmode(fd, O_BINARY);
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
#else
|
||||
@@ -175,27 +212,29 @@ int do_mkstemp(char *template, mode_t perms)
|
||||
|
||||
int do_stat(const char *fname, STRUCT_STAT *st)
|
||||
{
|
||||
#if HAVE_OFF64_T
|
||||
#ifdef USE_STAT64_FUNCS
|
||||
return stat64(fname, st);
|
||||
#else
|
||||
return stat(fname, st);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
int do_lstat(const char *fname, STRUCT_STAT *st)
|
||||
{
|
||||
#if HAVE_OFF64_T
|
||||
#ifdef SUPPORT_LINKS
|
||||
# ifdef USE_STAT64_FUNCS
|
||||
return lstat64(fname, st);
|
||||
#else
|
||||
# else
|
||||
return lstat(fname, st);
|
||||
# endif
|
||||
#else
|
||||
return do_stat(fname, st);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_fstat(int fd, STRUCT_STAT *st)
|
||||
{
|
||||
#if HAVE_OFF64_T
|
||||
#ifdef USE_STAT64_FUNCS
|
||||
return fstat64(fd, st);
|
||||
#else
|
||||
return fstat(fd, st);
|
||||
@@ -204,7 +243,7 @@ int do_fstat(int fd, STRUCT_STAT *st)
|
||||
|
||||
OFF_T do_lseek(int fd, OFF_T offset, int whence)
|
||||
{
|
||||
#if HAVE_OFF64_T
|
||||
#ifdef HAVE_LSEEK64
|
||||
off64_t lseek64();
|
||||
return lseek64(fd, offset, whence);
|
||||
#else
|
||||
@@ -212,20 +251,9 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_MMAP
|
||||
void *do_mmap(void *start, int len, int prot, int flags, int fd, OFF_T offset)
|
||||
{
|
||||
#if HAVE_OFF64_T
|
||||
return mmap64(start, len, prot, flags, fd, offset);
|
||||
#else
|
||||
return mmap(start, len, prot, flags, fd, offset);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
char *d_name(struct dirent *di)
|
||||
{
|
||||
#if HAVE_BROKEN_READDIR
|
||||
#ifdef HAVE_BROKEN_READDIR
|
||||
return (di->d_name - 2);
|
||||
#else
|
||||
return di->d_name;
|
||||
|
||||
4
t_stub.c
4
t_stub.c
@@ -29,7 +29,7 @@
|
||||
int modify_window = 0;
|
||||
int module_id = -1;
|
||||
char *partial_dir;
|
||||
struct exclude_list_struct server_exclude_list;
|
||||
struct filter_list_struct server_filter_list;
|
||||
|
||||
void rprintf(UNUSED(enum logcode code), const char *format, ...)
|
||||
{
|
||||
@@ -56,7 +56,7 @@ struct exclude_list_struct server_exclude_list;
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int check_exclude(UNUSED(struct exclude_list_struct *listp), UNUSED(char *name),
|
||||
int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(char *name),
|
||||
UNUSED(int name_is_dir))
|
||||
{
|
||||
/* This function doesn't really get called in this test context, so
|
||||
|
||||
@@ -35,15 +35,20 @@ for fn in name1 name2; do
|
||||
mv "$todir/$fn~" "$todir/$fn"
|
||||
done
|
||||
|
||||
checkit "$RSYNC -avv --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
echo deleted-file >"$todir/dname"
|
||||
cp -p "$todir/dname" "$chkdir"
|
||||
|
||||
checkit "$RSYNC -avv --no-whole-file --delete-after \
|
||||
--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"
|
||||
rm "$bakdir/dname"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
checkit "$RSYNC -avv --del \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
cat $srcdir/[efgr]*.[ch] > "$name1"
|
||||
cat $srcdir/[ew]*.[ch] > "$name2"
|
||||
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
|
||||
set -x
|
||||
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh "$0"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
mkdir "$fromdir"
|
||||
|
||||
@@ -9,25 +9,31 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
altdir="$tmpdir/alt"
|
||||
alt1dir="$tmpdir/alt1"
|
||||
alt2dir="$tmpdir/alt2"
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
# Setup the alt and chk dirs
|
||||
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$altdir/"
|
||||
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$alt1dir/"
|
||||
$RSYNC -av --include=etc-ltr-list --include='*/' --exclude='*' "$fromdir/" "$alt2dir/"
|
||||
|
||||
sleep 1
|
||||
touch "$fromdir/dir/text"
|
||||
|
||||
$RSYNC -av --exclude=/text "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/"
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avv --no-whole-file --compare-dest=\"$altdir\" \
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--compare-dest=\"$alt1dir\" --compare-dest=\"$alt2dir\" \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--copy-dest=\"$alt1dir\" --copy-dest=\"$alt2dir\" \
|
||||
\"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -26,6 +26,8 @@ build_rsyncd_conf
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
|
||||
@@ -20,6 +20,8 @@ build_rsyncd_conf
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
|
||||
29
testsuite/delete.test
Normal file
29
testsuite/delete.test
Normal file
@@ -0,0 +1,29 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of various delete directives.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
makepath "$chkdir"
|
||||
|
||||
# Create two chk dirs, one with a copy of the source files, and one with
|
||||
# what we expect to be left behind by the copy using --remove-sent-files.
|
||||
$RSYNC -av "$fromdir/" "$chkdir/copy/"
|
||||
$RSYNC -av -f 'exclude,! */' "$fromdir/" "$chkdir/empty/"
|
||||
|
||||
checkit "$RSYNC -avv --remove-sent-files \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir/copy" "$todir"
|
||||
|
||||
diff -r "$chkdir/empty" "$fromdir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -9,14 +9,17 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) test_skipped "Rsync won't copy devices unless we're root" ;;
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh "$0"
|
||||
fi
|
||||
test_skipped "Rsync won't copy devices unless we're root"
|
||||
;;
|
||||
esac
|
||||
|
||||
# TODO: Need to test whether hardlinks are possible on this OS/filesystem
|
||||
@@ -30,7 +33,7 @@ mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node
|
||||
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"
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" skip_file_diff
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2003 by Wayne Davison <wayned@samba.org>
|
||||
# Copyright (C) 2003, 2004, 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
@@ -12,30 +12,66 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
HOME="$scratchdir"
|
||||
CVSIGNORE='*.junk'
|
||||
export HOME CVSIGNORE
|
||||
|
||||
set -x
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
makepath "$fromdir/foo/down/to/you"
|
||||
makepath "$fromdir/bar/down/to/foo/too"
|
||||
makepath "$fromdir/bar/down/to/bar/baz"
|
||||
makepath "$fromdir/mid/for/foo/and/that/is/who"
|
||||
cat >"$fromdir/.filt" <<EOF
|
||||
exclude down
|
||||
: .filt-temp
|
||||
clear
|
||||
- .filt
|
||||
- *.bak
|
||||
- *.old
|
||||
EOF
|
||||
echo kept >"$fromdir/foo/file1"
|
||||
echo removed >"$fromdir/foo/file2"
|
||||
echo cvsout >"$fromdir/foo/file2.old"
|
||||
cat >"$fromdir/foo/.filt" <<EOF
|
||||
include .filt
|
||||
- file1
|
||||
EOF
|
||||
cat >"$fromdir/bar/.filt" <<EOF
|
||||
- home-cvs-exclude
|
||||
dir-merge .filt2
|
||||
+ to
|
||||
EOF
|
||||
echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
|
||||
cat >"$fromdir/bar/down/to/.filt2" <<EOF
|
||||
- .filt2
|
||||
EOF
|
||||
cat >"$fromdir/bar/down/to/foo/.filt2" <<EOF
|
||||
+ *.junk
|
||||
EOF
|
||||
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 weird >"$fromdir/bar/down/to/foo/+ file3"
|
||||
echo cvsout-but-filtin >"$fromdir/bar/down/to/foo/file4.junk"
|
||||
echo smashed >"$fromdir/bar/down/to/foo/to"
|
||||
cat >"$fromdir/bar/down/to/bar/.filt2" <<EOF
|
||||
- *.deep
|
||||
EOF
|
||||
echo filtout >"$fromdir/bar/down/to/bar/baz/file5.deep"
|
||||
# This one should be ineffectual
|
||||
cat >"$fromdir/mid/.filt2" <<EOF
|
||||
- extra
|
||||
EOF
|
||||
echo cvsout >"$fromdir/mid/one-in-one-out"
|
||||
echo one-in-one-out >"$fromdir/mid/.cvsignore"
|
||||
echo cvsin >"$fromdir/mid/one-for-all"
|
||||
cat >"$fromdir/mid/.filt" <<EOF
|
||||
:C
|
||||
EOF
|
||||
echo cvsin >"$fromdir/mid/for/one-in-one-out"
|
||||
echo expunged >"$fromdir/mid/for/foo/extra"
|
||||
echo retained >"$fromdir/mid/for/foo/keep"
|
||||
@@ -45,6 +81,7 @@ ln -s too "$fromdir/bar/down/to/foo/sym"
|
||||
|
||||
excl="$scratchdir/exclude-from"
|
||||
cat >"$excl" <<EOF
|
||||
!
|
||||
# If the second line of these two lines does anything, it's a bug.
|
||||
+ **/bar
|
||||
- /bar
|
||||
@@ -82,7 +119,8 @@ $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\" \
|
||||
--delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir by removing cvs-ignored files and then tweaking the dir times.
|
||||
|
||||
@@ -92,13 +130,71 @@ 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/"
|
||||
$RSYNC -av --existing --filter='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"
|
||||
checkit "$RSYNC -avvC --filter=\"merge $excl\" --delete-excluded \
|
||||
--delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir for our merge-exclude test and then tweak the dir times.
|
||||
|
||||
rm "$chkdir"/foo/file1
|
||||
rm "$chkdir"/bar/down/to/bar/baz/*.deep
|
||||
cp -p "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo
|
||||
cp -p "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo
|
||||
|
||||
$RSYNC -av --existing -f 'show .filt*' -f 'hide,! */' --del "$fromdir/" "$todir/"
|
||||
|
||||
echo retained >"$todir"/bar/down/to/bar/baz/nodel.deep
|
||||
cp -p "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz
|
||||
|
||||
$RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files, this time with a merge-exclude
|
||||
# file.
|
||||
|
||||
checkit "sed '/!/d' \"$excl\" |
|
||||
$RSYNC -avv -f dir-merge_.filt -f merge_- \
|
||||
--delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# Remove the files that will be deleted.
|
||||
|
||||
rm "$chkdir"/.filt
|
||||
rm "$chkdir"/bar/.filt
|
||||
rm "$chkdir"/bar/down/to/.filt2
|
||||
rm "$chkdir"/bar/down/to/foo/.filt2
|
||||
rm "$chkdir"/bar/down/to/bar/.filt2
|
||||
rm "$chkdir"/mid/.filt
|
||||
|
||||
$RSYNC -av --protocol=28 --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, try the prior command with --delete-before and some side-specific
|
||||
# rules.
|
||||
|
||||
checkit "sed '/!/d' \"$excl\" |
|
||||
$RSYNC -avv -f :s_.filt -f .s_- -f P_nodel.deep \
|
||||
--delete-before \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# Next, we'll test some rule-restricted filter files.
|
||||
|
||||
cat >"$fromdir/bar/down/.excl" <<EOF
|
||||
file3
|
||||
EOF
|
||||
cat >"$fromdir/bar/down/to/foo/.excl" <<EOF
|
||||
+ file3
|
||||
*.bak
|
||||
EOF
|
||||
$RSYNC -av --del "$fromdir/" "$chkdir/"
|
||||
rm "$chkdir/bar/down/to/foo/file1.bak"
|
||||
rm "$chkdir/bar/down/to/foo/file3"
|
||||
rm "$chkdir/bar/down/to/foo/+ file3"
|
||||
$RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --delete-excluded --exclude='*' "$fromdir/" "$todir/"
|
||||
|
||||
checkit "$RSYNC -avv -f dir-merge,-_.excl \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
25
testsuite/fuzzy.test
Normal file
25
testsuite/fuzzy.test
Normal file
@@ -0,0 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of the --fuzzy option.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
mkdir "$fromdir"
|
||||
mkdir "$todir"
|
||||
|
||||
cp -p "$srcdir"/rsync.c "$fromdir"/rsync.c
|
||||
cp -p "$fromdir"/rsync.c "$todir"/rsync2.c
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avvi --no-whole-file --fuzzy --delete-after \
|
||||
\"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -20,7 +20,7 @@ rm "$todir/text"
|
||||
runtest "one file" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
echo "extra line" >> "$todir/text"
|
||||
runtest "extra data" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
runtest "extra data" 'checkit "$RSYNC -avH --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
cp "$fromdir/text" "$todir/ThisShouldGo"
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
@@ -30,8 +30,34 @@ echo "This is the file" > "$name1"
|
||||
ln "$name1" "$name2" || fail "Can't create hardlink"
|
||||
ln "$name2" "$name3" || fail "Can't create hardlink"
|
||||
cp "$name2" "$name4" || fail "Can't copy file"
|
||||
cat $srcdir/*.c >"$fromdir/text"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -aHivv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
echo "extra extra" >>"$todir/name1"
|
||||
|
||||
checkit "$RSYNC -aHivv --no-whole-file \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# Add a new link in a new subdirectory to test that we don't try to link
|
||||
# the files before the directory gets created.
|
||||
mkdir "$fromdir/subdir"
|
||||
ln "$name1" "$fromdir/subdir/new-file"
|
||||
rm "$todir/text"
|
||||
|
||||
checkit "$RSYNC -aHivv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# Do some duplicate copies using --link-dest and --copy-dest to test that
|
||||
# we hard-link all locally-inherited items.
|
||||
checkit "$RSYNC -aHivv --link-dest=\"$todir\" \"$fromdir/\" \"$chkdir/\"" "$todir" "$chkdir"
|
||||
|
||||
rm -rf "$chkdir"
|
||||
checkit "$RSYNC -aHivv --copy-dest=\"$todir\" \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
|
||||
# Make sure there's nothing wrong with sending a single file with -H
|
||||
# enabled (this has broken twice so far, so we need this test).
|
||||
rm -rf "$todir"
|
||||
$RSYNC -aHivv "$name1" "$todir/"
|
||||
diff $diffopt "$name1" "$todir" || test_fail "solo copy of name1 failed"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
# set -x
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
@@ -17,7 +17,11 @@ 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"
|
||||
if [ -r /etc ]; then
|
||||
ls -la /etc >"$longdir/2"
|
||||
else
|
||||
ls -la / >"$longdir/2"
|
||||
fi
|
||||
checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
|
||||
@@ -19,8 +19,8 @@ from3dir="${fromdir}3"
|
||||
|
||||
mkdir "$from1dir" "$from2dir" "$from3dir"
|
||||
mkdir "$from2dir"/sub1 "$from3dir"/sub1
|
||||
mkdir "$from3dir"/sub2
|
||||
mkdir "$chkdir" "$chkdir"/sub1 "$chkdir"/sub2
|
||||
mkdir "$from3dir"/sub2 "$from1dir"/dir-and-not-dir
|
||||
mkdir "$chkdir" "$chkdir"/sub1 "$chkdir"/sub2 "$chkdir"/dir-and-not-dir
|
||||
echo "one" >"$from1dir"/one
|
||||
cp -p "$from1dir"/one "$from2dir"/one
|
||||
cp -p "$from1dir"/one "$from3dir"/one
|
||||
@@ -34,13 +34,19 @@ cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/uno
|
||||
echo "sub2" >"$from3dir"/sub1/dos
|
||||
echo "sub3" >"$from2dir"/sub1/tres
|
||||
echo "subby" >"$from3dir"/sub2/subby
|
||||
echo "extra" >"$from1dir"/dir-and-not-dir/inside
|
||||
echo "not-dir" >"$from3dir"/dir-and-not-dir
|
||||
|
||||
cp -p "$from1dir"/one "$from1dir"/two "$from2dir"/three "$from3dir"/four "$from1dir"/five "$from3dir"/six "$chkdir"
|
||||
cp -p "$from1dir"/dir-and-not-dir/inside "$chkdir"/dir-and-not-dir
|
||||
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/"
|
||||
$RSYNC -av --existing -f 'exclude,! */' "$from1dir/" "$from2dir/"
|
||||
$RSYNC -av --existing -f 'exclude,! */' "$from2dir/" "$from3dir/"
|
||||
$RSYNC -av --existing -f 'exclude,! */' "$from1dir/" "$chkdir/"
|
||||
$RSYNC -av --existing -f 'exclude,! */' "$from3dir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$from1dir/\" \"$from2dir/\" \"$from3dir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
|
||||
39
testsuite/relative.test
Normal file
39
testsuite/relative.test
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2005 by Wayne Davison <wayned@samba.org>
|
||||
#
|
||||
# This program is distributable under the terms of the GNU GPL (see COPYING)
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
deepstr='down/3/deep'
|
||||
deepdir="$fromdir/$deepstr"
|
||||
mkdir -p "$deepdir"
|
||||
fromdir="$deepdir"
|
||||
hands_setup
|
||||
fromdir="$tmpdir/from"
|
||||
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
cd "$fromdir"
|
||||
|
||||
# Main script starts here
|
||||
|
||||
echo "$fromdir"
|
||||
runtest "basic relative" 'checkit "$RSYNC -avR ./$deepstr \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
ln "$deepdir/filelist" "$deepdir/dir"
|
||||
runtest "hard links" 'checkit "$RSYNC -avHR ./$deepstr/ \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
cp "$deepdir/text" "$todir/$deepstr/ThisShouldGo"
|
||||
cp "$deepdir/text" "$todir/$deepstr/dir/ThisShouldGoToo"
|
||||
runtest "deletion" 'checkit "$RSYNC -avHR --delete ./$deepstr/ \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
runtest "non-deletion" 'checkit "$RSYNC -aiHR --delete ./$deepstr/ \"$todir\"" "$fromdir/" "$todir"' \
|
||||
| tee "$outfile"
|
||||
|
||||
# Make sure no files were deleted
|
||||
grep 'deleting ' "$outfile" && test_fail "Erroneous deletions occurred!"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -50,7 +50,7 @@ printmsg() {
|
||||
|
||||
|
||||
rsync_ls_lR() {
|
||||
find "$@" -print | sort | xargs "$TOOLDIR/tls"
|
||||
find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls"
|
||||
}
|
||||
|
||||
rsync_getgroups() {
|
||||
@@ -165,20 +165,23 @@ checkit() {
|
||||
failed="YES";
|
||||
fi
|
||||
|
||||
echo "-------------"
|
||||
echo "check how the files compare with diff:"
|
||||
echo ""
|
||||
for f in `cd "$2"; find . -type f -print `
|
||||
do
|
||||
diff $diffopt "$2"/"$f" "$3"/"$f" || failed=YES
|
||||
done
|
||||
|
||||
echo "-------------"
|
||||
echo "check how the directory listings compare with diff:"
|
||||
echo ""
|
||||
( 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
|
||||
|
||||
echo "-------------"
|
||||
echo "check how the files compare with diff:"
|
||||
echo ""
|
||||
if [ "x$4" != x ]; then
|
||||
echo " === Skipping (as directed) ==="
|
||||
else
|
||||
diff -r $diffopt "$2" "$3" || failed=YES
|
||||
fi
|
||||
|
||||
echo "-------------"
|
||||
if [ -z "$failed" ] ; then
|
||||
return 0
|
||||
else
|
||||
|
||||
@@ -28,7 +28,7 @@ fi
|
||||
# nothing to do.
|
||||
hands_setup
|
||||
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
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
|
||||
@@ -40,4 +40,4 @@ F1=`ls "$todir" | head -5 | tail -1`
|
||||
|
||||
mv "$todir/$F1" "$todir/ThisShouldGo"
|
||||
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
2
tls.c
2
tls.c
@@ -66,7 +66,7 @@ static void list_file(const char *fname)
|
||||
char datebuf[50];
|
||||
char linkbuf[4096];
|
||||
|
||||
if (do_lstat(fname, &buf) == -1)
|
||||
if (do_lstat(fname, &buf) < 0)
|
||||
failed("stat", fname);
|
||||
|
||||
/* The size of anything but a regular file is probably not
|
||||
|
||||
103
token.c
103
token.c
@@ -65,11 +65,11 @@ void set_compression(char *fname)
|
||||
}
|
||||
|
||||
/* non-compressing recv token */
|
||||
static int simple_recv_token(int f,char **data)
|
||||
static int32 simple_recv_token(int f, char **data)
|
||||
{
|
||||
static int residue;
|
||||
static int32 residue;
|
||||
static char *buf;
|
||||
int n;
|
||||
int32 n;
|
||||
|
||||
if (!buf) {
|
||||
buf = new_array(char, CHUNK_SIZE);
|
||||
@@ -78,7 +78,7 @@ static int simple_recv_token(int f,char **data)
|
||||
}
|
||||
|
||||
if (residue == 0) {
|
||||
int i = read_int(f);
|
||||
int32 i = read_int(f);
|
||||
if (i <= 0)
|
||||
return i;
|
||||
residue = i;
|
||||
@@ -93,22 +93,21 @@ static int simple_recv_token(int f,char **data)
|
||||
|
||||
|
||||
/* non-compressing send token */
|
||||
static void simple_send_token(int f,int token,
|
||||
struct map_struct *buf,OFF_T offset,int n)
|
||||
static void simple_send_token(int f, int32 token, struct map_struct *buf,
|
||||
OFF_T offset, int32 n)
|
||||
{
|
||||
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);
|
||||
l += n1;
|
||||
int32 len = 0;
|
||||
while (len < n) {
|
||||
int32 n1 = MIN(CHUNK_SIZE, n-len);
|
||||
write_int(f, n1);
|
||||
write_buf(f, map_ptr(buf, offset+len, n1), n1);
|
||||
len += n1;
|
||||
}
|
||||
}
|
||||
/* a -2 token means to send data only and no token */
|
||||
if (token != -2) {
|
||||
write_int(f,-(token+1));
|
||||
}
|
||||
if (token != -2)
|
||||
write_int(f, -(token+1));
|
||||
}
|
||||
|
||||
|
||||
@@ -129,9 +128,9 @@ static void simple_send_token(int f,int token,
|
||||
#define AVAIL_OUT_SIZE(avail_in_size) ((avail_in_size)*1001/1000+16)
|
||||
|
||||
/* For coding runs of tokens */
|
||||
static int last_token = -1;
|
||||
static int run_start;
|
||||
static int last_run_end;
|
||||
static int32 last_token = -1;
|
||||
static int32 run_start;
|
||||
static int32 last_run_end;
|
||||
|
||||
/* Deflation state */
|
||||
static z_stream tx_strm;
|
||||
@@ -149,10 +148,10 @@ static char *obuf;
|
||||
|
||||
/* Send a deflated token */
|
||||
static void
|
||||
send_deflated_token(int f, int token,
|
||||
struct map_struct *buf, OFF_T offset, int nb, int toklen)
|
||||
send_deflated_token(int f, int32 token, struct map_struct *buf, OFF_T offset,
|
||||
int32 nb, int32 toklen)
|
||||
{
|
||||
int n, r;
|
||||
int32 n, r;
|
||||
static int init_done, flush_pending;
|
||||
|
||||
if (last_token == -1) {
|
||||
@@ -261,18 +260,24 @@ send_deflated_token(int f, int token,
|
||||
/* end of file - clean up */
|
||||
write_byte(f, END_FLAG);
|
||||
} else if (token != -2) {
|
||||
/* add the data in the current block to the compressor's
|
||||
history and hash table */
|
||||
tx_strm.next_in = (Bytef *) map_ptr(buf, offset, toklen);
|
||||
tx_strm.avail_in = toklen;
|
||||
tx_strm.next_out = (Bytef *) obuf;
|
||||
tx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
|
||||
r = deflate(&tx_strm, Z_INSERT_ONLY);
|
||||
if (r != Z_OK || tx_strm.avail_in != 0) {
|
||||
rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n",
|
||||
r, tx_strm.avail_in);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
/* Add the data in the current block to the compressor's
|
||||
* history and hash table. */
|
||||
do {
|
||||
/* Break up long sections in the same way that
|
||||
* see_deflate_token() does. */
|
||||
int32 n1 = toklen > 0xffff ? 0xffff : toklen;
|
||||
toklen -= n1;
|
||||
tx_strm.next_in = (Bytef *)map_ptr(buf, offset, n1);
|
||||
tx_strm.avail_in = n1;
|
||||
tx_strm.next_out = (Bytef *) obuf;
|
||||
tx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
|
||||
r = deflate(&tx_strm, Z_INSERT_ONLY);
|
||||
if (r != Z_OK || tx_strm.avail_in != 0) {
|
||||
rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n",
|
||||
r, tx_strm.avail_in);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
} while (toklen > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,16 +291,16 @@ static char *cbuf;
|
||||
static char *dbuf;
|
||||
|
||||
/* for decoding runs of tokens */
|
||||
static int rx_token;
|
||||
static int rx_run;
|
||||
static int32 rx_token;
|
||||
static int32 rx_run;
|
||||
|
||||
/* Receive a deflated token and inflate it */
|
||||
static int
|
||||
recv_deflated_token(int f, char **data)
|
||||
static int32 recv_deflated_token(int f, char **data)
|
||||
{
|
||||
int n, r, flag;
|
||||
static int init_done;
|
||||
static int saved_flag;
|
||||
static int32 saved_flag;
|
||||
int32 n, flag;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
switch (recv_state) {
|
||||
@@ -422,9 +427,10 @@ recv_deflated_token(int f, char **data)
|
||||
* put the data corresponding to a token that we've just returned
|
||||
* from recv_deflated_token into the decompressor's history buffer.
|
||||
*/
|
||||
static void see_deflate_token(char *buf, int len)
|
||||
static void see_deflate_token(char *buf, int32 len)
|
||||
{
|
||||
int r, blklen;
|
||||
int r;
|
||||
int32 blklen;
|
||||
unsigned char hdr[5];
|
||||
|
||||
rx_strm.avail_in = 0;
|
||||
@@ -465,14 +471,13 @@ static void see_deflate_token(char *buf, int len)
|
||||
* 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,
|
||||
int n,int toklen)
|
||||
void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset,
|
||||
int32 n, int32 toklen)
|
||||
{
|
||||
if (!do_compression) {
|
||||
simple_send_token(f,token,buf,offset,n);
|
||||
} else {
|
||||
if (!do_compression)
|
||||
simple_send_token(f, token, buf, offset, n);
|
||||
else
|
||||
send_deflated_token(f, token, buf, offset, n, toklen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -482,7 +487,7 @@ void send_token(int f,int token,struct map_struct *buf,OFF_T offset,
|
||||
* if the return value is -i then it represents token i-1
|
||||
* if the return value is 0 then the end has been reached
|
||||
*/
|
||||
int recv_token(int f,char **data)
|
||||
int32 recv_token(int f, char **data)
|
||||
{
|
||||
int tok;
|
||||
|
||||
@@ -497,7 +502,7 @@ int recv_token(int f,char **data)
|
||||
/*
|
||||
* look at the data corresponding to a token, if necessary
|
||||
*/
|
||||
void see_token(char *data, int toklen)
|
||||
void see_token(char *data, int32 toklen)
|
||||
{
|
||||
if (do_compression)
|
||||
see_deflate_token(data, toklen);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "rsync.h"
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
# if !defined(GETGROUPS_T)
|
||||
# ifndef GETGROUPS_T
|
||||
# define GETGROUPS_T gid_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
223
util.c
223
util.c
@@ -32,7 +32,7 @@ extern int dry_run;
|
||||
extern int module_id;
|
||||
extern int modify_window;
|
||||
extern char *partial_dir;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
|
||||
int sanitize_paths = 0;
|
||||
|
||||
@@ -79,7 +79,7 @@ int fd_pair(int fd[2])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if HAVE_SOCKETPAIR
|
||||
#ifdef HAVE_SOCKETPAIR
|
||||
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
|
||||
#else
|
||||
ret = pipe(fd);
|
||||
@@ -105,9 +105,9 @@ void print_child_argv(char **cmd)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789"
|
||||
",.-_=+@/") != strlen(*cmd)) {
|
||||
rprintf(FINFO, "\"%s\" ", *cmd);
|
||||
rprintf(FINFO, "\"%s\" ", safe_fname(*cmd));
|
||||
} else {
|
||||
rprintf(FINFO, "%s ", *cmd);
|
||||
rprintf(FINFO, "%s ", safe_fname(*cmd));
|
||||
}
|
||||
}
|
||||
rprintf(FINFO, "\n");
|
||||
@@ -130,22 +130,22 @@ void overflow(char *str)
|
||||
|
||||
int set_modtime(char *fname, time_t modtime)
|
||||
{
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "set modtime of %s to (%ld) %s",
|
||||
fname, (long)modtime,
|
||||
safe_fname(fname), (long)modtime,
|
||||
asctime(localtime(&modtime)));
|
||||
}
|
||||
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
{
|
||||
#ifdef HAVE_UTIMBUF
|
||||
struct utimbuf tbuf;
|
||||
tbuf.actime = time(NULL);
|
||||
tbuf.modtime = modtime;
|
||||
return utime(fname,&tbuf);
|
||||
#elif defined(HAVE_UTIME)
|
||||
#elif defined HAVE_UTIME
|
||||
time_t t[2];
|
||||
t[0] = time(NULL);
|
||||
t[1] = modtime;
|
||||
@@ -245,7 +245,8 @@ static int safe_read(int desc, char *ptr, size_t len)
|
||||
|
||||
/** Copy a file.
|
||||
*
|
||||
* This is used in conjunction with the --temp-dir and --backup options */
|
||||
* This is used in conjunction with the --temp-dir, --backup, and
|
||||
* --copy-dest options. */
|
||||
int copy_file(char *source, char *dest, mode_t mode)
|
||||
{
|
||||
int ifd;
|
||||
@@ -350,7 +351,7 @@ int robust_unlink(char *fname)
|
||||
|
||||
if (verbose > 0) {
|
||||
rprintf(FINFO,"renaming %s to %s because of text busy\n",
|
||||
fname, path);
|
||||
safe_fname(fname), safe_fname(path));
|
||||
}
|
||||
|
||||
/* maybe we should return rename()'s exit status? Nah. */
|
||||
@@ -479,14 +480,14 @@ int lock_range(int fd, int offset, int len)
|
||||
return fcntl(fd,F_SETLK,&lock) == 0;
|
||||
}
|
||||
|
||||
static int exclude_server_path(char *arg)
|
||||
static int filter_server_path(char *arg)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (server_exclude_list.head) {
|
||||
if (server_filter_list.head) {
|
||||
for (s = arg; (s = strchr(s, '/')) != NULL; ) {
|
||||
*s = '\0';
|
||||
if (check_exclude(&server_exclude_list, arg, 1) < 0) {
|
||||
if (check_filter(&server_filter_list, arg, 1) < 0) {
|
||||
/* We must leave arg truncated! */
|
||||
return 1;
|
||||
}
|
||||
@@ -502,7 +503,7 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
|
||||
char **argv = *argv_ptr;
|
||||
int argc = *argc_ptr;
|
||||
int maxargs = *maxargs_ptr;
|
||||
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
|
||||
#if !defined HAVE_GLOB || !defined HAVE_GLOB_H
|
||||
if (argc == maxargs) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
@@ -513,7 +514,7 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
|
||||
if (!*s)
|
||||
s = ".";
|
||||
s = argv[argc++] = strdup(s);
|
||||
exclude_server_path(s);
|
||||
filter_server_path(s);
|
||||
#else
|
||||
glob_t globbuf;
|
||||
int i;
|
||||
@@ -529,7 +530,7 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
|
||||
s = strdup(s);
|
||||
|
||||
memset(&globbuf, 0, sizeof globbuf);
|
||||
if (!exclude_server_path(s))
|
||||
if (!filter_server_path(s))
|
||||
glob(s, 0, NULL, &globbuf);
|
||||
if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) {
|
||||
maxargs += globbuf.gl_pathc + MAX_ARGS;
|
||||
@@ -876,28 +877,41 @@ int pop_dir(char *dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filename, turning any newlines into '?'s. This ensures that
|
||||
* outputting it on a line of its own cannot generate an empty line. This
|
||||
* function can handle only 2 names at a time!
|
||||
**/
|
||||
const char *safe_fname(const char *fname)
|
||||
/* Return the filename, turning any non-printable characters into escaped
|
||||
* characters (e.g. \n -> \012, \ -> \\). This ensures that outputting it
|
||||
* cannot generate an empty line nor corrupt the screen. This function can
|
||||
* return only MAX_SAFE_NAMES values at a time! The returned value can be
|
||||
* longer than MAXPATHLEN (because we may be trying to output an error about
|
||||
* a too-long filename)! */
|
||||
char *safe_fname(const char *fname)
|
||||
{
|
||||
static char fbuf1[MAXPATHLEN], fbuf2[MAXPATHLEN];
|
||||
static char *fbuf = fbuf2;
|
||||
char *nl = strchr(fname, '\n');
|
||||
#define MAX_SAFE_NAMES 4
|
||||
static char fbuf[MAX_SAFE_NAMES][MAXPATHLEN*2];
|
||||
static int ndx = 0;
|
||||
int limit = sizeof fbuf / MAX_SAFE_NAMES - 1;
|
||||
char *t;
|
||||
|
||||
if (!nl)
|
||||
return fname;
|
||||
ndx = (ndx + 1) % MAX_SAFE_NAMES;
|
||||
for (t = fbuf[ndx]; *fname; fname++) {
|
||||
if (*fname == '\\') {
|
||||
if ((limit -= 2) < 0)
|
||||
break;
|
||||
*t++ = '\\';
|
||||
*t++ = '\\';
|
||||
} else if (!isprint(*(uchar*)fname)) {
|
||||
if ((limit -= 4) < 0)
|
||||
break;
|
||||
sprintf(t, "\\%03o", *(uchar*)fname);
|
||||
t += 4;
|
||||
} else {
|
||||
if (--limit < 0)
|
||||
break;
|
||||
*t++ = *fname;
|
||||
}
|
||||
}
|
||||
*t = '\0';
|
||||
|
||||
fbuf = fbuf == fbuf1 ? fbuf2 : fbuf1;
|
||||
strlcpy(fbuf, fname, MAXPATHLEN);
|
||||
nl = fbuf + (nl - (char *)fname);
|
||||
do {
|
||||
*nl = '?';
|
||||
} while ((nl = strchr(nl+1, '\n')) != NULL);
|
||||
|
||||
return fbuf;
|
||||
return fbuf[ndx];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -919,25 +933,21 @@ char *full_fname(const char *fn)
|
||||
p1 = p2 = "";
|
||||
else {
|
||||
p1 = curr_dir;
|
||||
p2 = "/";
|
||||
for (p2 = p1; *p2 == '/'; p2++) {}
|
||||
if (*p2)
|
||||
p2 = "/";
|
||||
}
|
||||
if (module_id >= 0) {
|
||||
m1 = " (in ";
|
||||
m2 = lp_name(module_id);
|
||||
m3 = ")";
|
||||
if (*p1) {
|
||||
if (p1 == curr_dir) {
|
||||
if (!lp_use_chroot(module_id)) {
|
||||
char *p = lp_path(module_id);
|
||||
if (*p != '/' || p[1])
|
||||
p1 += strlen(p);
|
||||
}
|
||||
if (!*p1)
|
||||
p2++;
|
||||
else
|
||||
p1++;
|
||||
}
|
||||
else
|
||||
fn++;
|
||||
} else
|
||||
m1 = m2 = m3 = "";
|
||||
|
||||
@@ -966,9 +976,17 @@ char *partial_dir_fname(const char *fname)
|
||||
fn = fname;
|
||||
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
|
||||
return NULL;
|
||||
if (server_exclude_list.head
|
||||
&& check_exclude(&server_exclude_list, partial_fname, 0) < 0)
|
||||
return NULL;
|
||||
if (server_filter_list.head) {
|
||||
static int len;
|
||||
if (!len)
|
||||
len = strlen(partial_dir);
|
||||
t[len] = '\0';
|
||||
if (check_filter(&server_filter_list, partial_fname, 1) < 0)
|
||||
return NULL;
|
||||
t[len] = '/';
|
||||
if (check_filter(&server_filter_list, partial_fname, 0) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return partial_fname;
|
||||
}
|
||||
@@ -990,11 +1008,7 @@ int handle_partial_dir(const char *fname, int create)
|
||||
dir = partial_fname;
|
||||
if (create) {
|
||||
STRUCT_STAT st;
|
||||
#if SUPPORT_LINKS
|
||||
int statret = do_lstat(dir, &st);
|
||||
#else
|
||||
int statret = do_stat(dir, &st);
|
||||
#endif
|
||||
if (statret == 0 && !S_ISDIR(st.st_mode)) {
|
||||
if (do_unlink(dir) < 0)
|
||||
return 0;
|
||||
@@ -1217,3 +1231,110 @@ void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
|
||||
return malloc(size * num);
|
||||
return realloc(ptr, size * num);
|
||||
}
|
||||
|
||||
/* Take a filename and filename length and return the most significant
|
||||
* filename suffix we can find. This ignores suffixes such as "~",
|
||||
* ".bak", ".orig", ".~1~", etc. */
|
||||
const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
|
||||
{
|
||||
const char *suf, *s;
|
||||
BOOL had_tilde;
|
||||
int s_len;
|
||||
|
||||
/* One or more dots at the start aren't a suffix. */
|
||||
while (fn_len && *fn == '.') fn++, fn_len--;
|
||||
|
||||
/* Ignore the ~ in a "foo~" filename. */
|
||||
if (fn_len > 1 && fn[fn_len-1] == '~')
|
||||
fn_len--, had_tilde = True;
|
||||
else
|
||||
had_tilde = False;
|
||||
|
||||
/* Assume we don't find an suffix. */
|
||||
suf = "";
|
||||
*len_ptr = 0;
|
||||
|
||||
/* Find the last significant suffix. */
|
||||
for (s = fn + fn_len; fn_len > 1; ) {
|
||||
while (*--s != '.' && s != fn) {}
|
||||
if (s == fn)
|
||||
break;
|
||||
s_len = fn_len - (s - fn);
|
||||
fn_len = s - fn;
|
||||
if (s_len == 4) {
|
||||
if (strcmp(s+1, "bak") == 0
|
||||
|| strcmp(s+1, "old") == 0)
|
||||
continue;
|
||||
} else if (s_len == 5) {
|
||||
if (strcmp(s+1, "orig") == 0)
|
||||
continue;
|
||||
} else if (s_len > 2 && had_tilde
|
||||
&& s[1] == '~' && isdigit(*(uchar*)(s+2)))
|
||||
continue;
|
||||
*len_ptr = s_len;
|
||||
suf = s;
|
||||
if (s_len == 1)
|
||||
break;
|
||||
/* Determine if the suffix is all digits. */
|
||||
for (s++, s_len--; s_len > 0; s++, s_len--) {
|
||||
if (!isdigit(*(uchar*)s))
|
||||
return suf;
|
||||
}
|
||||
/* An all-digit suffix may not be that signficant. */
|
||||
s = suf;
|
||||
}
|
||||
|
||||
return suf;
|
||||
}
|
||||
|
||||
/* This is an implementation of the Levenshtein distance algorithm. It
|
||||
* was implemented to avoid needing a two-dimensional matrix (to save
|
||||
* memory). It was also tweaked to try to factor in the ASCII distance
|
||||
* between changed characters as a minor distance quantity. The normal
|
||||
* Levenshtein units of distance (each signifying a single change between
|
||||
* the two strings) are defined as a "UNIT". */
|
||||
|
||||
#define UNIT (1 << 16)
|
||||
|
||||
uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2)
|
||||
{
|
||||
uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
|
||||
int32 cost;
|
||||
int i1, i2;
|
||||
|
||||
if (!len1 || !len2) {
|
||||
if (!len1) {
|
||||
s1 = s2;
|
||||
len1 = len2;
|
||||
}
|
||||
for (i1 = 0, cost = 0; i1 < len1; i1++)
|
||||
cost += s1[i1];
|
||||
return (int32)len1 * UNIT + cost;
|
||||
}
|
||||
|
||||
for (i2 = 0; i2 < len2; i2++)
|
||||
a[i2] = (i2+1) * UNIT;
|
||||
|
||||
for (i1 = 0; i1 < len1; i1++) {
|
||||
diag = i1 * UNIT;
|
||||
above = (i1+1) * UNIT;
|
||||
for (i2 = 0; i2 < len2; i2++) {
|
||||
left = a[i2];
|
||||
if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) {
|
||||
if (cost < 0)
|
||||
cost = UNIT - cost;
|
||||
else
|
||||
cost = UNIT + cost;
|
||||
}
|
||||
diag_inc = diag + cost;
|
||||
left_inc = left + UNIT + *((uchar*)s1+i1);
|
||||
above_inc = above + UNIT + *((uchar*)s2+i2);
|
||||
a[i2] = above = left < above
|
||||
? (left_inc < diag_inc ? left_inc : diag_inc)
|
||||
: (above_inc < diag_inc ? above_inc : diag_inc);
|
||||
diag = left;
|
||||
}
|
||||
}
|
||||
|
||||
return a[len2-1];
|
||||
}
|
||||
|
||||
@@ -1110,6 +1110,11 @@ local block_state deflate_stored(s, flush)
|
||||
s->strstart += s->lookahead;
|
||||
s->lookahead = 0;
|
||||
|
||||
if (flush == Z_INSERT_ONLY) {
|
||||
s->block_start = s->strstart;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Emit a stored block if pending_buf will be full: */
|
||||
max_start = s->block_start + max_block_size;
|
||||
if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
|
||||
@@ -1125,6 +1130,11 @@ local block_state deflate_stored(s, flush)
|
||||
FLUSH_BLOCK(s, 0);
|
||||
}
|
||||
}
|
||||
if (flush == Z_INSERT_ONLY) {
|
||||
s->block_start = s->strstart;
|
||||
return need_more;
|
||||
}
|
||||
|
||||
FLUSH_BLOCK(s, flush == Z_FINISH);
|
||||
return flush == Z_FINISH ? finish_done : block_done;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user