mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
619 Commits
v2.6.6
...
v2.6.8pre1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e26cfccf16 | ||
|
|
74f80abce2 | ||
|
|
5899b8cf3e | ||
|
|
08e0a62956 | ||
|
|
2bd17a51ae | ||
|
|
c7b9ebb598 | ||
|
|
e3db43ffe5 | ||
|
|
f61ab01d96 | ||
|
|
ceca8ccac8 | ||
|
|
374c3e1278 | ||
|
|
e09d8a304c | ||
|
|
2a7d9fe9b8 | ||
|
|
e63aeb6d68 | ||
|
|
077d5d4ebc | ||
|
|
e2d774cdd7 | ||
|
|
415b598346 | ||
|
|
69627d66f8 | ||
|
|
ac98cd98e3 | ||
|
|
91d324b4ea | ||
|
|
89fb50263b | ||
|
|
e257c6c20b | ||
|
|
43eae40e45 | ||
|
|
920240a687 | ||
|
|
f8b9da1a2c | ||
|
|
3c987ee956 | ||
|
|
5c6d46329b | ||
|
|
8b3e964d14 | ||
|
|
91a93df049 | ||
|
|
19826af5f0 | ||
|
|
49f4cfdf39 | ||
|
|
b3222792ad | ||
|
|
0640710115 | ||
|
|
fa65989a8b | ||
|
|
4209f079dd | ||
|
|
a7704777ce | ||
|
|
7d51b8374d | ||
|
|
a27042b521 | ||
|
|
5b51c893c5 | ||
|
|
408e69396c | ||
|
|
954bbed84a | ||
|
|
7c329ec72c | ||
|
|
07a8a360a5 | ||
|
|
1618c9e6d1 | ||
|
|
ba0147ac42 | ||
|
|
9e88f057b4 | ||
|
|
f171bf5b8f | ||
|
|
1b1628b90a | ||
|
|
50cf25672e | ||
|
|
b316862831 | ||
|
|
38a4b9c297 | ||
|
|
a058cbc410 | ||
|
|
1ef7913497 | ||
|
|
88a16c8b4f | ||
|
|
8030b28ff8 | ||
|
|
1c598b1db8 | ||
|
|
6854bf69a8 | ||
|
|
293def601d | ||
|
|
651dc65efc | ||
|
|
c2b2bd6a93 | ||
|
|
e32a48d256 | ||
|
|
b5cf121d70 | ||
|
|
44c26bf2a1 | ||
|
|
cc8c5057fe | ||
|
|
b4c7c1ca99 | ||
|
|
16d3b31b2c | ||
|
|
89a8180c5e | ||
|
|
34f961bbf3 | ||
|
|
2384f9e1db | ||
|
|
48cce779a2 | ||
|
|
6820753732 | ||
|
|
fbbe9a016d | ||
|
|
c64ca7ef58 | ||
|
|
900cfcb584 | ||
|
|
beab3078d6 | ||
|
|
530a2199da | ||
|
|
d9bca0c32f | ||
|
|
d733de97f5 | ||
|
|
f06c11ed40 | ||
|
|
c638caa63e | ||
|
|
d775372a34 | ||
|
|
07affc3d93 | ||
|
|
f2ebbebead | ||
|
|
a695b379b5 | ||
|
|
88c2190a7c | ||
|
|
2dbf36ef55 | ||
|
|
cca9208697 | ||
|
|
aa37022ef7 | ||
|
|
85c417579f | ||
|
|
baed67efc4 | ||
|
|
c5b7aa1532 | ||
|
|
904e5af128 | ||
|
|
a41d110647 | ||
|
|
a92d6ff13c | ||
|
|
05278935a3 | ||
|
|
a56cdef9b1 | ||
|
|
e9357a2deb | ||
|
|
8d94d27af0 | ||
|
|
6f2a222c59 | ||
|
|
8470a515ef | ||
|
|
06982ac43b | ||
|
|
865c3b5f92 | ||
|
|
8c9e06d7b9 | ||
|
|
a9cc128308 | ||
|
|
ccb16b467b | ||
|
|
1e44aeb92a | ||
|
|
c897f7119a | ||
|
|
ee8e2b1547 | ||
|
|
5fa38cd679 | ||
|
|
65535b5482 | ||
|
|
439a198d02 | ||
|
|
f041b02557 | ||
|
|
4d8639eb2d | ||
|
|
519c8de16f | ||
|
|
7f20af4674 | ||
|
|
55d24e5fed | ||
|
|
81f654e396 | ||
|
|
8f1dc165e2 | ||
|
|
9a0cfff57f | ||
|
|
d749eb6896 | ||
|
|
6d59ac192b | ||
|
|
94d3725cf2 | ||
|
|
8840ec0f49 | ||
|
|
44a8e86d47 | ||
|
|
73abdda442 | ||
|
|
15b03ab1a8 | ||
|
|
dc5245679a | ||
|
|
60414e5bce | ||
|
|
af40c7d667 | ||
|
|
7eb2ecda0f | ||
|
|
6d12a859bc | ||
|
|
920071e242 | ||
|
|
2a24b4bd0c | ||
|
|
a753502200 | ||
|
|
8958fae362 | ||
|
|
e2d68210d7 | ||
|
|
99534debc8 | ||
|
|
5b98629747 | ||
|
|
42003f6af3 | ||
|
|
434573b226 | ||
|
|
d6081c829c | ||
|
|
58718881ef | ||
|
|
ac669e8b92 | ||
|
|
567f1566a9 | ||
|
|
59a5687105 | ||
|
|
7b13ff9704 | ||
|
|
5e7b826a4f | ||
|
|
cbc63b9b48 | ||
|
|
71a84cbab0 | ||
|
|
55e54e464b | ||
|
|
467688dc06 | ||
|
|
375d8f913b | ||
|
|
021849204a | ||
|
|
b635f2e964 | ||
|
|
1e2b96bbee | ||
|
|
2857451ca2 | ||
|
|
2bc3835ee0 | ||
|
|
4f417448b4 | ||
|
|
503f163446 | ||
|
|
f17e769e28 | ||
|
|
f65e6a1276 | ||
|
|
4c248a3615 | ||
|
|
7794db7c0d | ||
|
|
3ca9e5d8ad | ||
|
|
5ca8a90c24 | ||
|
|
0679ac4ca9 | ||
|
|
20a0269782 | ||
|
|
a892d905bb | ||
|
|
bc880cb8d2 | ||
|
|
2243a9353e | ||
|
|
10f994a52a | ||
|
|
0f86c74eba | ||
|
|
c2b5407678 | ||
|
|
350879d8d1 | ||
|
|
a6a276027c | ||
|
|
45b79c8959 | ||
|
|
d0022dd908 | ||
|
|
e0f4a661be | ||
|
|
507433f6ca | ||
|
|
5974c662ff | ||
|
|
aa0bec8a52 | ||
|
|
2d2f71fb27 | ||
|
|
36f59b5802 | ||
|
|
7fc87d2daf | ||
|
|
3648ab3a24 | ||
|
|
7a9d183fc4 | ||
|
|
2a62f5ee19 | ||
|
|
f9cfaae952 | ||
|
|
bd4576fe4b | ||
|
|
4e194bf178 | ||
|
|
ef4e0d5e7e | ||
|
|
e6d8e70925 | ||
|
|
a6c5741c37 | ||
|
|
3ea7fc6ccf | ||
|
|
20926fbd63 | ||
|
|
2a3f3ba45d | ||
|
|
662127e6c7 | ||
|
|
0be05d6038 | ||
|
|
1f77038ef2 | ||
|
|
77ed253c73 | ||
|
|
b988781801 | ||
|
|
595251de24 | ||
|
|
c85631421d | ||
|
|
12c8cd02fc | ||
|
|
9656de5d13 | ||
|
|
9a31746b10 | ||
|
|
ceccbacc34 | ||
|
|
ff2e2ccfc1 | ||
|
|
12bda6f710 | ||
|
|
c53b6fd0ac | ||
|
|
b31243b472 | ||
|
|
c8d19f90a6 | ||
|
|
114bafe0d0 | ||
|
|
5ef8c5c6d4 | ||
|
|
9b499e9537 | ||
|
|
00f00f846b | ||
|
|
998113fedf | ||
|
|
ee5544112a | ||
|
|
7eaabd8fac | ||
|
|
4fc808dd98 | ||
|
|
7cfb250c93 | ||
|
|
47f480b619 | ||
|
|
fa9e950b1a | ||
|
|
49f4d850ce | ||
|
|
b3e15181ae | ||
|
|
aca5500aea | ||
|
|
427b6179b9 | ||
|
|
afa73c75b5 | ||
|
|
8261af7422 | ||
|
|
44e604f416 | ||
|
|
5173f99e68 | ||
|
|
8a3d4658eb | ||
|
|
6b43924848 | ||
|
|
eace352b39 | ||
|
|
fdbe8989fe | ||
|
|
18d7e9f46e | ||
|
|
c6fbd563d8 | ||
|
|
a5df33bb62 | ||
|
|
5cf4896050 | ||
|
|
2fb450bd99 | ||
|
|
4ea58045e2 | ||
|
|
29433538ff | ||
|
|
d382140904 | ||
|
|
b8e9c234e6 | ||
|
|
60ee01f517 | ||
|
|
2b28968dfb | ||
|
|
90b13cf606 | ||
|
|
d81894fc21 | ||
|
|
f5cbae9329 | ||
|
|
7a6653bc6c | ||
|
|
72f2d1b384 | ||
|
|
b66e31bf15 | ||
|
|
ea26c854af | ||
|
|
ef1f62807e | ||
|
|
d8aeda1e50 | ||
|
|
07efba8ec0 | ||
|
|
2959fe7447 | ||
|
|
4601589720 | ||
|
|
9f8225566e | ||
|
|
5e65c96705 | ||
|
|
a9d6e6fcac | ||
|
|
860dcf68ad | ||
|
|
812848323b | ||
|
|
344f9ba7fa | ||
|
|
2d5279ac9a | ||
|
|
fa3e4a0548 | ||
|
|
656c20715e | ||
|
|
a72885e042 | ||
|
|
b587adda1f | ||
|
|
50fd4832c2 | ||
|
|
c094d9320d | ||
|
|
aaccaa887d | ||
|
|
5481e42cd6 | ||
|
|
b3964d1d86 | ||
|
|
e35d9f2d6d | ||
|
|
4d16780366 | ||
|
|
1661fe9b0c | ||
|
|
63344ad4e1 | ||
|
|
90cf7d199f | ||
|
|
730df9d222 | ||
|
|
882d8c1cab | ||
|
|
17af842d2d | ||
|
|
bbe42182df | ||
|
|
81b096feef | ||
|
|
7627e92c54 | ||
|
|
f7bce90cf0 | ||
|
|
b33ce4c800 | ||
|
|
757287d8a5 | ||
|
|
3ed8eafccb | ||
|
|
d8b1c923ef | ||
|
|
4a4d2b1ba0 | ||
|
|
12fa790ea0 | ||
|
|
21955d9c92 | ||
|
|
a0d9819f8c | ||
|
|
a9af5d8eba | ||
|
|
65854cf91a | ||
|
|
9ec1ef2535 | ||
|
|
36119f6e2a | ||
|
|
e912bd4dfb | ||
|
|
c3ef136d41 | ||
|
|
8eda7a4bb8 | ||
|
|
78d146e866 | ||
|
|
77860bacd0 | ||
|
|
63cf5ae72c | ||
|
|
120cde9562 | ||
|
|
e6ffb966dd | ||
|
|
207522aef5 | ||
|
|
a1cc199b34 | ||
|
|
c22260706c | ||
|
|
d5782b52a2 | ||
|
|
85aecef6c3 | ||
|
|
876c993680 | ||
|
|
a272ff8c1b | ||
|
|
7402d58369 | ||
|
|
c0b134a445 | ||
|
|
a324d49bfc | ||
|
|
9c000f5e7b | ||
|
|
0e887ef29a | ||
|
|
fb72aaba48 | ||
|
|
a3869e9227 | ||
|
|
d671ccfc8e | ||
|
|
35bf8fa084 | ||
|
|
f7916cbf3f | ||
|
|
2b7dab686c | ||
|
|
a98cad00eb | ||
|
|
facdce2c1f | ||
|
|
34937987a6 | ||
|
|
831f06a5a5 | ||
|
|
5fe3c86f25 | ||
|
|
04f48837d1 | ||
|
|
f5b14759fb | ||
|
|
def97ff9a9 | ||
|
|
d38772e06f | ||
|
|
351f5e2f6c | ||
|
|
8778174936 | ||
|
|
e5f6a04d15 | ||
|
|
f8d47c1cb4 | ||
|
|
b5c6a6aeeb | ||
|
|
4e7d07c8d4 | ||
|
|
fc2dd77ec7 | ||
|
|
7b6fa00ff8 | ||
|
|
9ac3591366 | ||
|
|
6a819e02da | ||
|
|
4cff7c50db | ||
|
|
669302a172 | ||
|
|
c738605098 | ||
|
|
90cf838b18 | ||
|
|
67e4043e8c | ||
|
|
5e58e3f9cf | ||
|
|
49140b27c6 | ||
|
|
9cdadbb13a | ||
|
|
0ace7b2567 | ||
|
|
ccb8f5788b | ||
|
|
4e5baafedf | ||
|
|
0e82af2d27 | ||
|
|
535737bf39 | ||
|
|
6e6cc16399 | ||
|
|
bb0d8edfad | ||
|
|
ebec5eb689 | ||
|
|
5cb31dcf92 | ||
|
|
0ccffd7c80 | ||
|
|
57b66a2458 | ||
|
|
b8a39ed58a | ||
|
|
f5a910dd73 | ||
|
|
e16adcdff3 | ||
|
|
cf9b4794fd | ||
|
|
6d8c6bdbe5 | ||
|
|
8bbe41b53b | ||
|
|
ba30fb5c3c | ||
|
|
0938e8eee5 | ||
|
|
3b17384631 | ||
|
|
243c995f5f | ||
|
|
96b87581ff | ||
|
|
3de73827d7 | ||
|
|
458aeea4a6 | ||
|
|
14cbb64539 | ||
|
|
a9e4762634 | ||
|
|
487094a0d7 | ||
|
|
f608ebb106 | ||
|
|
87001ac6c2 | ||
|
|
ede1f0ebc9 | ||
|
|
b435d7174c | ||
|
|
2a59d2cc31 | ||
|
|
b8595e609a | ||
|
|
d37bc73a48 | ||
|
|
1902a7652f | ||
|
|
6ab423a5b6 | ||
|
|
c2be690cc6 | ||
|
|
f5a49d0e44 | ||
|
|
03e23e0730 | ||
|
|
eb598fac4f | ||
|
|
be0602ec3c | ||
|
|
6cbde57d88 | ||
|
|
5e4ff5f9c5 | ||
|
|
18e1289f27 | ||
|
|
99aaa6ca25 | ||
|
|
24172e4b2f | ||
|
|
beaf495400 | ||
|
|
79f48760f3 | ||
|
|
785abd4802 | ||
|
|
0ee6ca9800 | ||
|
|
7543020807 | ||
|
|
47b50b9bd0 | ||
|
|
45c49b52a4 | ||
|
|
0ee32c62d3 | ||
|
|
70e98a4348 | ||
|
|
fddf529df9 | ||
|
|
141c62659e | ||
|
|
61e16468f0 | ||
|
|
b74b3d538e | ||
|
|
d3db3eef1b | ||
|
|
90d5b12e72 | ||
|
|
955a3a3ded | ||
|
|
aec75b037b | ||
|
|
e5daa2731a | ||
|
|
390621a7ab | ||
|
|
478bb47c40 | ||
|
|
685517abd1 | ||
|
|
515afe7cf1 | ||
|
|
ec497df1a0 | ||
|
|
8e74463643 | ||
|
|
933d1dfd0f | ||
|
|
0fe987e226 | ||
|
|
770de8994e | ||
|
|
37cf7b4191 | ||
|
|
1a3ef40da9 | ||
|
|
0314302e9c | ||
|
|
9639c71842 | ||
|
|
d2da915cd0 | ||
|
|
e725abcf4e | ||
|
|
de01941274 | ||
|
|
d802ea54da | ||
|
|
c81a20fb7a | ||
|
|
6bf32edb8c | ||
|
|
4a50a2176e | ||
|
|
9e90555fd1 | ||
|
|
2067ec7342 | ||
|
|
c2c5682c0b | ||
|
|
4c72f27dd9 | ||
|
|
36d8d1a626 | ||
|
|
3447d61048 | ||
|
|
a3887c2644 | ||
|
|
8a1f3153b9 | ||
|
|
165dd4a636 | ||
|
|
541b23d144 | ||
|
|
7987ece7cc | ||
|
|
48224e4c43 | ||
|
|
6d4ecad122 | ||
|
|
1578919c37 | ||
|
|
10a1d6b4a0 | ||
|
|
2b7e12924d | ||
|
|
82f0c63e8a | ||
|
|
5d9530fe47 | ||
|
|
37f35d89d1 | ||
|
|
08c88178aa | ||
|
|
0fb2fc4a1d | ||
|
|
da2d13e3ce | ||
|
|
64318670a8 | ||
|
|
3c19f72c16 | ||
|
|
8938d67ef8 | ||
|
|
05724c07cf | ||
|
|
955c3145c3 | ||
|
|
8ea17b5098 | ||
|
|
b20fe0e6ac | ||
|
|
24787acd08 | ||
|
|
d71dad3bd3 | ||
|
|
889439c205 | ||
|
|
bee9df73c1 | ||
|
|
60613dc896 | ||
|
|
e175fb07f7 | ||
|
|
4a70af6f81 | ||
|
|
8f14cc496b | ||
|
|
3b4ecc6b80 | ||
|
|
a7e60f0c59 | ||
|
|
3d7cc5710d | ||
|
|
86fc7e6880 | ||
|
|
acee11fc60 | ||
|
|
b2e7c91313 | ||
|
|
97b7bff4d6 | ||
|
|
e16ca9ef31 | ||
|
|
b2e6caa01e | ||
|
|
2997e9f769 | ||
|
|
2374023982 | ||
|
|
902f03d101 | ||
|
|
cfe3978049 | ||
|
|
7752df41b7 | ||
|
|
d8b108c2a1 | ||
|
|
184dd27a18 | ||
|
|
0e5665d3ab | ||
|
|
ef3bb69ad8 | ||
|
|
45d41d08bd | ||
|
|
dd32e2c3d4 | ||
|
|
2b7e0f33a6 | ||
|
|
0582cdae8d | ||
|
|
9e8ea423e2 | ||
|
|
0c983c1fd4 | ||
|
|
3381ffa6ea | ||
|
|
3b15340966 | ||
|
|
91683c434b | ||
|
|
9e7530c414 | ||
|
|
8fd30fc43c | ||
|
|
b1b04fcdd4 | ||
|
|
56f0c976be | ||
|
|
9aacb4df0e | ||
|
|
0fdb1aa8ff | ||
|
|
bad0110609 | ||
|
|
3cc185a088 | ||
|
|
e8a8167ad9 | ||
|
|
854a1aad35 | ||
|
|
84e6d6fdcd | ||
|
|
f14a65d94c | ||
|
|
37439b36e7 | ||
|
|
c95ca2a228 | ||
|
|
97d8e7095f | ||
|
|
20c1926a01 | ||
|
|
d030233def | ||
|
|
35812ea1f9 | ||
|
|
d649b78920 | ||
|
|
7e43da819e | ||
|
|
40aaa571b4 | ||
|
|
470319d33b | ||
|
|
1db954e9bc | ||
|
|
d697314b42 | ||
|
|
59dd678603 | ||
|
|
02b5cb238b | ||
|
|
74de13d19c | ||
|
|
837d01dd5a | ||
|
|
926d86d1f9 | ||
|
|
aeb213ea0c | ||
|
|
7c6ea3d8c7 | ||
|
|
d409c6ac9c | ||
|
|
92f0b9d6ab | ||
|
|
2c8c8bbaad | ||
|
|
4fc8140a60 | ||
|
|
699f7024f1 | ||
|
|
ce0da32a9c | ||
|
|
82360c6b17 | ||
|
|
493568465b | ||
|
|
bf485d3d6b | ||
|
|
e90aab4982 | ||
|
|
550d4e2346 | ||
|
|
991daf008d | ||
|
|
505ada146c | ||
|
|
75c51953f1 | ||
|
|
8d6c1c4e97 | ||
|
|
10a1a3f511 | ||
|
|
40e6752fba | ||
|
|
dbefb6b4e4 | ||
|
|
6016841086 | ||
|
|
0047f535ef | ||
|
|
90eca40d27 | ||
|
|
0417c34e2d | ||
|
|
d64c2b226a | ||
|
|
868676dc15 | ||
|
|
e31058d41e | ||
|
|
ea8291d8f7 | ||
|
|
1348267518 | ||
|
|
f0323d68eb | ||
|
|
12a01be14f | ||
|
|
e0a18ce3f7 | ||
|
|
8ad5cea371 | ||
|
|
9059e0ac2f | ||
|
|
29fad7a3d8 | ||
|
|
02efda9f01 | ||
|
|
35a388b141 | ||
|
|
9a4a237ede | ||
|
|
5efbddbadb | ||
|
|
6a94c58b00 | ||
|
|
e3f8395360 | ||
|
|
f2b4c0840e | ||
|
|
08d82b84cb | ||
|
|
fbe57fdc95 | ||
|
|
92cdc39372 | ||
|
|
78be8e0fc9 | ||
|
|
a5b786d80f | ||
|
|
f853b777be | ||
|
|
fed1f3f4fe | ||
|
|
18cad44967 | ||
|
|
d17c9a4486 | ||
|
|
b6e22a47d3 | ||
|
|
ec69bdbd64 | ||
|
|
a8cbb57c9b | ||
|
|
b8cc35874e | ||
|
|
c3851185f3 | ||
|
|
e7ee91defc | ||
|
|
cfce9f6dc3 | ||
|
|
4afcb709a7 | ||
|
|
a912a980ec | ||
|
|
2c64b25827 | ||
|
|
38b9170c52 | ||
|
|
f40aa6fb07 | ||
|
|
b616493883 | ||
|
|
e86e2fa173 | ||
|
|
11bfaf6351 | ||
|
|
d37d1c44ff | ||
|
|
c89330313e | ||
|
|
c9dc1300ba | ||
|
|
53cf0b8bfb | ||
|
|
56961becc2 | ||
|
|
1dc42d123d | ||
|
|
d2ea5980ba | ||
|
|
15cf186b85 | ||
|
|
4fdb03a648 | ||
|
|
8f5b554f0b | ||
|
|
8cd3db27b6 | ||
|
|
273a7ed59f | ||
|
|
23deb0bcee | ||
|
|
7ea7bebf6b | ||
|
|
97894c6473 | ||
|
|
1f86fcf5dc | ||
|
|
bb9bdba4c9 | ||
|
|
5b9cc6953a | ||
|
|
33544bf422 | ||
|
|
20accf4d06 | ||
|
|
3fac51e21e | ||
|
|
d999d312c4 | ||
|
|
a22ca88565 | ||
|
|
9ec8bd87bb | ||
|
|
f11ece28ff | ||
|
|
f90f71498e |
23
INSTALL
23
INSTALL
@@ -1,4 +1,4 @@
|
||||
To build and install rsync
|
||||
To build and install rsync:
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
@@ -9,8 +9,15 @@ to ./configure. To see them, use:
|
||||
|
||||
$ ./configure --help
|
||||
|
||||
Configure tries to figure out if the local system uses group "nobody" or
|
||||
"nogroup" by looking in the /etc/group file. (This is only used for the
|
||||
default group of an rsync daemon, which attempts to run with "nobody"
|
||||
user and group permissions.) You can change the default user and group
|
||||
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
|
||||
config.h, or just override them in your /etc/rsyncd.conf file.
|
||||
|
||||
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
|
||||
cut-down copy of release 1.5 is included in the rsync distribution,
|
||||
cut-down copy of release 1.6.4 is included in the rsync distribution,
|
||||
and will be used if there is no popt library on your build host, or if
|
||||
the --with-included-popt option is passed to ./configure.
|
||||
|
||||
@@ -18,7 +25,6 @@ If you configure using --enable-maintainer-mode, then rsync will try
|
||||
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
|
||||
useful, but it should be turned off for production builds.
|
||||
|
||||
|
||||
RPM NOTES
|
||||
---------
|
||||
|
||||
@@ -37,16 +43,15 @@ fails:
|
||||
|
||||
Install gcc or HP's "ANSI/C Compiler".
|
||||
|
||||
|
||||
|
||||
MAC OSX NOTES
|
||||
-------------
|
||||
|
||||
Mac OS X (Darwin) seems to have an IPv6 stack, but it does not
|
||||
completely implement the "New Sockets" API.
|
||||
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
|
||||
not completely implement the "New Sockets" API.
|
||||
|
||||
<http://www.ipv6.org/impl/mac.html> says that Apple do not support
|
||||
IPv6 yet. If your build fails, try again with --disable-ipv6.
|
||||
<http://www.ipv6.org/impl/mac.html> says that Apple started to support
|
||||
IPv6 in 10.2 (Jaguar). If your build fails, try again after running
|
||||
configure with --disable-ipv6.
|
||||
|
||||
IBM AIX NOTES
|
||||
-------------
|
||||
|
||||
31
Makefile.in
31
Makefile.in
@@ -33,7 +33,7 @@ ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
|
||||
OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
|
||||
main.o checksum.o match.o syscall.o log.o backup.o
|
||||
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
|
||||
fileio.o batch.o clientname.o
|
||||
fileio.o batch.o clientname.o chmod.o
|
||||
OBJS3=progress.o pipe.o
|
||||
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
|
||||
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
@@ -90,29 +90,14 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
gen: $(srcdir)/configure $(srcdir)/config.h.in proto man
|
||||
gen:
|
||||
$(MAKE) -C $(srcdir) -f prepare-source.mak gen
|
||||
|
||||
man: $(srcdir)/rsync.1 $(srcdir)/rsyncd.conf.5
|
||||
|
||||
$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4
|
||||
cd $(srcdir); autoconf
|
||||
|
||||
$(srcdir)/config.h.in: $(srcdir)/configure.in $(srcdir)/aclocal.m4
|
||||
cd $(srcdir); autoheader
|
||||
|
||||
$(srcdir)/rsync.1: $(srcdir)/rsync.yo
|
||||
yodl2man -o $(srcdir)/rsync.1 $(srcdir)/rsync.yo
|
||||
|
||||
$(srcdir)/rsyncd.conf.5: $(srcdir)/rsyncd.conf.yo
|
||||
yodl2man -o $(srcdir)/rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
man:
|
||||
$(MAKE) -C $(srcdir) -f prepare-source.mak man
|
||||
|
||||
proto:
|
||||
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk >$(srcdir)/proto.h.new
|
||||
if diff $(srcdir)/proto.h $(srcdir)/proto.h.new >/dev/null; then \
|
||||
rm $(srcdir)/proto.h.new; \
|
||||
else \
|
||||
mv $(srcdir)/proto.h.new $(srcdir)/proto.h; \
|
||||
fi
|
||||
$(MAKE) -C $(srcdir) -f prepare-source.mak proto.h
|
||||
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
|
||||
@@ -160,8 +145,8 @@ check: all $(CHECK_PROGS)
|
||||
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin=`pwd`/rsync$(EXEEXT) srcdir="$(srcdir)" $(srcdir)/runtests.sh
|
||||
|
||||
wildtest.o: wildtest.c lib/wildmatch.c rsync.h
|
||||
wildtest$(EXEEXT): wildtest.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o @BUILD_POPT@ $(LIBS)
|
||||
wildtest$(EXEEXT): wildtest.o lib/compat.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o @BUILD_POPT@ $(LIBS)
|
||||
|
||||
# This does *not* depend on building or installing: you can use it to
|
||||
# check a version installed from a binary or some other source tree,
|
||||
|
||||
93
NEWS
93
NEWS
@@ -1,79 +1,48 @@
|
||||
NEWS for rsync 2.6.6 (UNRELEASED)
|
||||
NEWS for rsync 2.6.8 (UNRELEASED)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.5:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
- The zlib code was upgraded to version 1.2.3 in order to make it more
|
||||
secure. While the widely-publicized security problem in zlib 1.2.2 did
|
||||
not affect rsync, another security problem surfaced that affects rsync's
|
||||
zlib 1.1.4.
|
||||
Changes since 2.6.7:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- The setting of flist->high in clean_flist() was wrong for an empty list.
|
||||
This could cause flist_find() to crash in certain rare circumstances
|
||||
(e.g. if just the right directory setup was around when --fuzzy was
|
||||
combined with --link-dest).
|
||||
- Fixed a bug in the exclude code where an anchored exclude without any
|
||||
wildcards fails to match an absolute source arg, but only when --relative
|
||||
is in effect.
|
||||
|
||||
- The outputting of hard-linked files when verbosity was > 1 was not right:
|
||||
without -i it would output the name of each hard-linked file as though
|
||||
it had been changed (it now outputs a "is hard linked" message for the
|
||||
file); with -i it would output all dots for the unchanged attributes of
|
||||
a hard-link (it now changes those dots to spaces, as is done for other
|
||||
totally unchanged items).
|
||||
- Improved the I/O code for the generator to fix a potential hang when the
|
||||
receiver gets an EOF on the socket but the generator's select() call
|
||||
never indicates that the socket is writable for it to be notified about
|
||||
the EOF. (This can happen when using stunnel).
|
||||
|
||||
- When backing up a changed symlink or device, get rid of any old backup
|
||||
item so that we don't get an "already exists" error.
|
||||
- Fixed a problem with the file-reading code where a failed read (such as
|
||||
that caused by a bad sector) would make rsync think that the file's
|
||||
read-position was left after the failed read's data.
|
||||
|
||||
- A couple places that were comparing a local and a remote modification-
|
||||
time were not honoring the --modify-window option.
|
||||
- Fixed a logging bug where the "log file" directive was not being honored
|
||||
in a single-use daemon (one spawned by a remote-shell connection or by
|
||||
init).
|
||||
|
||||
- Fixed a really old, minor bug that could cause rsync to warn about being
|
||||
unable to mkdir() a path that ends in "/." because it just created the
|
||||
directory (required --relative, --no-implied-dirs, a source path that
|
||||
ended in either a trailing slash or a trailing "/.", and a non-existing
|
||||
destination dir to tickle the bug in a recent version).
|
||||
|
||||
- If the user specifies a remote-host for both the source and destination,
|
||||
we now output a syntax error rather than trying to open the destination
|
||||
hostspec as a filename.
|
||||
- If rsync cannot honor the --delete option, we output an error and exit
|
||||
instead of silently ignoring the option.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --append option that makes rsync append data onto files
|
||||
that are longer on the source than the destination (this includes new
|
||||
files).
|
||||
- In daemon mode, if rsync fails to bind to the requested port, the
|
||||
error(s) returned by socket() and/or bind() are now logged.
|
||||
|
||||
- The configure script now checks for lutimes() and lchmod() so that
|
||||
rsync can make use of them to update attributes of symlinks (on
|
||||
systems that support this).
|
||||
- When we output a fatal error, we now output the version of rsync in the
|
||||
message.
|
||||
|
||||
- Made the "max verbosity" setting in the rsyncd.conf file settable on a
|
||||
per-module basis (which now matches the documentation).
|
||||
- The rsyncstats script in "support" has an improved line-parsing regex
|
||||
that is easier to read and also makes it to parse syslog-generated lines.
|
||||
|
||||
- Added two config items to the rsyncd.conf parsing: "pre-xfer exec"
|
||||
and "post-xfer exec". These allow a command to be specified on a
|
||||
per-module basis that will be run before and/or after a daemon-mode
|
||||
transfer.
|
||||
- A new script in "support": file-attr-restore, can be used to restore the
|
||||
attributes of a file-set (the permissions, ownership, and group info)
|
||||
taken from the cached output of a "find ARG... -ls" command.
|
||||
|
||||
- The support/rrsync script has been upgraded to verify the args of options
|
||||
that take args (instead of rejecting any such options). The script was
|
||||
also changed to try to be more secure and to fix a problem in the parsing
|
||||
of a pull operation that has multiple sources.
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Improved the documentation that explains the difference between a
|
||||
normal daemon transfer and a daemon-over remote-shell transfer.
|
||||
|
||||
- Some of the diffs supplied in the patches dir were fixed and/or
|
||||
improved.
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Made configure define NOBODY_USER (currently hard-wired to "nobody") and
|
||||
NOBODY_GROUP (set to either "nobody" or "nogroup" depending on what we
|
||||
find in the /etc/group file).
|
||||
|
||||
- Added a test to the test suite, itemized.test, that tests the output of
|
||||
-i (log-format w/%i) and some double-verbose messages.
|
||||
- The acls.diff patch has been improved quite a bit, with more to come.
|
||||
|
||||
- A new patch was added: log-file.diff. This contains an early version of
|
||||
a future option, --log-file=FILE, that will allow any rsync to log its
|
||||
actions to a file (something that only a daemon supports at present).
|
||||
|
||||
407
OLDNEWS
407
OLDNEWS
@@ -1,3 +1,390 @@
|
||||
NEWS for rsync 2.6.7 (11 Mar 2006)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.6:
|
||||
|
||||
OUTPUT CHANGES:
|
||||
|
||||
- The letter 'D' in the itemized output was being used for both devices
|
||||
(character or block) as well as other special files (such as fifos and
|
||||
named sockets). This has changed to separate non-device special files
|
||||
under the 'S' designation (e.g. "cS+++++++ path/fifo"). See also the
|
||||
"--specials" option, below.
|
||||
|
||||
- The way rsync escapes unreadable characters has changed. First, rsync
|
||||
now has support for recognizing valid multibyte character sequences in
|
||||
your current locale, allowing it to escape fewer characters than before
|
||||
for a locale such as UTF-8. Second, it now uses an escape idiom of
|
||||
"\#123", which is the literal string "\#" followed by exactly 3 octal
|
||||
digits. Rsync no longer doubles a backslash character in a filename
|
||||
(e.g. it used to output "foo\\bar" when copying "foo\bar") -- now it only
|
||||
escapes a backslash that is followed by a hash-sign and 3 digits (0-9)
|
||||
(e.g. it will output "foo\#134#789" when copying "foo\#789"). See also
|
||||
the --8-bit-output (-8) option, mentioned below.
|
||||
|
||||
Script writers: the local rsync is the one that outputs escaped names,
|
||||
so if you need to support unescaping of filenames for older rsyncs, I'd
|
||||
suggest that you parse the output of "rsync --version" and only use the
|
||||
old unescaping rules for 2.6.5 and 2.6.6.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a really old bug that caused --checksum (-c) to checksum all the
|
||||
files encountered during the delete scan (ouch).
|
||||
|
||||
- Fixed a potential hang in a remote generator: when the receiver gets a
|
||||
read-error on the socket, it now signals the generator about this so that
|
||||
the generator does not try to send any of the terminating error messages
|
||||
to the client (avoiding a potential hang in some setups).
|
||||
|
||||
- Made hard-links work with symlinks and devices again.
|
||||
|
||||
- If the sender gets an early EOF reading a source file, we propagate this
|
||||
error to the receiver so that it can discard the file and try requesting
|
||||
it again (which is the existing behavior for other kinds of read errors).
|
||||
|
||||
- If a device-file/special-file changes permissions, rsync now updates the
|
||||
permissions without recreating the file.
|
||||
|
||||
- If the user specifies a remote-host for both the source and destination,
|
||||
we now output a syntax error rather than trying to open the destination
|
||||
hostspec as a filename.
|
||||
|
||||
- When --inplace creates a new destination file, rsync now creates it with
|
||||
permissions 0600 instead of 0000 -- this makes restarting possible when
|
||||
the transfer gets interrupted in the middle of sending a new file.
|
||||
|
||||
- Reject the combination of --inplace and --sparse since the sparse-output
|
||||
algorithm doesn't work when overwriting existing data.
|
||||
|
||||
- Fixed the directory name in the error that is output when pop_dir()
|
||||
fails.
|
||||
|
||||
- Really fixed the parsing of a "!" entry in .cvsignore files this time.
|
||||
|
||||
- If the generator gets a stat() error on a file, output it (this used to
|
||||
require at least -vv for the error to be seen).
|
||||
|
||||
- If waitpid() fails or the child rsync didn't exit cleanly, we now handle
|
||||
the exit status properly and generate a better error.
|
||||
|
||||
- Fixed some glitches in the double-verbose output when using --copy-dest,
|
||||
--link-dest, or --compare-dest. Also improved how the verbose output
|
||||
handles hard-links (within the transfer) that had an up-to-date alternate
|
||||
"dest" file, and copied files (via --copy-dest).
|
||||
|
||||
- Fixed the matching of the dont-compress items (e.g. *.gz) against files
|
||||
that have a path component containing a slash.
|
||||
|
||||
- If code reading a filter/exclude file an EINTR error, rsync now clears
|
||||
the error flag on the file handle so it can keep on reading.
|
||||
|
||||
- If --relative is active, the sending side cleans up trailing "/" or "/."
|
||||
suffixes to avoid triggering a bug in older rsync versions. Also, we now
|
||||
reject a ".." dir if it would be sent as a relative dir.
|
||||
|
||||
- If a non-directory is in the way of a directory and rsync is run with
|
||||
--dry-run and --delete, rsync no longer complains about not being able
|
||||
to opendir() the not-yet present directory.
|
||||
|
||||
- When --list-only is used and a non-existent local destination dir was
|
||||
also specified as a destination, rsync no longer generates a warning
|
||||
about being unable to create the missing directory.
|
||||
|
||||
- Fixed some problems with --relative --no-implied-dirs when the
|
||||
destination directory did not yet exist: we can now create a symlink or
|
||||
device when it is the first thing in the missing dir, and --fuzzy no
|
||||
longer complains about being unable to open the missing dir.
|
||||
|
||||
- Fixed a bug where the --copy-links option would not affect implied
|
||||
directories without --copy-unsafe-links (see --relative).
|
||||
|
||||
- Got rid of the need for --force to be used in some circumstances with
|
||||
--delete-after (making it consistent with --delete-before/-during).
|
||||
|
||||
- Rsync now ignores the SIGXFSZ signal, just in case your OS sends this
|
||||
when a file is too large (rsync handles the write error).
|
||||
|
||||
- Fixed a bug in the Proxy-Authorization header's base64-encoded value: it
|
||||
was not properly padded with trailing '=' chars. This only affects a
|
||||
user that need to use a password-authenticated proxy for an outgoing
|
||||
daemon-rsync connection.
|
||||
|
||||
- If we're transferring an empty directory to a new name, rsync no longer
|
||||
forces S_IWUSR if it wasn't already set, nor does it accidentally leave
|
||||
it set.
|
||||
|
||||
- Fixed a bug in the debug output (-vvvvv) that could mention the wrong
|
||||
checksum for the current file offset.
|
||||
|
||||
- Rsync no longer allows a single directory to be copied over a non-
|
||||
directory destination arg.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --append option that makes rsync append data onto files that
|
||||
are longer on the source than the destination (this includes new files).
|
||||
|
||||
- Added the --min-size=SIZE option to exclude small files from the
|
||||
transfer.
|
||||
|
||||
- Added the --compress-level option to allow you to set how aggressive
|
||||
rsync's compression should be (this option implies --compress).
|
||||
|
||||
- Enhanced the parsing of the SIZE value for --min-size and --max-size to
|
||||
allow easy entry of multiples of 1000 (instead of just multiples of 1024)
|
||||
and off-by-one values too (e.g. --max-size=8mb-1).
|
||||
|
||||
- Added the --8-bit-output (-8) option, which tells rsync to avoid escaping
|
||||
high-bit characters that it thinks are unreadable in the current locale.
|
||||
|
||||
- The new option --human-readable (-h) changes the output of --progress,
|
||||
--stats, and the end-of-run summary to be easier to read. If repeated,
|
||||
the units become powers of 1024 instead of powers of 1000. (The old
|
||||
meaning of -h, as a shorthand for --help, still works as long as you
|
||||
just use it on its own, as in "rsync -h".)
|
||||
|
||||
- If lutimes() and/or lchmod() are around, use them to allow the
|
||||
preservation of attributes on symlinks.
|
||||
|
||||
- The --link-dest option now affects symlinks and devices (when possible).
|
||||
|
||||
- Added two config items to the rsyncd.conf parsing: "pre-xfer exec" and
|
||||
"post-xfer exec". These allow a command to be specified on a per-module
|
||||
basis that will be run before and/or after a daemon-mode transfer. (See
|
||||
the man page for a list of the environment variables that are set with
|
||||
information about the transfer.)
|
||||
|
||||
- When using the --relative option, you can now insert a dot dir in
|
||||
the source path to indicate where the replication of the source dirs
|
||||
should start. For example, if you specify a source path of
|
||||
rsync://host/module/foo/bar/./baz/dir with -R, rsync will now only
|
||||
replicate the "baz/dir" part of the source path (note: a trailing
|
||||
dot dir is unaffected unless it also has a trailing slash).
|
||||
|
||||
- Added some new --no-FOO options that make it easier to override unwanted
|
||||
implied or default options. For example, "-a --no-o" (aka "--archive
|
||||
--no-owner") can be used to turn off the preservation of file ownership
|
||||
that is implied by -a.
|
||||
|
||||
- Added the --chmod=MODE option that allows the destination permissions to
|
||||
be changed from the source permissions. E.g. --chmod=g+w,o-rwx
|
||||
|
||||
- Added the "incoming chmod" and "outgoing chmod" daemon options that allow
|
||||
a module to specify what permissions changes should be applied to all
|
||||
files copied to and from the daemon.
|
||||
|
||||
- Allow the --temp-dir option to be specified when starting a daemon, which
|
||||
sets the default temporary directory for incoming files.
|
||||
|
||||
- If --delete is combined with --dirs without --recursive, rsync will now
|
||||
delete in any directory whose content is being synchronized.
|
||||
|
||||
- If --backup is combined with --delete without --backup-dir (and without
|
||||
--delete-excluded), we add a "protect" filter-rule to ensure that files
|
||||
with the backup suffix are not deleted.
|
||||
|
||||
- The file-count stats that are output by --progress were improved to
|
||||
better indicate what the numbers mean. For instance, the output:
|
||||
"(xfer#5, to-check=8383/9999)" indicates that this was the fifth file
|
||||
to be transferred, and we still need to check 8383 more files out of
|
||||
a total of 9999.
|
||||
|
||||
- The include/exclude code now allows a dir/*** directive (with 3 trailing
|
||||
stars) to match both the dir itself as well as all the content below the
|
||||
dir (dir/** would not match the dir).
|
||||
|
||||
- Added the --prune-empty-dirs (-m) option that makes the receiving rsync
|
||||
discard empty chains of directories from the file-list. This makes it
|
||||
easier to selectively copy files from a source hierarchy and end up with
|
||||
just the directories needed to hold the resulting files.
|
||||
|
||||
- If the --itemize-changes (-i) option is repeated, rsync now includes
|
||||
unchanged files in the itemized output (similar to -vv, but without all
|
||||
the other verbose messages that can get in the way). Of course, the
|
||||
client must be version 2.6.7 for this to work, but the remote rsync only
|
||||
needs to be 2.6.7 if you're pushing files.
|
||||
|
||||
- Added the --specials option to tell rsync to copy non-device special
|
||||
files (which rsync now attempts even as a normal user). The --devices
|
||||
option now requests the copying of just devices (character and block).
|
||||
The -D option still requests both (e.g. --devices and --specials), -a
|
||||
still implies -D, and non-root users still get a silent downgrade that
|
||||
omits device copying.
|
||||
|
||||
- Added the --super option to make the receiver always attempt super-user
|
||||
activities. This is useful for systems that allow things such as devices
|
||||
to be created or ownership to be set without being UID 0, and is also
|
||||
useful for someone who wants to ensure that errors will be output if the
|
||||
receiving rsync isn't being run as root.
|
||||
|
||||
- Added the --sockopts option for those few who want to customize the TCP
|
||||
options used to contact a daemon rsync.
|
||||
|
||||
- Added a way for the --temp-dir option to be combined with a partial-dir
|
||||
setting that lets rsync avoid non-atomic updates (for those times when
|
||||
--temp-dir is not being used because space is tight).
|
||||
|
||||
- A new support script, files-to-excludes, will transform a list of files
|
||||
into a set of include/exclude directives that will copy those files.
|
||||
|
||||
- A new option, --executability (-E) can be used to preserve just the
|
||||
execute bit on files, for those times when using the --perms option is
|
||||
not desired.
|
||||
|
||||
- The daemon now logs each connection and also each module-list request
|
||||
that it receives.
|
||||
|
||||
- New log-format options: %M (modtime), %U (uid), %G (gid), and %B
|
||||
(permission bits, e.g. "rwxr-xrwt").
|
||||
|
||||
- The --dry-run option no longer forces the enabling of --verbose.
|
||||
|
||||
- The --remove-sent-files option now does a better job of incrementally
|
||||
removing the sent files on the sending side (older versions tended to
|
||||
clump up all the removals at the end).
|
||||
|
||||
- A daemon now supersedes its minimal SIGCHLD handler with the standard
|
||||
PID-remembering version after forking. This ensures that the generator
|
||||
can get the child-exit status from the receiver.
|
||||
|
||||
- Use of the --bwlimit option no longer interferes with the remote rsync
|
||||
sending error messages about invalid/refused options.
|
||||
|
||||
- Rsync no longer returns a usage error when used with one local source arg
|
||||
and no destination: this now implies the --list-only option, just like
|
||||
the comparable situation with a remote source arg.
|
||||
|
||||
- Added the --copy-dirlinks option, a more limited version of --copy-links.
|
||||
|
||||
- Various documentation improvements, including: a better synopsis, some
|
||||
improved examples, a better discussion of the presence and absence of
|
||||
--perms (including how it interacts with the new --executability and
|
||||
--chmod options), an extended discussion of --temp-dir, an improved
|
||||
discussion of --partial-dir, a better description of rsync's pattern
|
||||
matching characters, an improved --no-implied-dirs section, and the
|
||||
documenting of what the --stats option outputs.
|
||||
|
||||
- Various new and updated diffs in the patches dir, including: acls.diff,
|
||||
xattrs.diff, atimes.diff, detect-renamed.diff, and slp.diff.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- We now use sigaction() and sigprocmask() if possible, and fall back on
|
||||
signal() if not. Using sigprocmask() ensures that rsync enables all the
|
||||
signals that it needs, just in case it was started in a masked state.
|
||||
|
||||
- Some buffer sizes were expanded a bit, particularly on systems where
|
||||
MAXPATHLEN is overly small (e.g. cygwin).
|
||||
|
||||
- If io_printf() tries to format more data than fits in the buffer, exit
|
||||
with an error instead of transmitting a truncated buffer.
|
||||
|
||||
- If a va_copy macro is defined, lib/snprintf.c will use it when defining
|
||||
the VA_COPY macro.
|
||||
|
||||
- Reduced the amount of stack memory needed for each level of directory
|
||||
recursion by nearly MAXPATHLEN bytes.
|
||||
|
||||
- The wildmatch function was extended to allow an array of strings to be
|
||||
supplied as the string to match. This allows the exclude code to do less
|
||||
string copying.
|
||||
|
||||
- Got rid of the safe_fname() function (and all the myriad calls) and
|
||||
replaced it with a new function in the log.c code that filters all the
|
||||
output going to the terminal.
|
||||
|
||||
- Unified the f_name() and the f_name_to() functions.
|
||||
|
||||
- Improved the hash-table code the sender uses to handle checksums to make
|
||||
it use slightly less memory and run just a little faster.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The diffs in the patches dir now require "patch -p1 <DIFF" instead of
|
||||
the previous -p0. Also, the version included in the release tar now
|
||||
affect generated files (e.g. configure, rsync.1, proto.h, etc.), so
|
||||
it is no longer necessary to run autoconf and/or yodl unless you're
|
||||
applying a patch that was checked out from CVS.
|
||||
|
||||
- Several diffs in the patches dir now use the proper --enable-FOO
|
||||
configure option instead of --with-FOO to turn on the inclusion of
|
||||
the newly patched feature.
|
||||
|
||||
- There is a new script, "prepare-source" than can be used to update the
|
||||
various generated files (proto.h, configure, etc.) even before configure
|
||||
has created the Makefile (this is mainly useful when patching the source
|
||||
with a patch that doesn't affect generated files).
|
||||
|
||||
- The testsuite now sets HOME so that it won't be affected by a file such
|
||||
as ~/.popt.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.6 (28 Jul 2005)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.5:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
- The zlib code was upgraded to version 1.2.3 in order to make it more
|
||||
secure. While the widely-publicized security problem in zlib 1.2.2 did
|
||||
not affect rsync, another security problem surfaced that affects rsync's
|
||||
zlib 1.1.4.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- The setting of flist->high in clean_flist() was wrong for an empty list.
|
||||
This could cause flist_find() to crash in certain rare circumstances
|
||||
(e.g. if just the right directory setup was around when --fuzzy was
|
||||
combined with --link-dest).
|
||||
|
||||
- The outputting of hard-linked files when verbosity was > 1 was not right:
|
||||
(1) Without -i it would output the name of each hard-linked file as
|
||||
though it had been changed; it now outputs a "is hard linked" message for
|
||||
the file. (2) With -i it would output all dots for the unchanged
|
||||
attributes of a hard-link; it now changes those dots to spaces, as is
|
||||
done for other totally unchanged items.
|
||||
|
||||
- When backing up a changed symlink or device, get rid of any old backup
|
||||
item so that we don't get an "already exists" error.
|
||||
|
||||
- A couple places that were comparing a local and a remote modification-
|
||||
time were not honoring the --modify-window option.
|
||||
|
||||
- Fixed a bug where the 'p' (permissions) itemized-changes flag might get
|
||||
set too often (if some non-significant mode bits differed).
|
||||
|
||||
- Fixed a really old, minor bug that could cause rsync to warn about being
|
||||
unable to mkdir() a path that ends in "/." because it just created the
|
||||
directory (required --relative, --no-implied-dirs, a source path that
|
||||
ended in either a trailing slash or a trailing "/.", and a non-existing
|
||||
destination dir to tickle the bug in a recent version).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Made the "max verbosity" setting in the rsyncd.conf file settable on a
|
||||
per-module basis (which now matches the documentation).
|
||||
|
||||
- The support/rrsync script has been upgraded to verify the args of options
|
||||
that take args (instead of rejecting any such options). The script was
|
||||
also changed to try to be more secure and to fix a problem in the parsing
|
||||
of a pull operation that has multiple sources.
|
||||
|
||||
- Improved the documentation that explains the difference between a
|
||||
normal daemon transfer and a daemon-over remote-shell transfer.
|
||||
|
||||
- Some of the diffs supplied in the patches dir were fixed and/or
|
||||
improved.
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Made configure define NOBODY_USER (currently hard-wired to "nobody") and
|
||||
NOBODY_GROUP (set to either "nobody" or "nogroup" depending on what we
|
||||
find in the /etc/group file).
|
||||
|
||||
- Added a test to the test suite, itemized.test, that tests the output of
|
||||
-i (log-format w/%i) and some double-verbose messages.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.5 (1 Jun 2005)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.4:
|
||||
@@ -228,7 +615,7 @@ Changes since 2.6.3:
|
||||
|
||||
- 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.)
|
||||
mkstemp(). (Fix derived from 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.
|
||||
@@ -293,9 +680,11 @@ Changes since 2.6.3:
|
||||
(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.)
|
||||
- The output of the items that are being updated by the generator (dirs,
|
||||
symlinks, devices) is now intermingled in the proper order with the
|
||||
output from the items that the receiver is updating (regular files)
|
||||
when pulling. This misordering was particularly bad when --progress
|
||||
was specified. (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
|
||||
@@ -702,6 +1091,8 @@ Changes since 2.6.2:
|
||||
user chose to combine the output of rsync's stdout and stderr (e.g.
|
||||
using the "2>&1").
|
||||
|
||||
- Fixed an option-parsing bug when --files-from got passed to a daemon.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --partial-dir=DIR option that lets you specify where to
|
||||
@@ -915,7 +1306,7 @@ Changes since 2.6.0:
|
||||
- We now reset the "new data has been sent" flag at the start of
|
||||
each file we send. This makes sure that an interrupted transfer
|
||||
with the --partial option set doesn't keep a shorter temp file
|
||||
than the current basis file when no new data has been transfered
|
||||
than the current basis file when no new data has been transferred
|
||||
over the wire for that file.
|
||||
|
||||
- Fixed a byte-order problem in --batch-mode on big-endian machines.
|
||||
@@ -968,6 +1359,9 @@ Changes since 2.6.0:
|
||||
- Fixed the ability to request an empty backup --suffix when sending
|
||||
files to an rsync daemon.
|
||||
|
||||
- Fixed an option-parsing bug when --files-from was sent to a server
|
||||
sender.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Most of the I/O is now buffered, which results in a pretty large
|
||||
@@ -1619,6 +2013,9 @@ Changes since 2.4.6:
|
||||
|
||||
Partial Protocol History
|
||||
RELEASE DATE VER. DATE OF COMMIT* PROTOCOL
|
||||
?? Apr 2006 2.6.8 29
|
||||
11 Mar 2006 2.6.7 29
|
||||
28 Jul 2005 2.6.6 29
|
||||
01 Jun 2005 2.6.5 29
|
||||
30 Mar 2005 2.6.4 17 Jan 2005 29
|
||||
30 Sep 2004 2.6.3 28
|
||||
|
||||
120
TODO
120
TODO
@@ -1,22 +1,17 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
BUGS ---------------------------------------------------------------
|
||||
Do not rely on having a group called "nobody"
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
Use chroot only if supported
|
||||
Allow supplementary groups in rsyncd.conf 2002/04/09
|
||||
Handling IPv6 on old machines
|
||||
Other IPv6 stuff:
|
||||
Other IPv6 stuff
|
||||
Add ACL support 2001/12/02
|
||||
Lazy directory creation
|
||||
proxy authentication 2002/01/23
|
||||
SOCKS 2002/01/23
|
||||
FAT support
|
||||
Allow forcing arbitrary permissions 2002/03/12
|
||||
--diff david.e.sewell 2002/03/15
|
||||
Add daemon --no-fork option
|
||||
Create more granular verbosity jw 2003/05/15
|
||||
Create more granular verbosity 2003/05/15
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
Keep list of open issues and todos on the web site
|
||||
@@ -25,22 +20,19 @@ Perhaps redo manual as SGML
|
||||
LOGGING --------------------------------------------------------------
|
||||
Memory accounting
|
||||
Improve error messages
|
||||
Better statistics: Rasmus 2002/03/08
|
||||
Better statistics Rasmus 2002/03/08
|
||||
Perhaps flush stdout like syslog
|
||||
Log deamon sessions that just list modules
|
||||
Log child death on signal
|
||||
Log errors with function that reports process of origin
|
||||
verbose output David Stein 2001/12/20
|
||||
internationalization
|
||||
|
||||
DEVELOPMENT --------------------------------------------------------
|
||||
Handling duplicate names
|
||||
Use generic zlib 2002/02/25
|
||||
TDB: 2002/03/12
|
||||
TDB 2002/03/12
|
||||
Splint 2002/03/12
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
File list structure in memory
|
||||
Traverse just one directory at a time
|
||||
Allow skipping MD4 file_sum 2002/04/08
|
||||
Accelerate MD4
|
||||
@@ -52,8 +44,6 @@ Test on kernel source
|
||||
Test large files
|
||||
Create mutator program for testing
|
||||
Create configure option to enable dangerous tests
|
||||
If tests are skipped, say why.
|
||||
Test daemon feature to disallow particular options.
|
||||
Create pipe program for testing
|
||||
Create test makefile target for some tests
|
||||
|
||||
@@ -66,17 +56,6 @@ reverse rsync over HTTP Range
|
||||
|
||||
|
||||
|
||||
BUGS ---------------------------------------------------------------
|
||||
|
||||
|
||||
Do not rely on having a group called "nobody"
|
||||
|
||||
http://www.linuxbase.org/spec/refspecs/LSB_1.1.0/gLSB/usernames.html
|
||||
|
||||
On Debian it's "nogroup"
|
||||
|
||||
-- --
|
||||
|
||||
FEATURES ------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -133,7 +112,7 @@ Handling IPv6 on old machines
|
||||
-- --
|
||||
|
||||
|
||||
Other IPv6 stuff:
|
||||
Other IPv6 stuff
|
||||
|
||||
Implement suggestions from http://www.kame.net/newsletter/19980604/
|
||||
and ftp://ftp.iij.ad.jp/pub/RFC/rfc2553.txt
|
||||
@@ -159,15 +138,6 @@ Add ACL support 2001/12/02
|
||||
-- --
|
||||
|
||||
|
||||
Lazy directory creation
|
||||
|
||||
With the current common --include '*/' --exclude '*' pattern, people
|
||||
can end up with many empty directories. We might avoid this by
|
||||
lazily creating such directories.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
proxy authentication 2002/01/23
|
||||
|
||||
Allow RSYNC_PROXY to be http://user:pass@proxy.foo:3128/, and do
|
||||
@@ -199,35 +169,6 @@ FAT support
|
||||
-- --
|
||||
|
||||
|
||||
Allow forcing arbitrary permissions 2002/03/12
|
||||
|
||||
On 12 Mar 2002, Dave Dykstra <dwd@bell-labs.com> wrote:
|
||||
> If we would add an option to do that functionality, I
|
||||
> would vote for one that was more general which could mask
|
||||
> off any set of permission bits and possibly add any set of
|
||||
> bits. Perhaps a chmod-like syntax if it could be
|
||||
> implemented simply.
|
||||
|
||||
I think that would be good too. For example, people uploading files
|
||||
to a web server might like to say
|
||||
|
||||
rsync -avzP --chmod a+rX ./ sourcefrog.net:/home/www/sourcefrog/
|
||||
|
||||
Ideally the patch would implement as many of the gnu chmod semantics
|
||||
as possible. I think the mode parser should be a separate function
|
||||
that passes back something like (mask,set) description to the rest
|
||||
of the program. For bonus points there would be a test case for the
|
||||
parser.
|
||||
|
||||
Possibly also --chown
|
||||
|
||||
(Debian #23628)
|
||||
|
||||
NOTE: there is a patch that implements this in the "patches" subdir.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
--diff david.e.sewell 2002/03/15
|
||||
|
||||
Allow people to specify the diff command. (Might want to use wdiff,
|
||||
@@ -252,7 +193,7 @@ Add daemon --no-fork option
|
||||
-- --
|
||||
|
||||
|
||||
Create more granular verbosity jw 2003/05/15
|
||||
Create more granular verbosity 2003/05/15
|
||||
|
||||
Control output with the --report option.
|
||||
|
||||
@@ -322,14 +263,10 @@ Improve error messages
|
||||
our load? (Debian #28416) Probably fixed now, but a test case would
|
||||
be good.
|
||||
|
||||
When running as a daemon, some errors should both be returned to the
|
||||
user and logged. This will make interacting with a daemon less
|
||||
cryptic.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Better statistics: Rasmus 2002/03/08
|
||||
Better statistics Rasmus 2002/03/08
|
||||
|
||||
<Rasmus>
|
||||
hey, how about an rsync option that just gives you the
|
||||
@@ -355,14 +292,6 @@ Perhaps flush stdout like syslog
|
||||
-- --
|
||||
|
||||
|
||||
Log deamon sessions that just list modules
|
||||
|
||||
At the connections that just get a list of modules are not logged,
|
||||
but they should be.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Log child death on signal
|
||||
|
||||
If a child of the rsync daemon dies with a signal, we should notice
|
||||
@@ -371,15 +300,6 @@ Log child death on signal
|
||||
-- --
|
||||
|
||||
|
||||
Log errors with function that reports process of origin
|
||||
|
||||
Use a separate function for reporting errors; prefix it with
|
||||
"rsync:" or "rsync(remote)", or perhaps even "rsync(local
|
||||
generator): ".
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
verbose output David Stein 2001/12/20
|
||||
|
||||
At end of transfer, show how many files were or were not transferred
|
||||
@@ -445,7 +365,7 @@ Use generic zlib 2002/02/25
|
||||
-- --
|
||||
|
||||
|
||||
TDB: 2002/03/12
|
||||
TDB 2002/03/12
|
||||
|
||||
Rather than storing the file list in memory, store it in a TDB.
|
||||
|
||||
@@ -472,20 +392,6 @@ Splint 2002/03/12
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
|
||||
File list structure in memory
|
||||
|
||||
Rather than one big array, perhaps have a tree in memory mirroring
|
||||
the directory tree.
|
||||
|
||||
This might make sorting much faster! (I'm not sure it's a big CPU
|
||||
problem, mind you.)
|
||||
|
||||
It might also reduce memory use in storing repeated directory names
|
||||
-- again I'm not sure this is a problem.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Traverse just one directory at a time
|
||||
|
||||
Traverse just one directory at a time. Tridge says it's possible.
|
||||
@@ -586,16 +492,6 @@ Create configure option to enable dangerous tests
|
||||
-- --
|
||||
|
||||
|
||||
If tests are skipped, say why.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Test daemon feature to disallow particular options.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Create pipe program for testing
|
||||
|
||||
Create pipe program that makes slow/jerky connections for
|
||||
|
||||
2
access.c
2
access.c
@@ -208,7 +208,7 @@ static int match_address(char *addr, char *tok)
|
||||
|
||||
ret = match_binary(a, t, mask, addrlen);
|
||||
|
||||
out:
|
||||
out:
|
||||
freeaddrinfo(resa);
|
||||
freeaddrinfo(rest);
|
||||
return ret;
|
||||
|
||||
@@ -21,21 +21,18 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern char *password_file;
|
||||
extern int am_root;
|
||||
|
||||
/***************************************************************************
|
||||
encode a buffer using base64 - simple and slow algorithm. null terminates
|
||||
the result.
|
||||
***************************************************************************/
|
||||
void base64_encode(char *buf, int len, char *out)
|
||||
void base64_encode(char *buf, int len, char *out, int pad)
|
||||
{
|
||||
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i;
|
||||
unsigned char *d = (unsigned char *)buf;
|
||||
int bytes = (len*8 + 5)/6;
|
||||
|
||||
memset(out, 0, bytes+1);
|
||||
|
||||
for (i = 0; i < bytes; i++) {
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
@@ -49,6 +46,11 @@ void base64_encode(char *buf, int len, char *out)
|
||||
}
|
||||
out[i] = b64[idx];
|
||||
}
|
||||
|
||||
while (pad && (i % 4))
|
||||
out[i++] = '=';
|
||||
|
||||
out[i] = '\0';
|
||||
}
|
||||
|
||||
/* Generate a challenge buffer and return it base64-encoded. */
|
||||
@@ -70,7 +72,7 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
sum_update(input, sizeof input);
|
||||
sum_end(md4_out);
|
||||
|
||||
base64_encode(md4_out, MD4_SUM_LENGTH, challenge);
|
||||
base64_encode(md4_out, MD4_SUM_LENGTH, challenge, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,13 +92,13 @@ 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)", safe_fname(fname));
|
||||
rsyserr(FLOG, errno, "stat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
|
||||
ok = 0;
|
||||
} else if (am_root && (st.st_uid != 0)) {
|
||||
} else if (MY_UID() == 0 && st.st_uid != 0) {
|
||||
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
ok = 0;
|
||||
}
|
||||
@@ -160,19 +162,19 @@ static char *getpassf(char *filename)
|
||||
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FERROR, errno, "could not open password file \"%s\"",
|
||||
safe_fname(filename));
|
||||
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)", safe_fname(filename));
|
||||
rsyserr(FERROR, errno, "stat(%s)", filename);
|
||||
ok = 0;
|
||||
} else if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR,"password file must not be other-accessible\n");
|
||||
ok = 0;
|
||||
} else if (am_root && st.st_uid != 0) {
|
||||
} else if (MY_UID() == 0 && st.st_uid != 0) {
|
||||
rprintf(FERROR,"password file must be owned by root when running as root\n");
|
||||
ok = 0;
|
||||
}
|
||||
@@ -209,7 +211,7 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
sum_update(challenge, strlen(challenge));
|
||||
sum_end(buf);
|
||||
|
||||
base64_encode(buf, MD4_SUM_LENGTH, out);
|
||||
base64_encode(buf, MD4_SUM_LENGTH, out, 0);
|
||||
}
|
||||
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
@@ -223,7 +225,7 @@ char *auth_server(int f_in, int f_out, int module, char *host, char *addr,
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
char challenge[MD4_SUM_LENGTH*2];
|
||||
char line[MAXPATHLEN];
|
||||
char line[BIGPATHBUFLEN];
|
||||
char secret[512];
|
||||
char pass2[MD4_SUM_LENGTH*2];
|
||||
char *tok, *pass;
|
||||
|
||||
37
backup.c
37
backup.c
@@ -21,7 +21,6 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int backup_suffix_len;
|
||||
extern int backup_dir_len;
|
||||
extern unsigned int backup_dir_remainder;
|
||||
extern char backup_dir_buf[MAXPATHLEN];
|
||||
@@ -30,9 +29,8 @@ extern char *backup_dir;
|
||||
|
||||
extern int am_root;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int orig_umask;
|
||||
extern int safe_symlinks;
|
||||
|
||||
/* make a complete pathname for backup file */
|
||||
@@ -65,8 +63,7 @@ static int make_simple_backup(char *fname)
|
||||
if (do_rename(fname, fnamebak) == 0) {
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
safe_fname(fname),
|
||||
safe_fname(fnamebak));
|
||||
fname, fnamebak);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -81,7 +78,7 @@ static int make_simple_backup(char *fname)
|
||||
continue;
|
||||
|
||||
rsyserr(FERROR, rename_errno, "rename %s to backup %s",
|
||||
safe_fname(fname), safe_fname(fnamebak));
|
||||
fname, fnamebak);
|
||||
errno = rename_errno;
|
||||
return 0;
|
||||
}
|
||||
@@ -112,7 +109,7 @@ static int make_bak_dir(char *fullpath)
|
||||
}
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (do_mkdir(fullpath, 0777 & ~orig_umask) == 0)
|
||||
if (mkdir_defmode(fullpath) == 0)
|
||||
break;
|
||||
if (errno != ENOENT) {
|
||||
rsyserr(FERROR, errno,
|
||||
@@ -141,7 +138,7 @@ static int make_bak_dir(char *fullpath)
|
||||
p += strlen(p);
|
||||
if (p == end)
|
||||
break;
|
||||
if (do_mkdir(fullpath, 0777 & ~orig_umask) < 0) {
|
||||
if (mkdir_defmode(fullpath) < 0) {
|
||||
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
@@ -149,7 +146,7 @@ static int make_bak_dir(char *fullpath)
|
||||
}
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
failure:
|
||||
while (p != end) {
|
||||
*p = '/';
|
||||
p += strlen(p);
|
||||
@@ -160,8 +157,9 @@ failure:
|
||||
/* robustly move a file, creating new directory structures if necessary */
|
||||
static int robust_move(char *src, char *dst)
|
||||
{
|
||||
if (robust_rename(src, dst, 0755) < 0 && (errno != ENOENT
|
||||
|| make_bak_dir(dst) < 0 || robust_rename(src, dst, 0755) < 0))
|
||||
if (robust_rename(src, dst, NULL, 0755) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(dst) < 0
|
||||
|| robust_rename(src, dst, NULL, 0755) < 0))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -181,14 +179,15 @@ static int keep_backup(char *fname)
|
||||
if (do_lstat(fname, &st) < 0)
|
||||
return 1;
|
||||
|
||||
if (!(file = make_file(fname, NULL, NO_FILTERS)))
|
||||
if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
|
||||
return 1; /* the file could have disappeared */
|
||||
|
||||
if (!(buf = get_backup_name(fname)))
|
||||
return 0;
|
||||
|
||||
/* Check to see if this is a device file, or link */
|
||||
if (IS_DEVICE(file->mode) && am_root && preserve_devices) {
|
||||
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|
||||
|| (preserve_specials && IS_SPECIAL(file->mode))) {
|
||||
do_unlink(buf);
|
||||
if (do_mknod(buf, file->mode, file->u.rdev) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
@@ -197,7 +196,7 @@ static int keep_backup(char *fname)
|
||||
full_fname(buf));
|
||||
} else if (verbose > 2) {
|
||||
rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
|
||||
safe_fname(fname));
|
||||
fname);
|
||||
}
|
||||
kept = 1;
|
||||
do_unlink(fname);
|
||||
@@ -235,7 +234,7 @@ static int keep_backup(char *fname)
|
||||
|| do_symlink(file->u.link, buf) < 0)) {
|
||||
rsyserr(FERROR, errno, "link %s -> \"%s\"",
|
||||
full_fname(buf),
|
||||
safe_fname(file->u.link));
|
||||
file->u.link);
|
||||
}
|
||||
do_unlink(fname);
|
||||
kept = 1;
|
||||
@@ -245,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",
|
||||
safe_fname(fname));
|
||||
fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -253,19 +252,19 @@ 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), safe_fname(buf));
|
||||
full_fname(fname), buf);
|
||||
} else if (st.st_nlink > 1) {
|
||||
/* If someone has hard-linked the file into the backup
|
||||
* dir, rename() might return success but do nothing! */
|
||||
robust_unlink(fname); /* Just in case... */
|
||||
}
|
||||
}
|
||||
set_perms(buf, file, NULL, 0);
|
||||
set_file_attrs(buf, file, NULL, 0);
|
||||
free(file);
|
||||
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
safe_fname(fname), safe_fname(buf));
|
||||
fname, buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
59
batch.c
59
batch.c
@@ -6,9 +6,9 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "zlib/zlib.h"
|
||||
#include <time.h>
|
||||
|
||||
extern int am_sender;
|
||||
extern int eol_nulls;
|
||||
extern int recurse;
|
||||
extern int xfer_dirs;
|
||||
@@ -19,11 +19,14 @@ extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int always_checksum;
|
||||
extern int do_compression;
|
||||
extern int def_compress_level;
|
||||
extern int protocol_version;
|
||||
extern char *batch_name;
|
||||
|
||||
extern struct filter_list_struct filter_list;
|
||||
|
||||
static int tweaked_compress_level;
|
||||
|
||||
static int *flag_ptr[] = {
|
||||
&recurse, /* 0 */
|
||||
&preserve_uid, /* 1 */
|
||||
@@ -33,7 +36,7 @@ static int *flag_ptr[] = {
|
||||
&preserve_hard_links, /* 5 */
|
||||
&always_checksum, /* 6 */
|
||||
&xfer_dirs, /* 7 (protocol 29) */
|
||||
&do_compression, /* 8 (protocol 29) */
|
||||
&tweaked_compress_level,/* 8 (protocol 29) */
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -54,6 +57,12 @@ void write_stream_flags(int fd)
|
||||
{
|
||||
int i, flags;
|
||||
|
||||
#if Z_DEFAULT_COMPRESSION == -1
|
||||
tweaked_compress_level = do_compression ? def_compress_level + 2 : 0;
|
||||
#else
|
||||
#error internal logic error! Fix def_compress_level logic above and below too!
|
||||
#endif
|
||||
|
||||
/* Start the batch file with a bitmap of data-stream-affecting
|
||||
* flags. */
|
||||
if (protocol_version < 29)
|
||||
@@ -88,6 +97,13 @@ void read_stream_flags(int fd)
|
||||
else if (xfer_dirs < 2)
|
||||
xfer_dirs = 0;
|
||||
}
|
||||
|
||||
if (tweaked_compress_level == 0 || tweaked_compress_level == 2)
|
||||
do_compression = 0;
|
||||
else {
|
||||
do_compression = 1;
|
||||
def_compress_level = tweaked_compress_level - 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_arg(int fd, char *arg)
|
||||
@@ -148,7 +164,7 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
S_IRUSR | S_IWUSR | S_IEXEC);
|
||||
if (fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
safe_fname(filename));
|
||||
filename);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
@@ -194,42 +210,7 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
write_filter_rules(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error",
|
||||
safe_fname(filename));
|
||||
filename);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void show_flist(int index, struct file_struct **fptr)
|
||||
{
|
||||
/* for debugging show_flist(flist->count, flist->files * */
|
||||
|
||||
int i;
|
||||
for (i = 0; i < index; i++) {
|
||||
rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
|
||||
rprintf(FINFO, "flist->modtime=%#lx\n",
|
||||
(long unsigned) fptr[i]->modtime);
|
||||
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",
|
||||
safe_fname(fptr[i]->basename));
|
||||
if (fptr[i]->dirname) {
|
||||
rprintf(FINFO, "flist->dirname=%s\n",
|
||||
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[])
|
||||
{
|
||||
int 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]));
|
||||
}
|
||||
|
||||
205
chmod.c
Normal file
205
chmod.c
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern mode_t orig_umask;
|
||||
|
||||
#define FLAG_X_KEEP (1<<0)
|
||||
#define FLAG_DIRS_ONLY (1<<1)
|
||||
#define FLAG_FILES_ONLY (1<<2)
|
||||
|
||||
struct chmod_mode_struct {
|
||||
struct chmod_mode_struct *next;
|
||||
int ModeAND, ModeOR;
|
||||
char flags;
|
||||
};
|
||||
|
||||
#define CHMOD_ADD 1
|
||||
#define CHMOD_SUB 2
|
||||
#define CHMOD_EQ 3
|
||||
|
||||
#define STATE_ERROR 0
|
||||
#define STATE_1ST_HALF 1
|
||||
#define STATE_2ND_HALF 2
|
||||
|
||||
/* Parse a chmod-style argument, and break it down into one or more AND/OR
|
||||
* pairs in a linked list. We return a pointer to new items on succcess
|
||||
* (appending the items to the specified list), or NULL on error. */
|
||||
struct chmod_mode_struct *parse_chmod(const char *modestr,
|
||||
struct chmod_mode_struct **root_mode_ptr)
|
||||
{
|
||||
int state = STATE_1ST_HALF;
|
||||
int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0;
|
||||
struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL,
|
||||
*prev_mode = NULL;
|
||||
|
||||
while (state != STATE_ERROR) {
|
||||
if (!*modestr || *modestr == ',') {
|
||||
int bits;
|
||||
|
||||
if (!op) {
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
prev_mode = curr_mode;
|
||||
curr_mode = new_array(struct chmod_mode_struct, 1);
|
||||
if (prev_mode)
|
||||
prev_mode->next = curr_mode;
|
||||
else
|
||||
first_mode = curr_mode;
|
||||
curr_mode->next = NULL;
|
||||
|
||||
if (where)
|
||||
bits = where * what;
|
||||
else {
|
||||
where = 0111;
|
||||
bits = (where * what) & ~orig_umask;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case CHMOD_ADD:
|
||||
curr_mode->ModeAND = CHMOD_BITS;
|
||||
curr_mode->ModeOR = bits + topoct;
|
||||
break;
|
||||
case CHMOD_SUB:
|
||||
curr_mode->ModeAND = CHMOD_BITS - bits - topoct;
|
||||
curr_mode->ModeOR = 0;
|
||||
break;
|
||||
case CHMOD_EQ:
|
||||
curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
|
||||
curr_mode->ModeOR = bits + topoct;
|
||||
break;
|
||||
}
|
||||
|
||||
curr_mode->flags = flags;
|
||||
|
||||
if (!*modestr)
|
||||
break;
|
||||
modestr++;
|
||||
|
||||
state = STATE_1ST_HALF;
|
||||
where = what = op = topoct = topbits = flags = 0;
|
||||
}
|
||||
|
||||
if (state != STATE_2ND_HALF) {
|
||||
switch (*modestr) {
|
||||
case 'D':
|
||||
if (flags & FLAG_FILES_ONLY)
|
||||
state = STATE_ERROR;
|
||||
flags |= FLAG_DIRS_ONLY;
|
||||
break;
|
||||
case 'F':
|
||||
if (flags & FLAG_DIRS_ONLY)
|
||||
state = STATE_ERROR;
|
||||
flags |= FLAG_FILES_ONLY;
|
||||
break;
|
||||
case 'u':
|
||||
where |= 0100;
|
||||
topbits |= 04000;
|
||||
break;
|
||||
case 'g':
|
||||
where |= 0010;
|
||||
topbits |= 02000;
|
||||
break;
|
||||
case 'o':
|
||||
where |= 0001;
|
||||
break;
|
||||
case 'a':
|
||||
where |= 0111;
|
||||
break;
|
||||
case '+':
|
||||
op = CHMOD_ADD;
|
||||
state = STATE_2ND_HALF;
|
||||
break;
|
||||
case '-':
|
||||
op = CHMOD_SUB;
|
||||
state = STATE_2ND_HALF;
|
||||
break;
|
||||
case '=':
|
||||
op = CHMOD_EQ;
|
||||
state = STATE_2ND_HALF;
|
||||
break;
|
||||
default:
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (*modestr) {
|
||||
case 'r':
|
||||
what |= 4;
|
||||
break;
|
||||
case 'w':
|
||||
what |= 2;
|
||||
break;
|
||||
case 'X':
|
||||
flags |= FLAG_X_KEEP;
|
||||
/* FALL THROUGH */
|
||||
case 'x':
|
||||
what |= 1;
|
||||
break;
|
||||
case 's':
|
||||
if (topbits)
|
||||
topoct |= topbits;
|
||||
else
|
||||
topoct = 04000;
|
||||
break;
|
||||
case 't':
|
||||
topoct |= 01000;
|
||||
break;
|
||||
default:
|
||||
state = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
modestr++;
|
||||
}
|
||||
|
||||
if (state == STATE_ERROR) {
|
||||
free_chmod_mode(first_mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(curr_mode = *root_mode_ptr))
|
||||
*root_mode_ptr = first_mode;
|
||||
else {
|
||||
while (curr_mode->next)
|
||||
curr_mode = curr_mode->next;
|
||||
curr_mode->next = first_mode;
|
||||
}
|
||||
|
||||
return first_mode;
|
||||
}
|
||||
|
||||
|
||||
/* Takes an existing file permission and a list of AND/OR changes, and
|
||||
* create a new permissions. */
|
||||
int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes)
|
||||
{
|
||||
int IsX = mode & 0111;
|
||||
int NonPerm = mode & ~CHMOD_BITS;
|
||||
|
||||
for ( ; chmod_modes; chmod_modes = chmod_modes->next) {
|
||||
if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm))
|
||||
continue;
|
||||
if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm))
|
||||
continue;
|
||||
mode &= chmod_modes->ModeAND;
|
||||
if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm))
|
||||
mode |= chmod_modes->ModeOR & ~0111;
|
||||
else
|
||||
mode |= chmod_modes->ModeOR;
|
||||
}
|
||||
|
||||
return mode | NonPerm;
|
||||
}
|
||||
|
||||
/* Free the linked list created by parse_chmod. */
|
||||
int free_chmod_mode(struct chmod_mode_struct *chmod_modes)
|
||||
{
|
||||
struct chmod_mode_struct *next;
|
||||
|
||||
while (chmod_modes) {
|
||||
next = chmod_modes->next;
|
||||
free(chmod_modes);
|
||||
chmod_modes = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
21
cleanup.c
21
cleanup.c
@@ -26,6 +26,10 @@ extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
extern char *partial_dir;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Close all open sockets and files, allowing a (somewhat) graceful
|
||||
* shutdown() of socket connections. This eliminates the abortive
|
||||
@@ -94,17 +98,18 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
}
|
||||
inside_cleanup++;
|
||||
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
SIGACTION(SIGUSR1, SIG_IGN);
|
||||
SIGACTION(SIGUSR2, SIG_IGN);
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
code, safe_fname(file), line);
|
||||
code, file, line);
|
||||
}
|
||||
|
||||
if (cleanup_child_pid != -1) {
|
||||
int status;
|
||||
if (waitpid(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) {
|
||||
if (wait_process(cleanup_child_pid, &status, WNOHANG)
|
||||
== cleanup_child_pid) {
|
||||
status = WEXITSTATUS(status);
|
||||
if (status > code)
|
||||
code = status;
|
||||
@@ -121,8 +126,8 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
flush_write_file(cleanup_fd_w);
|
||||
close(cleanup_fd_w);
|
||||
}
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file, 0,
|
||||
!partial_dir);
|
||||
finish_transfer(cleanup_new_fname, fname, NULL,
|
||||
cleanup_file, 0, !partial_dir);
|
||||
}
|
||||
io_flush(FULL_FLUSH);
|
||||
if (cleanup_fname)
|
||||
@@ -149,7 +154,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, safe_fname(file), line, code);
|
||||
ocode, file, line, code);
|
||||
}
|
||||
|
||||
close_all();
|
||||
@@ -166,7 +171,7 @@ void cleanup_disable(void)
|
||||
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
|
||||
int fd_r, int fd_w)
|
||||
{
|
||||
cleanup_fname = fnametmp;
|
||||
cleanup_fname = fname ? fnametmp : NULL;
|
||||
cleanup_new_fname = fname;
|
||||
cleanup_file = file;
|
||||
cleanup_fd_r = fd_r;
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "rsync.h"
|
||||
|
||||
static const char default_name[] = "UNKNOWN";
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
|
||||
|
||||
@@ -321,7 +320,6 @@ int check_name(int fd,
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* Given all these results, we expect that one of them will be
|
||||
* the same as ss. The comparison is a bit complicated. */
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
|
||||
259
clientserver.c
259
clientserver.c
@@ -28,6 +28,7 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int quiet;
|
||||
extern int list_only;
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
@@ -41,23 +42,31 @@ extern int filesfrom_fd;
|
||||
extern int remote_protocol;
|
||||
extern int protocol_version;
|
||||
extern int io_timeout;
|
||||
extern int orig_umask;
|
||||
extern int no_detach;
|
||||
extern int default_af_hint;
|
||||
extern mode_t orig_umask;
|
||||
extern char *bind_address;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern char *sockopts;
|
||||
extern char *config_file;
|
||||
extern char *files_from;
|
||||
extern char *tmpdir;
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
|
||||
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;
|
||||
struct chmod_mode_struct *daemon_chmod_modes;
|
||||
|
||||
/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */
|
||||
unsigned int module_dirlen = 0;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Run a client connected to an rsyncd. The alternative to this
|
||||
* function for remote-shell connections is do_cmd().
|
||||
@@ -97,6 +106,8 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
if (fd == -1)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
set_socket_options(fd, sockopts);
|
||||
|
||||
ret = start_inband_exchange(user, path, fd, fd, argc);
|
||||
|
||||
return ret ? ret : client_run(fd, fd, -1, argc, argv);
|
||||
@@ -108,7 +119,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
int i;
|
||||
char *sargs[MAX_ARGS];
|
||||
int sargc = 0;
|
||||
char line[MAXPATHLEN];
|
||||
char line[BIGPATHBUFLEN];
|
||||
char *p;
|
||||
|
||||
if (argc == 0 && !am_sender)
|
||||
@@ -215,27 +226,62 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *finish_pre_exec(pid_t pid, int fd, char *request,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int j, status = -1;
|
||||
|
||||
if (request) {
|
||||
write_buf(fd, request, strlen(request)+1);
|
||||
for (j = 0; j < argc; j++)
|
||||
write_buf(fd, argv[j], strlen(argv[j])+1);
|
||||
}
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i)
|
||||
write_byte(fd, 0);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (wait_process(pid, &status, 0) < 0
|
||||
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
char *e;
|
||||
if (asprintf(&e, "pre-xfer exec returned failure (%d)\n", status) < 0)
|
||||
out_of_memory("finish_pre_exec");
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int read_arg_from_pipe(int fd, char *buf, int limit)
|
||||
{
|
||||
char *bp = buf, *eob = buf + limit - 1;
|
||||
|
||||
while (1) {
|
||||
if (read(fd, bp, 1) != 1)
|
||||
return -1;
|
||||
if (*bp == '\0')
|
||||
break;
|
||||
if (bp < eob)
|
||||
bp++;
|
||||
}
|
||||
*bp = '\0';
|
||||
|
||||
return bp - buf;
|
||||
}
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
{
|
||||
int argc = 0;
|
||||
int maxargs;
|
||||
char **argv;
|
||||
char **argp;
|
||||
char line[MAXPATHLEN];
|
||||
char line[BIGPATHBUFLEN];
|
||||
uid_t uid = (uid_t)-2; /* canonically "nobody" */
|
||||
gid_t gid = (gid_t)-2;
|
||||
char *p;
|
||||
#ifdef HAVE_PUTENV
|
||||
char *s;
|
||||
#endif
|
||||
char *addr = client_addr(f_in);
|
||||
char *host = client_name(f_in);
|
||||
char *p, *err_msg = NULL;
|
||||
char *name = lp_name(i);
|
||||
int use_chroot = lp_use_chroot(i);
|
||||
int start_glob = 0;
|
||||
int ret;
|
||||
int ret, pre_exec_fd = -1;
|
||||
pid_t pre_exec_pid = 0;
|
||||
char *request = NULL;
|
||||
|
||||
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
|
||||
@@ -259,7 +305,7 @@ 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",
|
||||
safe_fname(lp_lock_file(i)));
|
||||
lp_lock_file(i));
|
||||
io_printf(f_out, "@ERROR: failed to open lock file\n");
|
||||
} else {
|
||||
rprintf(FLOG, "max connections (%d) reached\n",
|
||||
@@ -329,31 +375,29 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
p = lp_filter(i);
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ANCHORED2ABS);
|
||||
XFLG_ABS_IF_SLASH);
|
||||
|
||||
p = lp_include_from(i);
|
||||
parse_filter_file(&server_filter_list, p, MATCHFLG_INCLUDE,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_include(i);
|
||||
parse_rule(&server_filter_list, p,
|
||||
MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES);
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
|
||||
|
||||
p = lp_exclude_from(i);
|
||||
parse_filter_file(&server_filter_list, p, 0,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_exclude(i);
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES);
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
|
||||
|
||||
log_init();
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
s = lp_prexfer_exec(i);
|
||||
p = lp_postxfer_exec(i);
|
||||
if ((s && *s) || (p && *p)) {
|
||||
if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {
|
||||
char *modname, *modpath, *hostaddr, *hostname, *username;
|
||||
int status;
|
||||
if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
|
||||
@@ -368,15 +412,10 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
putenv(hostname);
|
||||
putenv(username);
|
||||
umask(orig_umask);
|
||||
if (s && *s) {
|
||||
status = system(s);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
rprintf(FLOG, "prexfer-exec failed\n");
|
||||
io_printf(f_out, "@ERROR: prexfer-exec failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (p && *p) {
|
||||
/* For post-xfer exec, fork a new process to run the rsync
|
||||
* daemon while this process waits for the exit status and
|
||||
* runs the indicated command at that point. */
|
||||
if (*lp_postxfer_exec(i)) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
rsyserr(FLOG, errno, "fork failed");
|
||||
@@ -385,7 +424,8 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
}
|
||||
if (pid) {
|
||||
char *ret1, *ret2;
|
||||
waitpid(pid, &status, 0);
|
||||
if (wait_process(pid, &status, 0) < 0)
|
||||
status = -1;
|
||||
if (asprintf(&ret1, "RSYNC_RAW_STATUS=%d", status) > 0)
|
||||
putenv(ret1);
|
||||
if (WIFEXITED(status))
|
||||
@@ -394,10 +434,55 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
status = -1;
|
||||
if (asprintf(&ret2, "RSYNC_EXIT_STATUS=%d", status) > 0)
|
||||
putenv(ret2);
|
||||
system(p);
|
||||
system(lp_postxfer_exec(i));
|
||||
_exit(status);
|
||||
}
|
||||
}
|
||||
/* For pre-xfer exec, fork a child process to run the indicated
|
||||
* command, though it first waits for the parent process to
|
||||
* send us the user's request via a pipe. */
|
||||
if (*lp_prexfer_exec(i)) {
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0 || (pre_exec_pid = fork()) < 0) {
|
||||
rsyserr(FLOG, errno, "pre-xfer exec preparation failed");
|
||||
io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (pre_exec_pid == 0) {
|
||||
char buf[BIGPATHBUFLEN];
|
||||
int j, len;
|
||||
close(fds[1]);
|
||||
set_blocking(fds[0]);
|
||||
len = read_arg_from_pipe(fds[0], buf, BIGPATHBUFLEN);
|
||||
if (len <= 0)
|
||||
_exit(1);
|
||||
if (asprintf(&p, "RSYNC_REQUEST=%s", buf) < 0)
|
||||
out_of_memory("rsync_module");
|
||||
putenv(p);
|
||||
for (j = 0; ; j++) {
|
||||
len = read_arg_from_pipe(fds[0], buf,
|
||||
BIGPATHBUFLEN);
|
||||
if (len <= 0) {
|
||||
if (!len)
|
||||
break;
|
||||
_exit(1);
|
||||
}
|
||||
if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) < 0)
|
||||
out_of_memory("rsync_module");
|
||||
putenv(p);
|
||||
}
|
||||
close(fds[0]);
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
status = system(lp_prexfer_exec(i));
|
||||
if (!WIFEXITED(status))
|
||||
_exit(1);
|
||||
_exit(WEXITSTATUS(status));
|
||||
}
|
||||
close(fds[0]);
|
||||
set_blocking(fds[1]);
|
||||
pre_exec_fd = fds[1];
|
||||
}
|
||||
umask(0);
|
||||
}
|
||||
#endif
|
||||
@@ -417,14 +502,14 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
*/
|
||||
if (chroot(lp_path(i))) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed",
|
||||
safe_fname(lp_path(i)));
|
||||
lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/")) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n",
|
||||
safe_fname(lp_path(i)));
|
||||
lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -432,7 +517,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
} else {
|
||||
if (!push_dir(lp_path(i))) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n",
|
||||
safe_fname(lp_path(i)));
|
||||
lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -474,6 +559,16 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
am_root = (MY_UID() == 0);
|
||||
}
|
||||
|
||||
if (lp_temp_dir(i) && *lp_temp_dir(i)) {
|
||||
tmpdir = lp_temp_dir(i);
|
||||
if (strlen(tmpdir) >= MAXPATHLEN - 10) {
|
||||
rprintf(FLOG,
|
||||
"the 'temp dir' value for %s is WAY too long -- ignoring.\n",
|
||||
name);
|
||||
tmpdir = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
io_printf(f_out, "@RSYNCD: OK\n");
|
||||
|
||||
maxargs = MAX_ARGS;
|
||||
@@ -498,22 +593,37 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
if (!(argv[argc] = strdup(p)))
|
||||
out_of_memory("rsync_module");
|
||||
|
||||
if (start_glob) {
|
||||
if (start_glob == 1) {
|
||||
request = strdup(p);
|
||||
start_glob++;
|
||||
}
|
||||
glob_expand(name, &argv, &argc, &maxargs);
|
||||
} else
|
||||
switch (start_glob) {
|
||||
case 0:
|
||||
argc++;
|
||||
if (strcmp(line, ".") == 0)
|
||||
start_glob = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (pre_exec_pid) {
|
||||
err_msg = finish_pre_exec(pre_exec_pid,
|
||||
pre_exec_fd, p,
|
||||
argc, argv);
|
||||
pre_exec_pid = 0;
|
||||
}
|
||||
request = strdup(p);
|
||||
start_glob = 2;
|
||||
/* FALL THROUGH */
|
||||
default:
|
||||
if (!err_msg)
|
||||
glob_expand(name, &argv, &argc, &maxargs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(line, ".") == 0)
|
||||
start_glob = 1;
|
||||
if (pre_exec_pid) {
|
||||
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
|
||||
argc, argv);
|
||||
}
|
||||
|
||||
verbose = 0; /* future verbosity is controlled by client options */
|
||||
argp = argv;
|
||||
ret = parse_arguments(&argc, (const char ***) &argp, 0);
|
||||
ret = parse_arguments(&argc, (const char ***) &argv, 0);
|
||||
quiet = 0; /* Don't let someone try to be tricky. */
|
||||
|
||||
if (filesfrom_fd == 0)
|
||||
filesfrom_fd = f_in;
|
||||
@@ -540,7 +650,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
if (protocol_version < 23
|
||||
&& (protocol_version == 22 || am_sender))
|
||||
io_start_multiplex_out();
|
||||
else if (!ret) {
|
||||
else if (!ret || err_msg) {
|
||||
/* We have to get I/O multiplexing started so that we can
|
||||
* get the error back to the client. This means getting
|
||||
* the protocol setup finished first in later versions. */
|
||||
@@ -566,8 +676,11 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
option_error();
|
||||
if (!ret || err_msg) {
|
||||
if (err_msg)
|
||||
rprintf(FERROR, err_msg);
|
||||
else
|
||||
option_error();
|
||||
msleep(400);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
@@ -575,7 +688,20 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
if (lp_timeout(i) && lp_timeout(i) > io_timeout)
|
||||
set_io_timeout(lp_timeout(i));
|
||||
|
||||
start_server(f_in, f_out, argc, argp);
|
||||
/* If we have some incoming/outgoing chmod changes, append them to
|
||||
* any user-specified changes (making our changes have priority).
|
||||
* We also get a pointer to just our changes so that a receiver
|
||||
* process can use them separately if --perms wasn't specified. */
|
||||
if (am_sender)
|
||||
p = lp_outgoing_chmod(i);
|
||||
else
|
||||
p = lp_incoming_chmod(i);
|
||||
if (*p && !(daemon_chmod_modes = parse_chmod(p, &chmod_modes))) {
|
||||
rprintf(FLOG, "Invalid \"%sing chmod\" directive: %s\n",
|
||||
am_sender ? "outgo" : "incom", p);
|
||||
}
|
||||
|
||||
start_server(f_in, f_out, argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -601,20 +727,29 @@ static void send_listing(int fd)
|
||||
here */
|
||||
int start_daemon(int f_in, int f_out)
|
||||
{
|
||||
char line[200];
|
||||
char *motd;
|
||||
char line[1024];
|
||||
char *motd, *addr, *host;
|
||||
int i;
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
|
||||
/* We must load the config file before calling any function that
|
||||
* might cause log-file output to occur. This ensures that the
|
||||
* "log file" param gets honored for the 2 non-forked use-cases
|
||||
* (when rsync is run by init and run by a remote shell). */
|
||||
if (!lp_load(config_file, 0))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
|
||||
log_init();
|
||||
addr = client_addr(f_in);
|
||||
host = client_name(f_in);
|
||||
rprintf(FLOG, "connect from %s (%s)\n", host, addr);
|
||||
|
||||
if (!am_server) {
|
||||
set_socket_options(f_in, "SO_KEEPALIVE");
|
||||
set_socket_options(f_in, lp_socket_options());
|
||||
if (sockopts)
|
||||
set_socket_options(f_in, sockopts);
|
||||
else
|
||||
set_socket_options(f_in, lp_socket_options());
|
||||
set_nonblocking(f_in);
|
||||
}
|
||||
|
||||
@@ -650,6 +785,8 @@ int start_daemon(int f_in, int f_out)
|
||||
return -1;
|
||||
|
||||
if (!*line || strcmp(line, "#list") == 0) {
|
||||
rprintf(FLOG, "module-list request from %s (%s)\n",
|
||||
host, addr);
|
||||
send_listing(f_out);
|
||||
return -1;
|
||||
}
|
||||
@@ -661,17 +798,19 @@ int start_daemon(int f_in, int f_out)
|
||||
}
|
||||
|
||||
if ((i = lp_number(line)) < 0) {
|
||||
char *addr = client_addr(f_in);
|
||||
char *host = client_name(f_in);
|
||||
rprintf(FLOG, "unknown module '%s' tried from %s (%s)\n",
|
||||
line, host, addr);
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rsync_module(f_in, f_out, i);
|
||||
}
|
||||
#ifdef HAVE_SIGACTION
|
||||
sigact.sa_flags = SA_NOCLDSTOP;
|
||||
#endif
|
||||
SIGACTION(SIGCHLD, remember_children);
|
||||
|
||||
return rsync_module(f_in, f_out, i, addr, host);
|
||||
}
|
||||
|
||||
int daemon_main(void)
|
||||
{
|
||||
@@ -719,7 +858,7 @@ int daemon_main(void)
|
||||
0666 & ~orig_umask)) == -1) {
|
||||
cleanup_set_pid(0);
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s",
|
||||
safe_fname(pid_file));
|
||||
pid_file);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
|
||||
|
||||
49
compat.c
49
compat.c
@@ -29,12 +29,12 @@ 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 prune_empty_dirs;
|
||||
extern int protocol_version;
|
||||
extern char *dest_option;
|
||||
|
||||
@@ -78,25 +78,38 @@ 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 (protocol_version < 29) {
|
||||
if (fuzzy_basis) {
|
||||
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 && inplace) {
|
||||
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 (basis_dir_cnt > 1) {
|
||||
rprintf(FERROR,
|
||||
"Using more than one %s option requires protocol"
|
||||
" 29 or higher (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (prune_empty_dirs) {
|
||||
rprintf(FERROR,
|
||||
"--prune-empty-dirs requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
if (am_server) {
|
||||
|
||||
86
configure.in
86
configure.in
@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
RSYNC_VERSION=2.6.6pre1
|
||||
RSYNC_VERSION=2.6.8pre1
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -26,8 +26,7 @@ AC_SUBST(SHELL)
|
||||
AC_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
|
||||
if test "x$ac_cv_prog_cc_stdc" = xno
|
||||
then
|
||||
if test x"$ac_cv_prog_cc_stdc" = x"no"; then
|
||||
AC_MSG_WARN([rsync requires an ANSI C compiler and you don't seem to have one])
|
||||
fi
|
||||
|
||||
@@ -38,12 +37,10 @@ fi
|
||||
|
||||
AC_MSG_CHECKING([whether to include debugging symbols])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--enable-debug],
|
||||
[including debugging symbols and features (default yes)]),
|
||||
[], [])
|
||||
AC_HELP_STRING([--disable-debug],
|
||||
[turn off debugging symbols and features]))
|
||||
|
||||
if test x"$enable_debug" = x"no"
|
||||
then
|
||||
if test x"$enable_debug" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
CFLAGS=${CFLAGS-"-O"}
|
||||
else
|
||||
@@ -56,10 +53,8 @@ fi
|
||||
|
||||
AC_ARG_ENABLE(profile,
|
||||
AC_HELP_STRING([--enable-profile],
|
||||
[turn on CPU profiling (default no)],
|
||||
[], []))
|
||||
if test x"$enable_profile" = xyes
|
||||
then
|
||||
[turn on CPU profiling]))
|
||||
if test x"$enable_profile" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -pg"
|
||||
fi
|
||||
|
||||
@@ -67,10 +62,8 @@ fi
|
||||
# Specifically, this turns on panic_action handling.
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
AC_HELP_STRING([--enable-maintainer-mode],
|
||||
[turn on extra debug features],
|
||||
[], []))
|
||||
if test x"$enable_maintainer_mode" = xyes
|
||||
then
|
||||
[turn on extra debug features]))
|
||||
if test x"$enable_maintainer_mode" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -DMAINTAINER_MODE"
|
||||
fi
|
||||
|
||||
@@ -80,16 +73,15 @@ fi
|
||||
CFLAGS="$CFLAGS -DHAVE_CONFIG_H"
|
||||
|
||||
# If GCC, turn on warnings.
|
||||
if test x"$GCC" = x"yes"
|
||||
then
|
||||
if test x"$GCC" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -Wall -W"
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(included-popt,
|
||||
[ --with-included-popt use bundled popt library, not from system])
|
||||
AC_HELP_STRING([--with-included-popt], [use bundled popt library, not from system]))
|
||||
|
||||
AC_ARG_WITH(rsync-path,
|
||||
[ --with-rsync-path=PATH set default --rsync-path to PATH (default: rsync)],
|
||||
AC_HELP_STRING([--with-rsync-path=PATH], [set default --rsync-path to PATH (default: rsync)]),
|
||||
[ RSYNC_PATH="$with_rsync_path" ],
|
||||
[ RSYNC_PATH="rsync" ])
|
||||
|
||||
@@ -124,8 +116,7 @@ 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
|
||||
if test x"$with_rsh" != x; then
|
||||
RSYNC_RSH="$with_rsh"
|
||||
else
|
||||
RSYNC_RSH="ssh"
|
||||
@@ -144,7 +135,7 @@ AC_MSG_RESULT($NOBODY_GROUP)
|
||||
AC_DEFINE_UNQUOTED(NOBODY_USER, "nobody", [unprivileged user--e.g. nobody])
|
||||
AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user])
|
||||
|
||||
# arrgh. libc in the current debian stable screws up the largefile
|
||||
# arrgh. libc in some old debian version screwed up the largefile
|
||||
# stuff, getting byte range locking wrong
|
||||
AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[
|
||||
AC_TRY_RUN([
|
||||
@@ -190,21 +181,9 @@ ipv6lib=none
|
||||
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_HELP_STRING([--disable-ipv6],
|
||||
[don't even try to use IPv6]))
|
||||
if test x"$enable_ipv6" != x"no"; then
|
||||
AC_MSG_CHECKING([ipv6 stack type])
|
||||
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
|
||||
case $i in
|
||||
@@ -293,6 +272,16 @@ yes
|
||||
AC_SEARCH_LIBS(getaddrinfo, inet6)
|
||||
fi
|
||||
|
||||
dnl Do you want to disable use of locale functions
|
||||
AC_ARG_ENABLE([locale],
|
||||
AC_HELP_STRING([--disable-locale],
|
||||
[turn off locale features]))
|
||||
AH_TEMPLATE([CONFIG_LOCALE],
|
||||
[Undefine if you don't want locale features. By default this is defined.])
|
||||
if test x"$enable_locale" != x"no"; then
|
||||
AC_DEFINE(CONFIG_LOCALE)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to call shutdown on all sockets])
|
||||
case $host_os in
|
||||
*cygwin* ) AC_MSG_RESULT(yes)
|
||||
@@ -310,7 +299,7 @@ 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 locale.h \
|
||||
netdb.h malloc.h float.h)
|
||||
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h)
|
||||
AC_HEADER_MAJOR
|
||||
|
||||
AC_CHECK_SIZEOF(int)
|
||||
@@ -377,7 +366,11 @@ if test x"$ac_cv_func_connect" = x"no"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB(resolv, inet_ntop)
|
||||
AC_SEARCH_LIBS(inet_ntop, resolv)
|
||||
|
||||
# Solaris and HP-UX weirdness:
|
||||
# Search for libiconv_open (not iconv_open) to discover if -liconv is needed!
|
||||
AC_SEARCH_LIBS(libiconv_open, iconv)
|
||||
|
||||
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
|
||||
|
||||
@@ -501,7 +494,8 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
|
||||
strerror putenv)
|
||||
strerror putenv iconv_open locale_charset nl_langinfo \
|
||||
sigaction sigprocmask)
|
||||
|
||||
AC_CHECK_FUNCS(getpgrp tcgetpgrp)
|
||||
if test $ac_cv_func_getpgrp = yes; then
|
||||
@@ -542,14 +536,12 @@ if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function])
|
||||
fi
|
||||
|
||||
if test x"$with_included_popt" != x"yes"
|
||||
then
|
||||
if test x"$with_included_popt" != x"yes"; then
|
||||
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to use included libpopt])
|
||||
if test x"$with_included_popt" = x"yes"
|
||||
then
|
||||
if test x"$with_included_popt" = x"yes"; then
|
||||
AC_MSG_RESULT($srcdir/popt)
|
||||
BUILD_POPT='$(popt_OBJS)'
|
||||
CFLAGS="$CFLAGS -I$srcdir/popt"
|
||||
@@ -694,7 +686,7 @@ AC_TRY_RUN([
|
||||
#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;}
|
||||
if (rc) {printf("(%d %d) ",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
|
||||
@@ -708,7 +700,7 @@ AC_TRY_RUN([
|
||||
#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;}
|
||||
if (rc) {printf("(%d %d) ",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
|
||||
|
||||
@@ -34,8 +34,11 @@
|
||||
#define RERR_STREAMIO 12 /* error in rsync protocol data stream */
|
||||
#define RERR_MESSAGEIO 13 /* errors with program diagnostics */
|
||||
#define RERR_IPC 14 /* error in IPC code */
|
||||
#define RERR_CRASHED 15 /* sibling crashed */
|
||||
#define RERR_TERMINATED 16 /* sibling terminated abnormally */
|
||||
|
||||
#define RERR_SIGNAL 20 /* status returned when sent SIGUSR1, SIGINT */
|
||||
#define RERR_SIGNAL1 19 /* status returned when sent SIGUSR1 */
|
||||
#define RERR_SIGNAL 20 /* status returned when sent SIGINT, SIGTERM, SIGHUP */
|
||||
#define RERR_WAITCHILD 21 /* some error returned by waitpid() */
|
||||
#define RERR_MALLOC 22 /* error allocating core memory buffers */
|
||||
#define RERR_PARTIAL 23 /* partial transfer */
|
||||
|
||||
158
exclude.c
158
exclude.c
@@ -34,6 +34,7 @@ extern int list_only;
|
||||
extern int recurse;
|
||||
extern int io_error;
|
||||
extern int local_server;
|
||||
extern int prune_empty_dirs;
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
extern int cvs_exclude;
|
||||
@@ -46,8 +47,8 @@ extern unsigned int curr_dir_len;
|
||||
extern unsigned int module_dirlen;
|
||||
|
||||
struct filter_list_struct filter_list = { 0, 0, "" };
|
||||
struct filter_list_struct cvs_filter_list = { 0, 0, " [cvsignore]" };
|
||||
struct filter_list_struct server_filter_list = { 0, 0, " [server]" };
|
||||
struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" };
|
||||
struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
|
||||
|
||||
/* Need room enough for ":MODS " prefix plus some room to grow. */
|
||||
#define MAX_RULE_PREFIX (16)
|
||||
@@ -133,9 +134,9 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
listp->debug_type);
|
||||
}
|
||||
|
||||
/* This flag also indicates that we're reading a list that
|
||||
/* These flags also indicate that we're reading a list that
|
||||
* needs to be filtered now, not post-filtered later. */
|
||||
if (xflags & XFLG_ANCHORED2ABS) {
|
||||
if (xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH)) {
|
||||
uint32 mf = mflags & (MATCHFLG_RECEIVER_SIDE|MATCHFLG_SENDER_SIDE);
|
||||
if (am_sender) {
|
||||
if (mf == MATCHFLG_RECEIVER_SIDE)
|
||||
@@ -150,10 +151,14 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
out_of_memory("add_rule");
|
||||
memset(ret, 0, sizeof ret[0]);
|
||||
|
||||
if (xflags & XFLG_ANCHORED2ABS && *pat == '/'
|
||||
&& !(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))) {
|
||||
if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))
|
||||
&& ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/')
|
||||
|| (xflags & XFLG_ABS_IF_SLASH && strchr(pat, '/') != NULL))) {
|
||||
mflags |= MATCHFLG_ABS_PATH;
|
||||
ex_len = dirbuf_len - module_dirlen - 1;
|
||||
if (*pat == '/')
|
||||
ex_len = dirbuf_len - module_dirlen - 1;
|
||||
else
|
||||
ex_len = 0;
|
||||
} else
|
||||
ex_len = 0;
|
||||
if (!(ret->pattern = new_array(char, ex_len + pat_len + 1)))
|
||||
@@ -170,6 +175,12 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
/* If the pattern starts with **, note that. */
|
||||
if (cp == ret->pattern)
|
||||
mflags |= MATCHFLG_WILD2_PREFIX;
|
||||
/* If the pattern ends with ***, note that. */
|
||||
if (pat_len >= 3
|
||||
&& ret->pattern[pat_len-3] == '*'
|
||||
&& ret->pattern[pat_len-2] == '*'
|
||||
&& ret->pattern[pat_len-1] == '*')
|
||||
mflags |= MATCHFLG_WILD3_SUFFIX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +303,7 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
|
||||
}
|
||||
if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
|
||||
rprintf(FERROR, "merge-file name overflows: %s\n",
|
||||
safe_fname(merge_file));
|
||||
merge_file);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
@@ -305,8 +316,7 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
|
||||
goto done;
|
||||
|
||||
if (dirbuf_len + fn_len >= MAXPATHLEN) {
|
||||
rprintf(FERROR, "merge-file name overflows: %s\n",
|
||||
safe_fname(fn));
|
||||
rprintf(FERROR, "merge-file name overflows: %s\n", fn);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
|
||||
@@ -488,71 +498,69 @@ void pop_local_filters(void *mem)
|
||||
|
||||
static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir)
|
||||
{
|
||||
char *p, full_name[MAXPATHLEN];
|
||||
int match_start = 0;
|
||||
int slash_handling, str_cnt = 0, anchored_match = 0;
|
||||
int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1;
|
||||
char *pattern = ex->pattern;
|
||||
char *p, *pattern = ex->pattern;
|
||||
const char *strings[16]; /* more than enough */
|
||||
|
||||
if (!*name)
|
||||
return 0;
|
||||
|
||||
/* If the pattern does not have any slashes AND it does not have
|
||||
* a "**" (which could match a slash), then we just match the
|
||||
* name portion of the path. */
|
||||
if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
/* If the pattern does not have any slashes AND it does
|
||||
* not have a "**" (which could match a slash), then we
|
||||
* just match the name portion of the path. */
|
||||
if ((p = strrchr(name,'/')) != NULL)
|
||||
name = p+1;
|
||||
}
|
||||
else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
|
||||
} else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
|
||||
&& curr_dir_len > module_dirlen + 1) {
|
||||
pathjoin(full_name, sizeof full_name,
|
||||
curr_dir + module_dirlen + 1, name);
|
||||
name = full_name;
|
||||
/* If we're matching against an absolute-path pattern,
|
||||
* we need to prepend our full path info. */
|
||||
strings[str_cnt++] = curr_dir + module_dirlen + 1;
|
||||
strings[str_cnt++] = "/";
|
||||
} else if (ex->match_flags & MATCHFLG_WILD2_PREFIX && *name != '/') {
|
||||
/* Allow "**"+"/" to match at the start of the string. */
|
||||
strings[str_cnt++] = "/";
|
||||
}
|
||||
|
||||
if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir)
|
||||
strings[str_cnt++] = name;
|
||||
if (name_is_dir) {
|
||||
/* Allow a trailing "/"+"***" to match the directory. */
|
||||
if (ex->match_flags & MATCHFLG_WILD3_SUFFIX)
|
||||
strings[str_cnt++] = "/";
|
||||
} else if (ex->match_flags & MATCHFLG_DIRECTORY)
|
||||
return !ret_match;
|
||||
strings[str_cnt] = NULL;
|
||||
|
||||
if (*pattern == '/') {
|
||||
match_start = 1;
|
||||
anchored_match = 1;
|
||||
pattern++;
|
||||
if (*name == '/')
|
||||
name++;
|
||||
if (strings[0][0] == '/')
|
||||
strings[0]++;
|
||||
}
|
||||
|
||||
if (!anchored_match && ex->u.slash_cnt
|
||||
&& !(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
/* A non-anchored match with an infix slash and no "**"
|
||||
* needs to match the last slash_cnt+1 name elements. */
|
||||
slash_handling = ex->u.slash_cnt + 1;
|
||||
} else if (!anchored_match && !(ex->match_flags & MATCHFLG_WILD2_PREFIX)
|
||||
&& ex->match_flags & MATCHFLG_WILD2) {
|
||||
/* A non-anchored match with an infix or trailing "**" (but not
|
||||
* a prefixed "**") needs to try matching after every slash. */
|
||||
slash_handling = -1;
|
||||
} else {
|
||||
/* The pattern matches only at the start of the path or name. */
|
||||
slash_handling = 0;
|
||||
}
|
||||
|
||||
if (ex->match_flags & MATCHFLG_WILD) {
|
||||
/* A non-anchored match with an infix slash and no "**"
|
||||
* needs to match the last slash_cnt+1 name elements. */
|
||||
if (!match_start && ex->u.slash_cnt
|
||||
&& !(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
int cnt = ex->u.slash_cnt + 1;
|
||||
for (p = name + strlen(name) - 1; p >= name; p--) {
|
||||
if (*p == '/' && !--cnt)
|
||||
break;
|
||||
}
|
||||
name = p+1;
|
||||
}
|
||||
if (wildmatch(pattern, name))
|
||||
if (wildmatch_array(pattern, strings, slash_handling))
|
||||
return ret_match;
|
||||
if (ex->match_flags & MATCHFLG_WILD2_PREFIX) {
|
||||
/* If the **-prefixed pattern has a '/' as the next
|
||||
* character, then try to match the rest of the
|
||||
* pattern at the root. */
|
||||
if (pattern[2] == '/' && wildmatch(pattern+3, name))
|
||||
return ret_match;
|
||||
}
|
||||
else if (!match_start && ex->match_flags & MATCHFLG_WILD2) {
|
||||
/* A non-anchored match with an infix or trailing "**"
|
||||
* (but not a prefixed "**") needs to try matching
|
||||
* after every slash. */
|
||||
while ((name = strchr(name, '/')) != NULL) {
|
||||
name++;
|
||||
if (wildmatch(pattern, name))
|
||||
return ret_match;
|
||||
}
|
||||
}
|
||||
} else if (match_start) {
|
||||
if (strcmp(name,pattern) == 0)
|
||||
} else if (str_cnt > 1) {
|
||||
if (litmatch_array(pattern, strings, slash_handling))
|
||||
return ret_match;
|
||||
} else if (anchored_match) {
|
||||
if (strcmp(strings[0], pattern) == 0)
|
||||
return ret_match;
|
||||
} else {
|
||||
int l1 = strlen(name);
|
||||
@@ -577,11 +585,13 @@ static void report_filter_result(char const *name,
|
||||
* case we add it back in here. */
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "[%s] %scluding %s %s because of pattern %s%s%s\n",
|
||||
who_am_i(),
|
||||
ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex",
|
||||
name_is_dir ? "directory" : "file", name, ent->pattern,
|
||||
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type);
|
||||
static char *actions[2][2]
|
||||
= { {"show", "hid"}, {"risk", "protect"} };
|
||||
const char *w = who_am_i();
|
||||
rprintf(FINFO, "[%s] %sing %s %s because of pattern %s%s%s\n",
|
||||
w, actions[*w!='s'][!(ent->match_flags&MATCHFLG_INCLUDE)],
|
||||
name_is_dir ? "directory" : "file", name, ent->pattern,
|
||||
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,7 +837,8 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
|
||||
len = strlen((char*)s);
|
||||
|
||||
if (new_mflags & MATCHFLG_CLEAR_LIST) {
|
||||
if (!(xflags & XFLG_OLD_PREFIXES) && len) {
|
||||
if (!(mflags & MATCHFLG_NO_PREFIXES)
|
||||
&& !(xflags & XFLG_OLD_PREFIXES) && len) {
|
||||
rprintf(FERROR,
|
||||
"'!' rule has trailing characters: %s\n", p);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
@@ -954,7 +965,7 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
|
||||
uint32 mflags, int xflags)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */
|
||||
char line[BIGPATHBUFLEN];
|
||||
char *eob = line + sizeof line - 1;
|
||||
int word_split = mflags & MATCHFLG_WORD_SPLIT;
|
||||
|
||||
@@ -976,7 +987,7 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] parse_filter_file(%s,%x,%x)%s\n",
|
||||
who_am_i(), safe_fname(fname), mflags, xflags,
|
||||
who_am_i(), fname, mflags, xflags,
|
||||
fp ? "" : " [not found]");
|
||||
}
|
||||
|
||||
@@ -985,7 +996,7 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to open %sclude file %s",
|
||||
mflags & MATCHFLG_INCLUDE ? "in" : "ex",
|
||||
safe_fname(fname));
|
||||
fname);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
return;
|
||||
@@ -997,8 +1008,10 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
|
||||
int ch, overflow = 0;
|
||||
while (1) {
|
||||
if ((ch = getc(fp)) == EOF) {
|
||||
if (ferror(fp) && errno == EINTR)
|
||||
if (ferror(fp) && errno == EINTR) {
|
||||
clearerr(fp);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (word_split && isspace(ch))
|
||||
@@ -1135,8 +1148,8 @@ static void send_rules(int f_out, struct filter_list_struct *flp)
|
||||
/* This is only called by the client. */
|
||||
void send_filter_list(int f_out)
|
||||
{
|
||||
int receiver_wants_list = delete_mode
|
||||
&& (!delete_excluded || protocol_version >= 29);
|
||||
int receiver_wants_list = prune_empty_dirs
|
||||
|| (delete_mode && (!delete_excluded || protocol_version >= 29));
|
||||
|
||||
if (local_server || (am_sender && !receiver_wants_list))
|
||||
f_out = -1;
|
||||
@@ -1167,10 +1180,11 @@ void send_filter_list(int f_out)
|
||||
/* This is only called by the server. */
|
||||
void recv_filter_list(int f_in)
|
||||
{
|
||||
char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */
|
||||
char line[BIGPATHBUFLEN];
|
||||
int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
|
||||
int receiver_wants_list = delete_mode
|
||||
&& (!delete_excluded || protocol_version >= 29);
|
||||
int receiver_wants_list = prune_empty_dirs
|
||||
|| (delete_mode
|
||||
&& (!delete_excluded || protocol_version >= 29));
|
||||
unsigned int len;
|
||||
|
||||
if (!local_server && (am_sender || receiver_wants_list)) {
|
||||
|
||||
51
fileio.c
51
fileio.c
@@ -22,6 +22,10 @@
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
#ifndef ENODATA
|
||||
#define ENODATA EAGAIN
|
||||
#endif
|
||||
|
||||
extern int sparse_files;
|
||||
|
||||
static char last_byte;
|
||||
@@ -217,34 +221,35 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
if ((nread=read(map->fd,map->p + read_offset,read_size)) != read_size) {
|
||||
if (nread < 0) {
|
||||
nread = 0;
|
||||
if (!map->status)
|
||||
map->status = errno;
|
||||
}
|
||||
/* the best we can do is zero the buffer - the file
|
||||
has changed mid transfer! */
|
||||
memset(map->p+read_offset+nread, 0, read_size - nread);
|
||||
}
|
||||
map->p_fd_offset += nread;
|
||||
}
|
||||
|
||||
if (map->p_fd_offset != read_start) {
|
||||
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;
|
||||
}
|
||||
map->p_offset = window_start;
|
||||
map->p_len = window_size;
|
||||
|
||||
while (read_size > 0) {
|
||||
nread = read(map->fd, map->p + read_offset, read_size);
|
||||
if (nread <= 0) {
|
||||
if (!map->status)
|
||||
map->status = nread ? errno : ENODATA;
|
||||
/* The best we can do is zero the buffer -- the file
|
||||
* has changed mid transfer! */
|
||||
memset(map->p + read_offset, 0, read_size);
|
||||
break;
|
||||
}
|
||||
map->p_fd_offset += nread;
|
||||
read_offset += nread;
|
||||
read_size -= nread;
|
||||
}
|
||||
|
||||
return map->p;
|
||||
}
|
||||
|
||||
|
||||
693
generator.c
693
generator.c
File diff suppressed because it is too large
Load Diff
48
hlink.c
48
hlink.c
@@ -20,10 +20,11 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int dry_run;
|
||||
extern int verbose;
|
||||
extern int link_dest;
|
||||
extern int make_backups;
|
||||
extern int log_format_has_i;
|
||||
extern char *basis_dir[];
|
||||
extern struct file_list *the_file_list;
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -173,8 +174,6 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
{
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
int head;
|
||||
if (!file->link_u.links)
|
||||
return 0;
|
||||
if (skip && !(file->flags & FLAG_HLINK_EOL))
|
||||
head = hlink_list[file->F_HLINDEX] = file->F_NEXT;
|
||||
else
|
||||
@@ -183,16 +182,41 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
struct file_struct *head_file = FPTR(head);
|
||||
if (!log_format_has_i && verbose > 1) {
|
||||
rprintf(FINFO, "\"%s\" is a hard link\n",
|
||||
safe_fname(f_name(file)));
|
||||
f_name(file, NULL));
|
||||
}
|
||||
if (head_file->F_HLINDEX == FINISHED_LINK) {
|
||||
STRUCT_STAT st2;
|
||||
char *toname = f_name(head_file);
|
||||
STRUCT_STAT st2, st3;
|
||||
char *toname = f_name(head_file, NULL);
|
||||
if (link_stat(toname, &st2, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(toname));
|
||||
return -1;
|
||||
}
|
||||
if (statret < 0 && basis_dir[0] != NULL) {
|
||||
char cmpbuf[MAXPATHLEN];
|
||||
int j = 0;
|
||||
do {
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &st3, 0) < 0)
|
||||
continue;
|
||||
if (link_dest) {
|
||||
if (st2.st_dev != st3.st_dev
|
||||
|| st2.st_ino != st3.st_ino)
|
||||
continue;
|
||||
statret = 1;
|
||||
st = &st3;
|
||||
if (verbose < 2 || !log_format_has_i)
|
||||
itemizing = code = 0;
|
||||
break;
|
||||
}
|
||||
if (!unchanged_file(cmpbuf, file, &st3))
|
||||
continue;
|
||||
statret = 1;
|
||||
st = &st3;
|
||||
if (unchanged_attrs(file, &st3))
|
||||
break;
|
||||
} while (basis_dir[++j] != NULL);
|
||||
}
|
||||
maybe_hard_link(file, ndx, fname, statret, st,
|
||||
toname, &st2, itemizing, code);
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
@@ -217,7 +241,7 @@ int hard_link_one(struct file_struct *file, int ndx, char *fname,
|
||||
} else
|
||||
code = FERROR;
|
||||
rsyserr(code, errno, "link %s => %s failed",
|
||||
full_fname(fname), safe_fname(toname));
|
||||
full_fname(fname), toname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -226,10 +250,8 @@ int hard_link_one(struct file_struct *file, int ndx, char *fname,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
|
||||
terse ? "" : toname);
|
||||
}
|
||||
if (code && verbose && !terse) {
|
||||
rprintf(code, "%s => %s\n",
|
||||
safe_fname(fname), safe_fname(toname));
|
||||
}
|
||||
if (code && verbose && !terse)
|
||||
rprintf(code, "%s => %s\n", fname, toname);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -245,7 +267,7 @@ void hard_link_cluster(struct file_struct *file, int master, int itemizing,
|
||||
int statret, ndx = master;
|
||||
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
if (link_stat(f_name_to(file, hlink1), &st1, 0) < 0)
|
||||
if (link_stat(f_name(file, hlink1), &st1, 0) < 0)
|
||||
return;
|
||||
if (!(file->flags & FLAG_HLINK_TOL)) {
|
||||
while (!(file->flags & FLAG_HLINK_EOL)) {
|
||||
@@ -258,7 +280,7 @@ void hard_link_cluster(struct file_struct *file, int master, int itemizing,
|
||||
file = FPTR(ndx);
|
||||
if (file->F_HLINDEX != SKIPPED_LINK)
|
||||
continue;
|
||||
hlink2 = f_name(file);
|
||||
hlink2 = f_name(file, NULL);
|
||||
statret = link_stat(hlink2, &st2, 0);
|
||||
maybe_hard_link(file, ndx, hlink2, statret, &st2,
|
||||
hlink1, &st1, itemizing, code);
|
||||
|
||||
300
io.c
300
io.c
@@ -41,7 +41,6 @@
|
||||
|
||||
extern int bwlimit;
|
||||
extern size_t bwlimit_writemax;
|
||||
extern int verbose;
|
||||
extern int io_timeout;
|
||||
extern int allowed_lull;
|
||||
extern int am_server;
|
||||
@@ -103,8 +102,10 @@ 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 defer_forwarding_messages = 0;
|
||||
static int select_timeout = SELECT_TIMEOUT;
|
||||
static int active_filecnt = 0;
|
||||
static OFF_T active_bytecnt = 0;
|
||||
|
||||
static void read_loop(int fd, char *buf, size_t len);
|
||||
|
||||
@@ -119,14 +120,17 @@ struct flist_ndx_list {
|
||||
|
||||
static struct flist_ndx_list redo_list, hlink_list;
|
||||
|
||||
struct msg_list {
|
||||
struct msg_list *next;
|
||||
char *buf;
|
||||
struct msg_list_item {
|
||||
struct msg_list_item *next;
|
||||
int len;
|
||||
char buf[1];
|
||||
};
|
||||
|
||||
static struct msg_list *msg_list_head;
|
||||
static struct msg_list *msg_list_tail;
|
||||
struct msg_list {
|
||||
struct msg_list_item *head, *tail;
|
||||
};
|
||||
|
||||
static struct msg_list msg2genr, msg2sndr;
|
||||
|
||||
static void flist_ndx_push(struct flist_ndx_list *lp, int ndx)
|
||||
{
|
||||
@@ -222,33 +226,22 @@ void set_msg_fd_out(int fd)
|
||||
}
|
||||
|
||||
/* Add a message to the pending MSG_* list. */
|
||||
static void msg_list_add(int code, char *buf, int len)
|
||||
static void msg_list_add(struct msg_list *lst, int code, char *buf, int len)
|
||||
{
|
||||
struct msg_list *ml;
|
||||
struct msg_list_item *m;
|
||||
int sz = len + 4 + sizeof m[0] - 1;
|
||||
|
||||
if (!(ml = new(struct msg_list)))
|
||||
if (!(m = (struct msg_list_item *)new_array(char, sz)))
|
||||
out_of_memory("msg_list_add");
|
||||
ml->next = NULL;
|
||||
if (!(ml->buf = new_array(char, len+4)))
|
||||
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;
|
||||
if (msg_list_tail)
|
||||
msg_list_tail->next = ml;
|
||||
m->next = NULL;
|
||||
m->len = len + 4;
|
||||
SIVAL(m->buf, 0, ((code+MPLEX_BASE)<<24) | len);
|
||||
memcpy(m->buf + 4, buf, len);
|
||||
if (lst->tail)
|
||||
lst->tail->next = m;
|
||||
else
|
||||
msg_list_head = ml;
|
||||
msg_list_tail = ml;
|
||||
}
|
||||
|
||||
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);
|
||||
lst->head = m;
|
||||
lst->tail = m;
|
||||
}
|
||||
|
||||
/* Read a message from the MSG_* fd and handle it. This is called either
|
||||
@@ -286,6 +279,8 @@ static void read_msg_fd(void)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, buf, 4);
|
||||
if (remove_sent_files)
|
||||
decrement_active_files(IVAL(buf,0));
|
||||
flist_ndx_push(&redo_list, IVAL(buf,0));
|
||||
break;
|
||||
case MSG_DELETED:
|
||||
@@ -294,7 +289,10 @@ static void read_msg_fd(void)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, buf, len);
|
||||
io_multiplex_write(MSG_DELETED, buf, len);
|
||||
if (defer_forwarding_messages)
|
||||
msg_list_add(&msg2sndr, MSG_DELETED, buf, len);
|
||||
else
|
||||
io_multiplex_write(MSG_DELETED, buf, len);
|
||||
break;
|
||||
case MSG_SUCCESS:
|
||||
if (len != 4 || !am_generator) {
|
||||
@@ -302,11 +300,23 @@ static void read_msg_fd(void)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
read_loop(fd, buf, len);
|
||||
if (remove_sent_files)
|
||||
io_multiplex_write(MSG_SUCCESS, buf, len);
|
||||
if (remove_sent_files) {
|
||||
decrement_active_files(IVAL(buf,0));
|
||||
if (defer_forwarding_messages)
|
||||
msg_list_add(&msg2sndr, MSG_SUCCESS, buf, len);
|
||||
else
|
||||
io_multiplex_write(MSG_SUCCESS, buf, len);
|
||||
}
|
||||
if (preserve_hard_links)
|
||||
flist_ndx_push(&hlink_list, IVAL(buf,0));
|
||||
break;
|
||||
case MSG_SOCKERR:
|
||||
if (!am_generator) {
|
||||
rprintf(FERROR, "invalid message %d:%d\n", tag, len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
close_multiplexing_out();
|
||||
/* FALL THROUGH */
|
||||
case MSG_INFO:
|
||||
case MSG_ERROR:
|
||||
case MSG_LOG:
|
||||
@@ -315,22 +325,48 @@ static void read_msg_fd(void)
|
||||
if (n >= sizeof buf)
|
||||
n = sizeof buf - 1;
|
||||
read_loop(fd, buf, n);
|
||||
rwrite((enum logcode)tag, buf, n);
|
||||
if (am_generator && am_server && defer_forwarding_messages)
|
||||
msg_list_add(&msg2sndr, tag, buf, n);
|
||||
else
|
||||
rwrite((enum logcode)tag, buf, n);
|
||||
len -= n;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rprintf(FERROR, "unknown message %d:%d\n", tag, len);
|
||||
rprintf(FERROR, "unknown message %d:%d [%s]\n",
|
||||
tag, len, who_am_i());
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
msg_fd_in = fd;
|
||||
}
|
||||
|
||||
/* This is used by the generator to limit how many file transfers can
|
||||
* be active at once when --remove-sent-files is specified. Without
|
||||
* this, sender-side deletions were mostly happening at the end. */
|
||||
void increment_active_files(int ndx, int itemizing, enum logcode code)
|
||||
{
|
||||
/* TODO: tune these limits? */
|
||||
while (active_filecnt >= (active_bytecnt >= 128*1024 ? 10 : 50)) {
|
||||
if (hlink_list.head)
|
||||
check_for_finished_hlinks(itemizing, code);
|
||||
read_msg_fd();
|
||||
}
|
||||
|
||||
active_filecnt++;
|
||||
active_bytecnt += the_file_list->files[ndx]->length;
|
||||
}
|
||||
|
||||
void decrement_active_files(int ndx)
|
||||
{
|
||||
active_filecnt--;
|
||||
active_bytecnt -= the_file_list->files[ndx]->length;
|
||||
}
|
||||
|
||||
/* Try to push messages off the list onto the wire. If we leave with more
|
||||
* to do, return 0. On error, return -1. If everything flushed, return 1.
|
||||
* This is only active in the receiver. */
|
||||
int msg_list_push(int flush_it_all)
|
||||
static int msg2genr_flush(int flush_it_all)
|
||||
{
|
||||
static int written = 0;
|
||||
struct timeval tv;
|
||||
@@ -339,9 +375,9 @@ int msg_list_push(int flush_it_all)
|
||||
if (msg_fd_out < 0)
|
||||
return -1;
|
||||
|
||||
while (msg_list_head) {
|
||||
struct msg_list *ml = msg_list_head;
|
||||
int n = write(msg_fd_out, ml->buf + written, ml->len - written);
|
||||
while (msg2genr.head) {
|
||||
struct msg_list_item *m = msg2genr.head;
|
||||
int n = write(msg_fd_out, m->buf + written, m->len - written);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
@@ -355,18 +391,27 @@ int msg_list_push(int flush_it_all)
|
||||
tv.tv_usec = 0;
|
||||
if (!select(msg_fd_out+1, NULL, &fds, NULL, &tv))
|
||||
check_timeout();
|
||||
} else if ((written += n) == ml->len) {
|
||||
free(ml->buf);
|
||||
msg_list_head = ml->next;
|
||||
if (!msg_list_head)
|
||||
msg_list_tail = NULL;
|
||||
free(ml);
|
||||
} else if ((written += n) == m->len) {
|
||||
msg2genr.head = m->next;
|
||||
if (!msg2genr.head)
|
||||
msg2genr.tail = NULL;
|
||||
free(m);
|
||||
written = 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
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(&msg2genr, code, buf, len);
|
||||
msg2genr_flush(NORMAL_FLUSH);
|
||||
}
|
||||
|
||||
int get_redo_num(int itemizing, enum logcode code)
|
||||
{
|
||||
while (1) {
|
||||
@@ -434,7 +479,6 @@ static void whine_about_eof(int fd)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from a socket with I/O timeout. return the number of bytes
|
||||
* read. If no bytes can be read then exit, never return a number <= 0.
|
||||
@@ -448,11 +492,11 @@ static void whine_about_eof(int fd)
|
||||
*/
|
||||
static int read_timeout(int fd, char *buf, size_t len)
|
||||
{
|
||||
int n, ret = 0;
|
||||
int n, cnt = 0;
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
|
||||
while (ret == 0) {
|
||||
while (cnt == 0) {
|
||||
/* until we manage to read *something* */
|
||||
fd_set r_fds, w_fds;
|
||||
struct timeval tv;
|
||||
@@ -462,7 +506,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_list_head) {
|
||||
if (msg2genr.head) {
|
||||
FD_SET(msg_fd_out, &w_fds);
|
||||
if (msg_fd_out > maxfd)
|
||||
maxfd = msg_fd_out;
|
||||
@@ -499,8 +543,8 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds))
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
if (msg2genr.head && FD_ISSET(msg_fd_out, &w_fds))
|
||||
msg2genr_flush(NORMAL_FLUSH);
|
||||
|
||||
if (io_filesfrom_f_out >= 0) {
|
||||
if (io_filesfrom_buflen) {
|
||||
@@ -578,21 +622,23 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
continue;
|
||||
|
||||
/* Don't write errors on a dead socket. */
|
||||
if (fd == sock_f_in)
|
||||
if (fd == sock_f_in) {
|
||||
close_multiplexing_out();
|
||||
rsyserr(FERROR, errno, "read error");
|
||||
rsyserr(FSOCKERR, errno, "read error");
|
||||
} else
|
||||
rsyserr(FERROR, errno, "read error");
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
buf += n;
|
||||
len -= n;
|
||||
ret += n;
|
||||
cnt += n;
|
||||
|
||||
if (fd == sock_f_in && io_timeout)
|
||||
last_io_in = time(NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -642,7 +688,6 @@ int read_filesfrom_line(int fd, char *fname)
|
||||
return s - fname;
|
||||
}
|
||||
|
||||
|
||||
static char *iobuf_out;
|
||||
static int iobuf_out_cnt;
|
||||
|
||||
@@ -655,7 +700,6 @@ void io_start_buffering_out(void)
|
||||
iobuf_out_cnt = 0;
|
||||
}
|
||||
|
||||
|
||||
static char *iobuf_in;
|
||||
static size_t iobuf_in_siz;
|
||||
|
||||
@@ -668,7 +712,6 @@ void io_start_buffering_in(void)
|
||||
out_of_memory("io_start_buffering_in");
|
||||
}
|
||||
|
||||
|
||||
void io_end_buffering(void)
|
||||
{
|
||||
io_flush(NORMAL_FLUSH);
|
||||
@@ -678,14 +721,12 @@ 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) {
|
||||
@@ -700,7 +741,6 @@ void maybe_send_keepalive(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Continue trying to read len bytes - don't return until len has been
|
||||
* read.
|
||||
@@ -715,7 +755,6 @@ static void read_loop(int fd, char *buf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from the file descriptor handling multiplexing - return number
|
||||
* of bytes read.
|
||||
@@ -727,12 +766,8 @@ 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;
|
||||
#if MAXPATHLEN < 4096
|
||||
char line[4096+1024];
|
||||
#else
|
||||
char line[MAXPATHLEN+1024];
|
||||
#endif
|
||||
int tag, cnt = 0;
|
||||
char line[BIGPATHBUFLEN];
|
||||
|
||||
if (!iobuf_in || fd != sock_f_in)
|
||||
return read_timeout(fd, buf, len);
|
||||
@@ -742,13 +777,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
iobuf_in_ndx = 0;
|
||||
}
|
||||
|
||||
while (ret == 0) {
|
||||
while (cnt == 0) {
|
||||
if (remaining) {
|
||||
len = MIN(len, remaining);
|
||||
memcpy(buf, iobuf_in + iobuf_in_ndx, len);
|
||||
iobuf_in_ndx += len;
|
||||
remaining -= len;
|
||||
ret = len;
|
||||
cnt = len;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -774,12 +809,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
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
|
||||
else {
|
||||
line[msg_bytes] = '\0';
|
||||
log_delete(line, S_IFREG);
|
||||
}
|
||||
break;
|
||||
case MSG_SUCCESS:
|
||||
if (msg_bytes != 4) {
|
||||
@@ -812,11 +848,9 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
if (remaining == 0)
|
||||
io_flush(NORMAL_FLUSH);
|
||||
|
||||
return ret;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Do a buffered read from @p fd. Don't return until all @p n bytes
|
||||
* have been read. If all @p n can't be read then exit with an
|
||||
@@ -824,12 +858,12 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
**/
|
||||
static void readfd(int fd, char *buffer, size_t N)
|
||||
{
|
||||
int ret;
|
||||
int cnt;
|
||||
size_t total = 0;
|
||||
|
||||
while (total < N) {
|
||||
ret = readfd_unbuffered(fd, buffer + total, N-total);
|
||||
total += ret;
|
||||
cnt = readfd_unbuffered(fd, buffer + total, N-total);
|
||||
total += cnt;
|
||||
}
|
||||
|
||||
if (fd == write_batch_monitor_in) {
|
||||
@@ -841,7 +875,6 @@ static void readfd(int fd, char *buffer, size_t N)
|
||||
stats.total_read += total;
|
||||
}
|
||||
|
||||
|
||||
int read_shortint(int f)
|
||||
{
|
||||
uchar b[2];
|
||||
@@ -849,37 +882,36 @@ int read_shortint(int f)
|
||||
return (b[1] << 8) + b[0];
|
||||
}
|
||||
|
||||
|
||||
int32 read_int(int f)
|
||||
{
|
||||
char b[4];
|
||||
int32 ret;
|
||||
int32 num;
|
||||
|
||||
readfd(f,b,4);
|
||||
ret = IVAL(b,0);
|
||||
if (ret == (int32)0xffffffff)
|
||||
num = IVAL(b,0);
|
||||
if (num == (int32)0xffffffff)
|
||||
return -1;
|
||||
return ret;
|
||||
return num;
|
||||
}
|
||||
|
||||
int64 read_longint(int f)
|
||||
{
|
||||
int64 ret;
|
||||
int64 num;
|
||||
char b[8];
|
||||
ret = read_int(f);
|
||||
num = read_int(f);
|
||||
|
||||
if ((int32)ret != (int32)0xffffffff)
|
||||
return ret;
|
||||
if ((int32)num != (int32)0xffffffff)
|
||||
return num;
|
||||
|
||||
#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);
|
||||
num = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
return num;
|
||||
}
|
||||
|
||||
void read_buf(int f,char *buf,size_t len)
|
||||
@@ -924,6 +956,11 @@ int read_vstring(int f, char *buf, int bufsize)
|
||||
void read_sum_head(int f, struct sum_struct *sum)
|
||||
{
|
||||
sum->count = read_int(f);
|
||||
if (sum->count < 0) {
|
||||
rprintf(FERROR, "Invalid checksum count %ld [%s]\n",
|
||||
(long)sum->count, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
sum->blength = read_int(f);
|
||||
if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) {
|
||||
rprintf(FERROR, "Invalid block length %ld [%s]\n",
|
||||
@@ -961,7 +998,6 @@ void write_sum_head(int f, struct sum_struct *sum)
|
||||
write_int(f, sum->remainder);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sleep after writing to limit I/O bandwidth usage.
|
||||
*
|
||||
@@ -987,7 +1023,7 @@ static void sleep_for_bwlimit(int bytes_written)
|
||||
|
||||
#define ONE_SEC 1000000L /* # of microseconds in a second */
|
||||
|
||||
if (!bwlimit)
|
||||
if (!bwlimit_writemax)
|
||||
return;
|
||||
|
||||
total_written += bytes_written;
|
||||
@@ -1017,9 +1053,8 @@ static void sleep_for_bwlimit(int bytes_written)
|
||||
total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
|
||||
}
|
||||
|
||||
|
||||
/* Write len bytes to the file descriptor fd, looping as necessary to get
|
||||
* the job done and also (in certain circumstnces) reading any data on
|
||||
* the job done and also (in certain circumstances) reading any data on
|
||||
* msg_fd_in to avoid deadlock.
|
||||
*
|
||||
* This function underlies the multiplexing system. The body of the
|
||||
@@ -1028,7 +1063,8 @@ 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, using_r_fds;
|
||||
int maxfd, count, cnt, using_r_fds;
|
||||
int defer_save = defer_forwarding_messages;
|
||||
struct timeval tv;
|
||||
|
||||
no_flush++;
|
||||
@@ -1038,7 +1074,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
FD_SET(fd,&w_fds);
|
||||
maxfd = fd;
|
||||
|
||||
if (msg_fd_in >= 0 && len-total >= contiguous_write_len) {
|
||||
if (msg_fd_in >= 0) {
|
||||
FD_ZERO(&r_fds);
|
||||
FD_SET(msg_fd_in,&r_fds);
|
||||
if (msg_fd_in > maxfd)
|
||||
@@ -1068,12 +1104,12 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
continue;
|
||||
|
||||
n = len - total;
|
||||
if (bwlimit && n > bwlimit_writemax)
|
||||
if (bwlimit_writemax && n > bwlimit_writemax)
|
||||
n = bwlimit_writemax;
|
||||
ret = write(fd, buf + total, n);
|
||||
cnt = write(fd, buf + total, n);
|
||||
|
||||
if (ret <= 0) {
|
||||
if (ret < 0) {
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
@@ -1099,18 +1135,36 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
total += ret;
|
||||
total += cnt;
|
||||
defer_forwarding_messages = 1;
|
||||
|
||||
if (fd == sock_f_out) {
|
||||
if (io_timeout || am_generator)
|
||||
last_io_out = time(NULL);
|
||||
sleep_for_bwlimit(ret);
|
||||
sleep_for_bwlimit(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
defer_forwarding_messages = defer_save;
|
||||
no_flush--;
|
||||
}
|
||||
|
||||
static void msg2sndr_flush(void)
|
||||
{
|
||||
if (defer_forwarding_messages)
|
||||
return;
|
||||
|
||||
while (msg2sndr.head && io_multiplexing_out) {
|
||||
struct msg_list_item *m = msg2sndr.head;
|
||||
if (!(msg2sndr.head = m->next))
|
||||
msg2sndr.tail = NULL;
|
||||
stats.total_written += m->len;
|
||||
defer_forwarding_messages = 1;
|
||||
writefd_unbuffered(sock_f_out, m->buf, m->len);
|
||||
defer_forwarding_messages = 0;
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an message to a multiplexed stream. If this fails then rsync
|
||||
@@ -1118,38 +1172,33 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
**/
|
||||
static void mplex_write(enum msgcode code, char *buf, size_t len)
|
||||
{
|
||||
char buffer[4096];
|
||||
char buffer[1024];
|
||||
size_t n = 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;
|
||||
n = 0;
|
||||
else
|
||||
memcpy(buffer + 4, buf, n);
|
||||
|
||||
memcpy(&buffer[4], buf, n);
|
||||
writefd_unbuffered(sock_f_out, buffer, n+4);
|
||||
|
||||
len -= n;
|
||||
buf += n;
|
||||
|
||||
if (len)
|
||||
if (len) {
|
||||
defer_forwarding_messages = 1;
|
||||
writefd_unbuffered(sock_f_out, buf, len);
|
||||
|
||||
if (am_generator && msg_fd_in >= 0)
|
||||
contiguous_write_len = 0;
|
||||
defer_forwarding_messages = 0;
|
||||
msg2sndr_flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void io_flush(int flush_it_all)
|
||||
{
|
||||
msg_list_push(flush_it_all);
|
||||
msg2genr_flush(flush_it_all);
|
||||
msg2sndr_flush();
|
||||
|
||||
if (!iobuf_out_cnt || no_flush)
|
||||
return;
|
||||
@@ -1161,7 +1210,6 @@ void io_flush(int flush_it_all)
|
||||
iobuf_out_cnt = 0;
|
||||
}
|
||||
|
||||
|
||||
static void writefd(int fd,char *buf,size_t len)
|
||||
{
|
||||
if (fd == msg_fd_out) {
|
||||
@@ -1196,7 +1244,6 @@ static void writefd(int fd,char *buf,size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void write_shortint(int f, int x)
|
||||
{
|
||||
uchar b[2];
|
||||
@@ -1205,7 +1252,6 @@ void write_shortint(int f, int x)
|
||||
writefd(f, (char *)b, 2);
|
||||
}
|
||||
|
||||
|
||||
void write_int(int f,int32 x)
|
||||
{
|
||||
char b[4];
|
||||
@@ -1213,7 +1259,6 @@ void write_int(int f,int32 x)
|
||||
writefd(f,b,4);
|
||||
}
|
||||
|
||||
|
||||
void write_int_named(int f, int32 x, const char *phase)
|
||||
{
|
||||
io_write_phase = phase;
|
||||
@@ -1221,7 +1266,6 @@ void write_int_named(int f, int32 x, const char *phase)
|
||||
io_write_phase = phase_unknown;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Note: int64 may actually be a 32-bit type if ./configure couldn't find any
|
||||
* 64-bit types on this platform.
|
||||
@@ -1283,7 +1327,6 @@ void write_vstring(int f, char *str, int len)
|
||||
writefd(f, str, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a line of up to @p maxlen characters into @p buf (not counting
|
||||
* the trailing null). Strips the (required) trailing newline and all
|
||||
@@ -1309,11 +1352,10 @@ int read_line(int f, char *buf, size_t maxlen)
|
||||
return maxlen > 0;
|
||||
}
|
||||
|
||||
|
||||
void io_printf(int fd, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
char buf[BIGPATHBUFLEN];
|
||||
int len;
|
||||
|
||||
va_start(ap, format);
|
||||
@@ -1323,10 +1365,14 @@ void io_printf(int fd, const char *format, ...)
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
|
||||
if (len > (int)sizeof buf) {
|
||||
rprintf(FERROR, "io_printf() was too long for the buffer.\n");
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
write_sbuf(fd, buf);
|
||||
}
|
||||
|
||||
|
||||
/** Setup for multiplexing a MSG_* stream with the data stream. */
|
||||
void io_start_multiplex_out(void)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
*
|
||||
* @param buf buffer of at least 11 characters
|
||||
**/
|
||||
void permstring(char *perms,
|
||||
int mode)
|
||||
void permstring(char *perms, mode_t mode)
|
||||
{
|
||||
static const char *perm_map = "rwxrwxrwx";
|
||||
int i;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#define PERMSTRING_SIZE 11
|
||||
|
||||
void permstring(char *perms, int mode);
|
||||
void permstring(char *perms, mode_t mode);
|
||||
|
||||
@@ -56,8 +56,7 @@ pool_create(size_t size, size_t quantum,
|
||||
pool->size = size /* round extent size to min alignment reqs */
|
||||
? (size + MINALIGN - 1) & ~(MINALIGN - 1)
|
||||
: POOL_DEF_EXTENT;
|
||||
if (pool->flags & POOL_INTERN)
|
||||
{
|
||||
if (pool->flags & POOL_INTERN) {
|
||||
pool->size -= sizeof (struct pool_extent);
|
||||
flags |= POOL_APPEND;
|
||||
}
|
||||
@@ -77,15 +76,13 @@ pool_destroy(alloc_pool_t p)
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
if (pool->live)
|
||||
{
|
||||
if (pool->live) {
|
||||
cur = pool->live;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
}
|
||||
for (cur = pool->free; cur; cur = next)
|
||||
{
|
||||
for (cur = pool->free; cur; cur = next) {
|
||||
next = cur->next;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
@@ -109,16 +106,14 @@ pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
if (len > pool->size)
|
||||
goto bomb;
|
||||
|
||||
if (!pool->live || len > pool->live->free)
|
||||
{
|
||||
if (!pool->live || len > pool->live->free) {
|
||||
void *start;
|
||||
size_t free;
|
||||
size_t bound;
|
||||
size_t sqew;
|
||||
size_t asize;
|
||||
|
||||
if (pool->live)
|
||||
{
|
||||
if (pool->live) {
|
||||
pool->live->next = pool->free;
|
||||
pool->free = pool->live;
|
||||
}
|
||||
@@ -137,16 +132,11 @@ pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
memset(start, 0, pool->size);
|
||||
|
||||
if (pool->flags & POOL_APPEND)
|
||||
{
|
||||
pool->live = PTR_ADD(start, free);
|
||||
}
|
||||
else if (!(pool->live = (struct pool_extent *) malloc(sizeof (struct pool_extent))))
|
||||
{
|
||||
goto bomb;
|
||||
}
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (sqew = (size_t)PTR_ADD(start, free) % pool->quantum))
|
||||
{
|
||||
&& (sqew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
|
||||
bound += sqew;
|
||||
free -= sqew;
|
||||
}
|
||||
@@ -186,8 +176,7 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
else if (pool->quantum > 1 && len % pool->quantum)
|
||||
len += pool->quantum - len % pool->quantum;
|
||||
|
||||
if (!addr && pool->live)
|
||||
{
|
||||
if (!addr && pool->live) {
|
||||
pool->live->next = pool->free;
|
||||
pool->free = pool->live;
|
||||
pool->live = NULL;
|
||||
@@ -197,35 +186,28 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
pool->b_freed += len;
|
||||
|
||||
cur = pool->live;
|
||||
if (cur
|
||||
&& addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
{
|
||||
if (addr == PTR_ADD(cur->start, cur->free))
|
||||
{
|
||||
if (cur && addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size)) {
|
||||
if (addr == PTR_ADD(cur->start, cur->free)) {
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, len);
|
||||
pool->b_freed += len;
|
||||
} else {
|
||||
} else
|
||||
cur->bound += len;
|
||||
}
|
||||
if (cur->free + cur->bound >= pool->size)
|
||||
{
|
||||
if (cur->free + cur->bound >= pool->size) {
|
||||
size_t sqew;
|
||||
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum))
|
||||
{
|
||||
&& (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
|
||||
cur->bound += sqew;
|
||||
cur->free -= sqew;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next)
|
||||
{
|
||||
for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next) {
|
||||
if (addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
break;
|
||||
@@ -233,16 +215,14 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
if (prev)
|
||||
{
|
||||
if (prev) {
|
||||
prev->next = cur->next;
|
||||
cur->next = pool->free;
|
||||
pool->free = cur;
|
||||
}
|
||||
cur->bound += len;
|
||||
|
||||
if (cur->free + cur->bound >= pool->size)
|
||||
{
|
||||
if (cur->free + cur->bound >= pool->size) {
|
||||
pool->free = cur->next;
|
||||
|
||||
free(cur->start);
|
||||
@@ -254,11 +234,11 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
}
|
||||
|
||||
#define FDPRINT(label, value) \
|
||||
snprintf(buf, BUFSIZ, label, value), \
|
||||
write(fd, buf, strlen(buf));
|
||||
snprintf(buf, sizeof buf, label, value), \
|
||||
write(fd, buf, strlen(buf))
|
||||
|
||||
#define FDEXTSTAT(ext) \
|
||||
snprintf(buf, BUFSIZ, " %12ld %5ld\n", \
|
||||
snprintf(buf, sizeof buf, " %12ld %5ld\n", \
|
||||
(long) ext->free, \
|
||||
(long) ext->bound), \
|
||||
write(fd, buf, strlen(buf))
|
||||
@@ -291,14 +271,10 @@ pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
write(fd, "\n", 1);
|
||||
|
||||
if (pool->live)
|
||||
{
|
||||
FDEXTSTAT(pool->live);
|
||||
}
|
||||
strcpy(buf, " FREE BOUND\n");
|
||||
write(fd, buf, strlen(buf));
|
||||
|
||||
for (cur = pool->free; cur; cur = cur->next)
|
||||
{
|
||||
FDEXTSTAT(cur);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef VA_COPY
|
||||
#ifdef HAVE_VA_COPY
|
||||
#if defined HAVE_VA_COPY || defined va_copy
|
||||
#define VA_COPY(dest, src) va_copy(dest, src)
|
||||
#else
|
||||
#ifdef HAVE___VA_COPY
|
||||
|
||||
313
lib/wildmatch.c
313
lib/wildmatch.c
@@ -57,173 +57,312 @@
|
||||
int wildmatch_iteration_count;
|
||||
#endif
|
||||
|
||||
static int domatch(const uchar *p, const uchar *text)
|
||||
static int force_lower_case = 0;
|
||||
|
||||
/* Match pattern "p" against the a virtually-joined string consisting
|
||||
* of "text" and any strings in array "a". */
|
||||
static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
|
||||
{
|
||||
int matched, special;
|
||||
uchar ch, prev;
|
||||
uchar p_ch;
|
||||
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count++;
|
||||
#endif
|
||||
|
||||
for ( ; (ch = *p) != '\0'; text++, p++) {
|
||||
if (*text == '\0' && ch != '*')
|
||||
return FALSE;
|
||||
switch (ch) {
|
||||
for ( ; (p_ch = *p) != '\0'; text++, p++) {
|
||||
int matched, special;
|
||||
uchar t_ch, prev_ch;
|
||||
while ((t_ch = *text) == '\0') {
|
||||
if (*a == NULL) {
|
||||
if (p_ch != '*')
|
||||
return ABORT_ALL;
|
||||
break;
|
||||
}
|
||||
text = *a++;
|
||||
}
|
||||
if (force_lower_case && ISUPPER(t_ch))
|
||||
t_ch = tolower(t_ch);
|
||||
switch (p_ch) {
|
||||
case '\\':
|
||||
/* Literal match with following character. Note that the test
|
||||
* in "default" handles the p[1] == '\0' failure case. */
|
||||
ch = *++p;
|
||||
p_ch = *++p;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (*text != ch)
|
||||
if (t_ch != p_ch)
|
||||
return FALSE;
|
||||
continue;
|
||||
case '?':
|
||||
/* Match anything but '/'. */
|
||||
if (*text == '/')
|
||||
if (t_ch == '/')
|
||||
return FALSE;
|
||||
continue;
|
||||
case '*':
|
||||
if (*++p == '*') {
|
||||
while (*++p == '*') {}
|
||||
special = TRUE;
|
||||
}
|
||||
else
|
||||
} else
|
||||
special = FALSE;
|
||||
if (*p == '\0') {
|
||||
/* Trailing "**" matches everything. Trailing "*" matches
|
||||
* only if there are no more slash characters. */
|
||||
return special? TRUE : strchr((char*)text, '/') == NULL;
|
||||
if (!special) {
|
||||
do {
|
||||
if (strchr((char*)text, '/') != NULL)
|
||||
return FALSE;
|
||||
} while ((text = *a++) != NULL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
for ( ; *text; text++) {
|
||||
if ((matched = domatch(p, text)) != FALSE) {
|
||||
while (1) {
|
||||
if (t_ch == '\0') {
|
||||
if ((text = *a++) == NULL)
|
||||
break;
|
||||
t_ch = *text;
|
||||
continue;
|
||||
}
|
||||
if ((matched = dowild(p, text, a)) != FALSE) {
|
||||
if (!special || matched != ABORT_TO_STARSTAR)
|
||||
return matched;
|
||||
}
|
||||
else if (!special && *text == '/')
|
||||
} else if (!special && t_ch == '/')
|
||||
return ABORT_TO_STARSTAR;
|
||||
t_ch = *++text;
|
||||
}
|
||||
return ABORT_ALL;
|
||||
case '[':
|
||||
ch = *++p;
|
||||
p_ch = *++p;
|
||||
#ifdef NEGATE_CLASS2
|
||||
if (ch == NEGATE_CLASS2)
|
||||
ch = NEGATE_CLASS;
|
||||
if (p_ch == NEGATE_CLASS2)
|
||||
p_ch = NEGATE_CLASS;
|
||||
#endif
|
||||
/* Assign literal TRUE/FALSE because of "matched" comparison. */
|
||||
special = ch == NEGATE_CLASS? TRUE : FALSE;
|
||||
special = p_ch == NEGATE_CLASS? TRUE : FALSE;
|
||||
if (special) {
|
||||
/* Inverted character class. */
|
||||
ch = *++p;
|
||||
p_ch = *++p;
|
||||
}
|
||||
prev = 0;
|
||||
prev_ch = 0;
|
||||
matched = FALSE;
|
||||
do {
|
||||
if (!ch)
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
if (ch == '\\') {
|
||||
ch = *++p;
|
||||
if (!ch)
|
||||
if (p_ch == '\\') {
|
||||
p_ch = *++p;
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
if (*text == ch)
|
||||
if (t_ch == p_ch)
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (ch == '-' && prev && p[1] && p[1] != ']') {
|
||||
ch = *++p;
|
||||
if (ch == '\\') {
|
||||
ch = *++p;
|
||||
if (!ch)
|
||||
} else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
|
||||
p_ch = *++p;
|
||||
if (p_ch == '\\') {
|
||||
p_ch = *++p;
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
}
|
||||
if (*text <= ch && *text >= prev)
|
||||
if (t_ch <= p_ch && t_ch >= prev_ch)
|
||||
matched = TRUE;
|
||||
ch = 0; /* This makes "prev" get set to 0. */
|
||||
}
|
||||
else if (ch == '[' && p[1] == ':') {
|
||||
p_ch = 0; /* This makes "prev_ch" get set to 0. */
|
||||
} else if (p_ch == '[' && p[1] == ':') {
|
||||
const uchar *s;
|
||||
int i;
|
||||
for (s = p += 2; (ch = *p) && ch != ']'; p++) {}
|
||||
if (!ch)
|
||||
for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {}
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
i = p - s - 1;
|
||||
if (i < 0 || p[-1] != ':') {
|
||||
/* Didn't find ":]", so treat like a normal set. */
|
||||
p = s - 2;
|
||||
ch = '[';
|
||||
if (*text == ch)
|
||||
p_ch = '[';
|
||||
if (t_ch == p_ch)
|
||||
matched = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (CC_EQ(s,i, "alnum")) {
|
||||
if (ISALNUM(*text))
|
||||
if (ISALNUM(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "alpha")) {
|
||||
if (ISALPHA(*text))
|
||||
} else if (CC_EQ(s,i, "alpha")) {
|
||||
if (ISALPHA(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "blank")) {
|
||||
if (ISBLANK(*text))
|
||||
} else if (CC_EQ(s,i, "blank")) {
|
||||
if (ISBLANK(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "cntrl")) {
|
||||
if (ISCNTRL(*text))
|
||||
} else if (CC_EQ(s,i, "cntrl")) {
|
||||
if (ISCNTRL(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "digit")) {
|
||||
if (ISDIGIT(*text))
|
||||
} else if (CC_EQ(s,i, "digit")) {
|
||||
if (ISDIGIT(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "graph")) {
|
||||
if (ISGRAPH(*text))
|
||||
} else if (CC_EQ(s,i, "graph")) {
|
||||
if (ISGRAPH(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "lower")) {
|
||||
if (ISLOWER(*text))
|
||||
} else if (CC_EQ(s,i, "lower")) {
|
||||
if (ISLOWER(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "print")) {
|
||||
if (ISPRINT(*text))
|
||||
} else if (CC_EQ(s,i, "print")) {
|
||||
if (ISPRINT(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "punct")) {
|
||||
if (ISPUNCT(*text))
|
||||
} else if (CC_EQ(s,i, "punct")) {
|
||||
if (ISPUNCT(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "space")) {
|
||||
if (ISSPACE(*text))
|
||||
} else if (CC_EQ(s,i, "space")) {
|
||||
if (ISSPACE(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "upper")) {
|
||||
if (ISUPPER(*text))
|
||||
} else if (CC_EQ(s,i, "upper")) {
|
||||
if (ISUPPER(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else if (CC_EQ(s,i, "xdigit")) {
|
||||
if (ISXDIGIT(*text))
|
||||
} else if (CC_EQ(s,i, "xdigit")) {
|
||||
if (ISXDIGIT(t_ch))
|
||||
matched = TRUE;
|
||||
}
|
||||
else /* malformed [:class:] string */
|
||||
} else /* malformed [:class:] string */
|
||||
return ABORT_ALL;
|
||||
ch = 0; /* This makes "prev" get set to 0. */
|
||||
}
|
||||
else if (*text == ch)
|
||||
p_ch = 0; /* This makes "prev_ch" get set to 0. */
|
||||
} else if (t_ch == p_ch)
|
||||
matched = TRUE;
|
||||
} while (prev = ch, (ch = *++p) != ']');
|
||||
if (matched == special || *text == '/')
|
||||
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
|
||||
if (matched == special || t_ch == '/')
|
||||
return FALSE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return *text == '\0';
|
||||
do {
|
||||
if (*text)
|
||||
return FALSE;
|
||||
} while ((text = *a++) != NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Find the pattern (p) in the text string (t). */
|
||||
int wildmatch(const char *p, const char *t)
|
||||
/* Match literal string "s" against the a virtually-joined string consisting
|
||||
* of "text" and any strings in array "a". */
|
||||
static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
|
||||
{
|
||||
for ( ; *s != '\0'; text++, s++) {
|
||||
while (*text == '\0') {
|
||||
if ((text = *a++) == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
if (*text != *s)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
do {
|
||||
if (*text)
|
||||
return FALSE;
|
||||
} while ((text = *a++) != NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return the last "count" path elements from the concatenated string.
|
||||
* We return a string pointer to the start of the string, and update the
|
||||
* array pointer-pointer to point to any remaining string elements. */
|
||||
static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
|
||||
{
|
||||
const uchar*const *a = *a_ptr;
|
||||
const uchar*const *first_a = a;
|
||||
|
||||
while (*a)
|
||||
a++;
|
||||
|
||||
while (a != first_a) {
|
||||
const uchar *s = *--a;
|
||||
s += strlen((char*)s);
|
||||
while (--s >= *a) {
|
||||
if (*s == '/' && !--count) {
|
||||
*a_ptr = a+1;
|
||||
return s+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
*a_ptr = a+1;
|
||||
return *a;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Match the "pattern" against the "text" string. */
|
||||
int wildmatch(const char *pattern, const char *text)
|
||||
{
|
||||
static const uchar *nomore[1]; /* A NULL pointer. */
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
return domatch((const uchar*)p, (const uchar*)t) == TRUE;
|
||||
return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
|
||||
}
|
||||
|
||||
/* Match the "pattern" against the forced-to-lower-case "text" string. */
|
||||
int iwildmatch(const char *pattern, const char *text)
|
||||
{
|
||||
static const uchar *nomore[1]; /* A NULL pointer. */
|
||||
int ret;
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
force_lower_case = 1;
|
||||
ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
|
||||
force_lower_case = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Match pattern "p" against the a virtually-joined string consisting
|
||||
* of all the pointers in array "texts" (which has a NULL pointer at the
|
||||
* end). The int "where" can be 0 (normal matching), > 0 (match only
|
||||
* the trailing N slash-separated filename components of "texts"), or < 0
|
||||
* (match the "pattern" at the start or after any slash in "texts"). */
|
||||
int wildmatch_array(const char *pattern, const char*const *texts, int where)
|
||||
{
|
||||
const uchar *p = (const uchar*)pattern;
|
||||
const uchar*const *a = (const uchar*const*)texts;
|
||||
const uchar *text;
|
||||
int matched;
|
||||
|
||||
#ifdef WILD_TEST_ITERATIONS
|
||||
wildmatch_iteration_count = 0;
|
||||
#endif
|
||||
|
||||
if (where > 0)
|
||||
text = trailing_N_elements(&a, where);
|
||||
else
|
||||
text = *a++;
|
||||
if (!text)
|
||||
return FALSE;
|
||||
|
||||
if ((matched = dowild(p, text, a)) != TRUE && where < 0
|
||||
&& matched != ABORT_ALL) {
|
||||
while (1) {
|
||||
if (*text == '\0') {
|
||||
if ((text = (uchar*)*a++) == NULL)
|
||||
return FALSE;
|
||||
continue;
|
||||
}
|
||||
if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
|
||||
&& matched != ABORT_TO_STARSTAR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return matched == TRUE;
|
||||
}
|
||||
|
||||
/* Match literal string "s" against the a virtually-joined string consisting
|
||||
* of all the pointers in array "texts" (which has a NULL pointer at the
|
||||
* end). The int "where" can be 0 (normal matching), or > 0 (match
|
||||
* only the trailing N slash-separated filename components of "texts"). */
|
||||
int litmatch_array(const char *string, const char*const *texts, int where)
|
||||
{
|
||||
const uchar *s = (const uchar*)string;
|
||||
const uchar*const *a = (const uchar* const*)texts;
|
||||
const uchar *text;
|
||||
|
||||
if (where > 0)
|
||||
text = trailing_N_elements(&a, where);
|
||||
else
|
||||
text = *a++;
|
||||
if (!text)
|
||||
return FALSE;
|
||||
|
||||
return doliteral(s, text, a) == TRUE;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/* wildmatch.h */
|
||||
|
||||
int wildmatch(const char *p, const char *text);
|
||||
int wildmatch(const char *pattern, const char *text);
|
||||
int iwildmatch(const char *pattern, const char *text);
|
||||
int wildmatch_array(const char *pattern, const char*const *texts, int where);
|
||||
int litmatch_array(const char *string, const char*const *texts, int where);
|
||||
|
||||
268
loadparm.c
268
loadparm.c
@@ -98,91 +98,107 @@ struct parm_struct
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *motd_file;
|
||||
char *bind_address;
|
||||
char *log_file;
|
||||
char *motd_file;
|
||||
char *pid_file;
|
||||
char *socket_options;
|
||||
char *bind_address;
|
||||
int syslog_facility;
|
||||
|
||||
int rsync_port;
|
||||
int syslog_facility;
|
||||
} global;
|
||||
|
||||
static global Globals;
|
||||
|
||||
|
||||
/*
|
||||
* This structure describes a single service.
|
||||
* This structure describes a single service. Their order must match the
|
||||
* initializers below, which you can accomplish by keeping each sub-section
|
||||
* sorted. (e.g. in vim, just visually select each subsection and use !sort.)
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char *path;
|
||||
char *auth_users;
|
||||
char *comment;
|
||||
char *lock_file;
|
||||
BOOL read_only;
|
||||
BOOL write_only;
|
||||
BOOL list;
|
||||
BOOL use_chroot;
|
||||
BOOL transfer_logging;
|
||||
BOOL ignore_errors;
|
||||
char *uid;
|
||||
char *dont_compress;
|
||||
char *exclude;
|
||||
char *exclude_from;
|
||||
char *filter;
|
||||
char *gid;
|
||||
char *hosts_allow;
|
||||
char *hosts_deny;
|
||||
char *auth_users;
|
||||
char *secrets_file;
|
||||
BOOL strict_modes;
|
||||
char *filter;
|
||||
char *exclude;
|
||||
char *exclude_from;
|
||||
char *include;
|
||||
char *include_from;
|
||||
char *incoming_chmod;
|
||||
char *lock_file;
|
||||
char *log_format;
|
||||
char *refuse_options;
|
||||
char *dont_compress;
|
||||
char *prexfer_exec;
|
||||
char *name;
|
||||
char *outgoing_chmod;
|
||||
char *path;
|
||||
char *postxfer_exec;
|
||||
int timeout;
|
||||
char *prexfer_exec;
|
||||
char *refuse_options;
|
||||
char *secrets_file;
|
||||
char *temp_dir;
|
||||
char *uid;
|
||||
|
||||
int max_connections;
|
||||
int max_verbosity;
|
||||
int timeout;
|
||||
|
||||
BOOL ignore_errors;
|
||||
BOOL ignore_nonreadable;
|
||||
BOOL list;
|
||||
BOOL read_only;
|
||||
BOOL strict_modes;
|
||||
BOOL transfer_logging;
|
||||
BOOL use_chroot;
|
||||
BOOL write_only;
|
||||
} service;
|
||||
|
||||
|
||||
/* This is a default service used to prime a services structure */
|
||||
/* This is a default service used to prime a services structure. In order
|
||||
* to make these easy to keep sorted in the same way as the variables
|
||||
* above, use the variable name in the leading comment, including a
|
||||
* trailing ';' (to avoid a sorting problem with trailing digits). */
|
||||
static service sDefault =
|
||||
{
|
||||
NULL, /* name */
|
||||
NULL, /* path */
|
||||
NULL, /* comment */
|
||||
DEFAULT_LOCK_FILE, /* lock file */
|
||||
True, /* read only */
|
||||
False, /* write only */
|
||||
True, /* list */
|
||||
True, /* use chroot */
|
||||
False, /* transfer logging */
|
||||
False, /* ignore errors */
|
||||
NOBODY_USER,/* uid */
|
||||
NOBODY_GROUP,/* gid */
|
||||
NULL, /* hosts allow */
|
||||
NULL, /* hosts deny */
|
||||
NULL, /* auth users */
|
||||
NULL, /* secrets file */
|
||||
True, /* strict modes */
|
||||
NULL, /* filter */
|
||||
NULL, /* exclude */
|
||||
NULL, /* exclude from */
|
||||
NULL, /* include */
|
||||
NULL, /* include from */
|
||||
"%o %h [%a] %m (%u) %f %l", /* log format */
|
||||
NULL, /* refuse options */
|
||||
"*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz", /* dont compress */
|
||||
NULL, /* prexfer_exec */
|
||||
NULL, /* postxfer_exec */
|
||||
0, /* timeout */
|
||||
0, /* max connections */
|
||||
1, /* max verbosity */
|
||||
False /* ignore nonreadable */
|
||||
/* auth_users; */ NULL,
|
||||
/* comment; */ NULL,
|
||||
/* dont_compress; */ "*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz",
|
||||
/* exclude; */ NULL,
|
||||
/* exclude_from; */ NULL,
|
||||
/* filter; */ NULL,
|
||||
/* gid; */ NOBODY_GROUP,
|
||||
/* hosts_allow; */ NULL,
|
||||
/* hosts_deny; */ NULL,
|
||||
/* include; */ NULL,
|
||||
/* include_from; */ NULL,
|
||||
/* incoming_chmod; */ NULL,
|
||||
/* lock_file; */ DEFAULT_LOCK_FILE,
|
||||
/* log_format; */ "%o %h [%a] %m (%u) %f %l",
|
||||
/* name; */ NULL,
|
||||
/* outgoing_chmod; */ NULL,
|
||||
/* path; */ NULL,
|
||||
/* postxfer_exec; */ NULL,
|
||||
/* prexfer_exec; */ NULL,
|
||||
/* refuse_options; */ NULL,
|
||||
/* secrets_file; */ NULL,
|
||||
/* temp_dir; */ NULL,
|
||||
/* uid; */ NOBODY_USER,
|
||||
|
||||
/* max_connections; */ 0,
|
||||
/* max_verbosity; */ 1,
|
||||
/* timeout; */ 0,
|
||||
|
||||
/* ignore_errors; */ False,
|
||||
/* ignore_nonreadable; */ False,
|
||||
/* list; */ True,
|
||||
/* read_only; */ True,
|
||||
/* strict_modes; */ True,
|
||||
/* transfer_logging; */ False,
|
||||
/* use_chroot; */ True,
|
||||
/* write_only; */ False,
|
||||
};
|
||||
|
||||
|
||||
@@ -265,48 +281,51 @@ static struct enum_list enum_facilities[] = {
|
||||
/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
|
||||
static struct parm_struct parm_table[] =
|
||||
{
|
||||
{"motd file", P_STRING, P_GLOBAL, &Globals.motd_file, NULL, 0},
|
||||
{"syslog facility", P_ENUM, P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
|
||||
{"socket options", P_STRING, P_GLOBAL, &Globals.socket_options,NULL, 0},
|
||||
{"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0},
|
||||
{"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0},
|
||||
{"port", P_INTEGER, P_GLOBAL, &Globals.rsync_port, NULL, 0},
|
||||
{"address", P_STRING, P_GLOBAL, &Globals.bind_address, NULL, 0},
|
||||
{"address", P_STRING, P_GLOBAL,&Globals.bind_address, NULL,0},
|
||||
{"log file", P_STRING, P_GLOBAL,&Globals.log_file, NULL,0},
|
||||
{"motd file", P_STRING, P_GLOBAL,&Globals.motd_file, NULL,0},
|
||||
{"pid file", P_STRING, P_GLOBAL,&Globals.pid_file, NULL,0},
|
||||
{"port", P_INTEGER,P_GLOBAL,&Globals.rsync_port, NULL,0},
|
||||
{"socket options", P_STRING, P_GLOBAL,&Globals.socket_options, NULL,0},
|
||||
{"syslog facility", P_ENUM, P_GLOBAL,&Globals.syslog_facility,enum_facilities,0},
|
||||
|
||||
{"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0},
|
||||
{"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0},
|
||||
{"max verbosity", P_INTEGER, P_LOCAL, &sDefault.max_verbosity,NULL, 0},
|
||||
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
|
||||
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
|
||||
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
|
||||
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL, 0},
|
||||
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
|
||||
{"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL, 0},
|
||||
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
|
||||
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
|
||||
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable, NULL, 0},
|
||||
{"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL, 0},
|
||||
{"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL, 0},
|
||||
{"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL, 0},
|
||||
{"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL, 0},
|
||||
{"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},
|
||||
{"include from", P_STRING, P_LOCAL, &sDefault.include_from,NULL, 0},
|
||||
{"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0},
|
||||
{"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors,NULL,0},
|
||||
{"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL, 0},
|
||||
{"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options,NULL, 0},
|
||||
{"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress,NULL, 0},
|
||||
{"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL,0},
|
||||
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL,0},
|
||||
{"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress, NULL,0},
|
||||
{"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from, NULL,0},
|
||||
{"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL,0},
|
||||
{"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL,0},
|
||||
{"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL,0},
|
||||
{"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL,0},
|
||||
{"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL,0},
|
||||
{"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors, NULL,0},
|
||||
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable,NULL,0},
|
||||
{"include from", P_STRING, P_LOCAL, &sDefault.include_from, NULL,0},
|
||||
{"include", P_STRING, P_LOCAL, &sDefault.include, NULL,0},
|
||||
{"incoming chmod", P_STRING, P_LOCAL, &sDefault.incoming_chmod, NULL,0},
|
||||
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL,0},
|
||||
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL,0},
|
||||
{"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL,0},
|
||||
{"max connections", P_INTEGER,P_LOCAL, &sDefault.max_connections, NULL,0},
|
||||
{"max verbosity", P_INTEGER,P_LOCAL, &sDefault.max_verbosity, NULL,0},
|
||||
{"name", P_STRING, P_LOCAL, &sDefault.name, NULL,0},
|
||||
{"outgoing chmod", P_STRING, P_LOCAL, &sDefault.outgoing_chmod, NULL,0},
|
||||
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL,0},
|
||||
#ifdef HAVE_PUTENV
|
||||
{"pre-xfer exec", P_STRING, P_LOCAL, &sDefault.prexfer_exec, NULL, 0},
|
||||
{"post-xfer exec", P_STRING, P_LOCAL, &sDefault.postxfer_exec,NULL, 0},
|
||||
{"post-xfer exec", P_STRING, P_LOCAL, &sDefault.postxfer_exec, NULL,0},
|
||||
{"pre-xfer exec", P_STRING, P_LOCAL, &sDefault.prexfer_exec, NULL,0},
|
||||
#endif
|
||||
{NULL, P_BOOL, P_NONE, NULL, NULL, 0}
|
||||
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL,0},
|
||||
{"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options, NULL,0},
|
||||
{"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file, NULL,0},
|
||||
{"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes, NULL,0},
|
||||
{"temp dir", P_PATH, P_LOCAL, &sDefault.temp_dir, NULL,0},
|
||||
{"timeout", P_INTEGER,P_LOCAL, &sDefault.timeout, NULL,0},
|
||||
{"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging, NULL,0},
|
||||
{"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL,0},
|
||||
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL,0},
|
||||
{"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL,0},
|
||||
{NULL, P_BOOL, P_NONE, NULL, NULL,0}
|
||||
};
|
||||
|
||||
|
||||
@@ -353,45 +372,51 @@ static void init_locals(void)
|
||||
int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
|
||||
|
||||
|
||||
FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
|
||||
FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
|
||||
FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
|
||||
FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
|
||||
FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
|
||||
FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
|
||||
FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
|
||||
FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
|
||||
FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
|
||||
|
||||
FN_LOCAL_STRING(lp_name, name)
|
||||
FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
|
||||
FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
|
||||
|
||||
FN_LOCAL_STRING(lp_auth_users, auth_users)
|
||||
FN_LOCAL_STRING(lp_comment, comment)
|
||||
FN_LOCAL_STRING(lp_path, path)
|
||||
FN_LOCAL_STRING(lp_lock_file, lock_file)
|
||||
FN_LOCAL_BOOL(lp_read_only, read_only)
|
||||
FN_LOCAL_BOOL(lp_write_only, write_only)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
|
||||
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
|
||||
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
|
||||
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
|
||||
FN_LOCAL_STRING(lp_uid, uid)
|
||||
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
|
||||
FN_LOCAL_STRING(lp_exclude, exclude)
|
||||
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
|
||||
FN_LOCAL_STRING(lp_filter, filter)
|
||||
FN_LOCAL_STRING(lp_gid, gid)
|
||||
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
|
||||
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)
|
||||
FN_LOCAL_STRING(lp_include_from, include_from)
|
||||
FN_LOCAL_STRING(lp_incoming_chmod, incoming_chmod)
|
||||
FN_LOCAL_STRING(lp_lock_file, lock_file)
|
||||
FN_LOCAL_STRING(lp_log_format, log_format)
|
||||
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
|
||||
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
|
||||
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
|
||||
FN_LOCAL_STRING(lp_name, name)
|
||||
FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod)
|
||||
FN_LOCAL_STRING(lp_path, path)
|
||||
FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
|
||||
FN_LOCAL_INTEGER(lp_timeout, timeout)
|
||||
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
|
||||
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
|
||||
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
|
||||
FN_LOCAL_STRING(lp_temp_dir, temp_dir)
|
||||
FN_LOCAL_STRING(lp_uid, uid)
|
||||
|
||||
FN_LOCAL_INTEGER(lp_max_connections, max_connections)
|
||||
FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
|
||||
FN_LOCAL_INTEGER(lp_timeout, timeout)
|
||||
|
||||
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
|
||||
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
FN_LOCAL_BOOL(lp_read_only, read_only)
|
||||
FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
|
||||
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
|
||||
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
|
||||
FN_LOCAL_BOOL(lp_write_only, write_only)
|
||||
|
||||
/* local prototypes */
|
||||
static int strwicmp(char *psz1, char *psz2);
|
||||
@@ -777,7 +802,6 @@ False on failure.
|
||||
BOOL lp_load(char *pszFname, int globals_only)
|
||||
{
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
pstring n2;
|
||||
BOOL bRetval;
|
||||
@@ -790,7 +814,7 @@ BOOL lp_load(char *pszFname, int globals_only)
|
||||
|
||||
if (pszFname)
|
||||
pstrcpy(n2,pszFname);
|
||||
else if (am_server && am_daemon && !am_root)
|
||||
else if (am_server && !am_root)
|
||||
pstrcpy(n2,RSYNCD_USERCONF);
|
||||
else
|
||||
pstrcpy(n2,RSYNCD_SYSCONF);
|
||||
|
||||
232
log.c
232
log.c
@@ -26,6 +26,9 @@
|
||||
<mbp@samba.org>, Oct 2000.
|
||||
*/
|
||||
#include "rsync.h"
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
@@ -36,12 +39,18 @@ extern int local_server;
|
||||
extern int quiet;
|
||||
extern int module_id;
|
||||
extern int msg_fd_out;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int preserve_times;
|
||||
extern int log_format_has_i;
|
||||
extern int log_format_has_o_or_i;
|
||||
extern int daemon_log_format_has_o_or_i;
|
||||
extern mode_t orig_umask;
|
||||
extern char *auth_user;
|
||||
extern char *log_format;
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
extern iconv_t ic_chck;
|
||||
#endif
|
||||
|
||||
static int log_initialised;
|
||||
static int logfile_was_closed;
|
||||
@@ -65,8 +74,11 @@ struct {
|
||||
{ RERR_STREAMIO , "error in rsync protocol data stream" },
|
||||
{ RERR_MESSAGEIO , "errors with program diagnostics" },
|
||||
{ RERR_IPC , "error in IPC code" },
|
||||
{ RERR_SIGNAL , "received SIGUSR1 or SIGINT" },
|
||||
{ RERR_WAITCHILD , "some error returned by waitpid()" },
|
||||
{ RERR_CRASHED , "sibling process crashed" },
|
||||
{ RERR_TERMINATED , "sibling process terminated abnormally" },
|
||||
{ RERR_SIGNAL1 , "received SIGUSR1" },
|
||||
{ RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" },
|
||||
{ RERR_WAITCHILD , "waitpid() failed" },
|
||||
{ RERR_MALLOC , "error allocating core memory buffers" },
|
||||
{ RERR_PARTIAL , "some files could not be transferred" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transferred" },
|
||||
@@ -80,7 +92,6 @@ struct {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Map from rsync error code to name, or return NULL.
|
||||
*/
|
||||
@@ -94,7 +105,6 @@ static char const *rerr_name(int code)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void logit(int priority, char *buf)
|
||||
{
|
||||
if (logfile_was_closed)
|
||||
@@ -134,8 +144,7 @@ static void syslog_init()
|
||||
|
||||
static void logfile_open(void)
|
||||
{
|
||||
extern int orig_umask;
|
||||
int old_umask = umask(022 | orig_umask);
|
||||
mode_t old_umask = umask(022 | orig_umask);
|
||||
logfile = fopen(logfname, "a");
|
||||
umask(old_umask);
|
||||
if (!logfile) {
|
||||
@@ -187,20 +196,41 @@ void logfile_reopen(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
|
||||
{
|
||||
const char *s, *end = buf + len;
|
||||
for (s = buf; s < end; s++) {
|
||||
if ((s < end - 4
|
||||
&& *s == '\\' && s[1] == '#'
|
||||
&& isdigit(*(uchar*)(s+2))
|
||||
&& isdigit(*(uchar*)(s+3))
|
||||
&& isdigit(*(uchar*)(s+4)))
|
||||
|| (*s != '\t'
|
||||
&& ((use_isprint && !isprint(*(uchar*)s))
|
||||
|| *(uchar*)s < ' '))) {
|
||||
if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
fprintf(f, "\\#%03o", *(uchar*)s);
|
||||
buf = s + 1;
|
||||
}
|
||||
}
|
||||
if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
/* this is the underlying (unformatted) rsync debugging function. Call
|
||||
* it with FINFO, FERROR or FLOG */
|
||||
* it with FINFO, FERROR or FLOG. Note: recursion can happen with
|
||||
* certain fatal conditions. */
|
||||
void rwrite(enum logcode code, char *buf, int len)
|
||||
{
|
||||
int trailing_CR_or_NL;
|
||||
FILE *f = NULL;
|
||||
/* recursion can happen with certain fatal conditions */
|
||||
|
||||
if (quiet && code == FINFO)
|
||||
return;
|
||||
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
buf[len] = 0;
|
||||
if (quiet && code == FINFO)
|
||||
return;
|
||||
|
||||
if (am_server && msg_fd_out >= 0) {
|
||||
/* Pass the message to our sibling. */
|
||||
@@ -208,6 +238,9 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == FSOCKERR) /* This gets simplified for a non-sibling. */
|
||||
code = FERROR;
|
||||
|
||||
if (code == FCLIENT)
|
||||
code = FINFO;
|
||||
else if (am_daemon) {
|
||||
@@ -239,31 +272,67 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
if (code == FERROR) {
|
||||
switch (code) {
|
||||
case FERROR:
|
||||
log_got_error = 1;
|
||||
f = stderr;
|
||||
goto pre_scan;
|
||||
case FINFO:
|
||||
f = am_server ? stderr : stdout;
|
||||
pre_scan:
|
||||
while (len > 1 && *buf == '\n') {
|
||||
fputc(*buf, f);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
case FNAME:
|
||||
f = am_server ? stderr : stdout;
|
||||
break;
|
||||
default:
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (code == FINFO)
|
||||
f = am_server ? stderr : stdout;
|
||||
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
|
||||
? buf[--len] : 0;
|
||||
|
||||
if (!f)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
if (ic_chck != (iconv_t)-1) {
|
||||
char convbuf[1024];
|
||||
char *in_buf = buf, *out_buf = convbuf;
|
||||
size_t in_cnt = len, out_cnt = sizeof convbuf - 1;
|
||||
|
||||
if (fwrite(buf, len, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
iconv(ic_chck, NULL, 0, NULL, 0);
|
||||
while (iconv(ic_chck, &in_buf,&in_cnt,
|
||||
&out_buf,&out_cnt) == (size_t)-1) {
|
||||
if (out_buf != convbuf) {
|
||||
filtered_fwrite(f, convbuf, out_buf - convbuf, 0);
|
||||
out_buf = convbuf;
|
||||
out_cnt = sizeof convbuf - 1;
|
||||
}
|
||||
if (errno == E2BIG)
|
||||
continue;
|
||||
fprintf(f, "\\#%03o", *(uchar*)in_buf++);
|
||||
in_cnt--;
|
||||
}
|
||||
if (out_buf != convbuf)
|
||||
filtered_fwrite(f, convbuf, out_buf - convbuf, 0);
|
||||
} else
|
||||
#endif
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars);
|
||||
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n')
|
||||
if (trailing_CR_or_NL) {
|
||||
fputc(trailing_CR_or_NL, f);
|
||||
fflush(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This is the rsync debugging function. Call it with FINFO, FERROR or
|
||||
* FLOG. */
|
||||
void rprintf(enum logcode code, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[MAXPATHLEN+512];
|
||||
char buf[BIGPATHBUFLEN];
|
||||
size_t len;
|
||||
|
||||
va_start(ap, format);
|
||||
@@ -274,7 +343,7 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
* truncate the resulting string. (Note that configure ensures
|
||||
* that we have a vsnprintf() that doesn't ever return -1.) */
|
||||
if (len > sizeof buf - 1) {
|
||||
const char ellipsis[] = "[...]";
|
||||
static const char ellipsis[] = "[...]";
|
||||
|
||||
/* Reset length, and zero-terminate the end of our buffer */
|
||||
len = sizeof buf - 1;
|
||||
@@ -290,7 +359,7 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
* 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);
|
||||
memcpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis);
|
||||
if (format[strlen(format)-1] == '\n') {
|
||||
buf[len-1] = '\n';
|
||||
}
|
||||
@@ -299,7 +368,6 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
rwrite(code, buf, len);
|
||||
}
|
||||
|
||||
|
||||
/* This is like rprintf, but it also tries to print some
|
||||
* representation of the error code. Normally errcode = errno.
|
||||
*
|
||||
@@ -311,7 +379,7 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[MAXPATHLEN+512];
|
||||
char buf[BIGPATHBUFLEN];
|
||||
size_t len;
|
||||
|
||||
strcpy(buf, RSYNC_NAME ": ");
|
||||
@@ -331,8 +399,6 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
rwrite(code, buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rflush(enum logcode code)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
@@ -360,8 +426,6 @@ void rflush(enum logcode code)
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* a generic logging routine for send/recv, with parameter
|
||||
* substitiution */
|
||||
static void log_formatted(enum logcode code, char *format, char *op,
|
||||
@@ -399,51 +463,83 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
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 'h':
|
||||
if (am_daemon)
|
||||
n = client_name(0);
|
||||
break;
|
||||
case 'a':
|
||||
if (am_daemon)
|
||||
n = client_addr(0);
|
||||
break;
|
||||
case 'l':
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(double)file->length);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'U':
|
||||
strlcat(fmt, "ld", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(long)file->uid);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'G':
|
||||
if (file->gid == GID_NONE)
|
||||
n = "DEFAULT";
|
||||
else {
|
||||
strlcat(fmt, "ld", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(long)file->gid);
|
||||
n = buf2;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
strlcat(fmt, "ld", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(long)getpid());
|
||||
n = buf2;
|
||||
break;
|
||||
case 'o': n = op; break;
|
||||
case 'M':
|
||||
n = timestring(file->modtime);
|
||||
{
|
||||
char *cp = n;
|
||||
while ((cp = strchr(cp, ' ')) != NULL)
|
||||
*cp = '-';
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
n = buf2 + MAXPATHLEN - PERMSTRING_SIZE;
|
||||
permstring(n - 1, file->mode); /* skip the type char */
|
||||
break;
|
||||
case 'o':
|
||||
n = op;
|
||||
break;
|
||||
case 'f':
|
||||
n = safe_fname(f_name(file));
|
||||
n = f_name(file, NULL);
|
||||
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. */
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1])
|
||||
strcpy(n, buf2);
|
||||
strlcpy(n, buf2, MAXPATHLEN);
|
||||
else
|
||||
n = buf2;
|
||||
}
|
||||
clean_fname(n, 0);
|
||||
} else
|
||||
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, "/");
|
||||
}
|
||||
n = f_name(file, NULL);
|
||||
if (S_ISDIR(file->mode))
|
||||
strlcat(n, "/", MAXPATHLEN);
|
||||
break;
|
||||
case 'L':
|
||||
if (hlink && *hlink) {
|
||||
n = safe_fname(hlink);
|
||||
n = hlink;
|
||||
strcpy(buf2, " => ");
|
||||
} else if (S_ISLNK(file->mode) && file->u.link) {
|
||||
n = safe_fname(file->u.link);
|
||||
n = file->u.link;
|
||||
strcpy(buf2, " -> ");
|
||||
} else {
|
||||
n = "";
|
||||
@@ -455,10 +551,18 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'm': n = lp_name(module_id); break;
|
||||
case 't': n = timestring(time(NULL)); break;
|
||||
case 'P': n = lp_path(module_id); break;
|
||||
case 'u': n = auth_user; break;
|
||||
case 'm':
|
||||
n = lp_name(module_id);
|
||||
break;
|
||||
case 't':
|
||||
n = timestring(time(NULL));
|
||||
break;
|
||||
case 'P':
|
||||
n = lp_path(module_id);
|
||||
break;
|
||||
case 'u':
|
||||
n = auth_user;
|
||||
break;
|
||||
case 'b':
|
||||
if (am_sender) {
|
||||
b = stats.total_written -
|
||||
@@ -494,17 +598,17 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
n[1] = S_ISDIR(file->mode) ? 'd'
|
||||
: IS_SPECIAL(file->mode) ? 'S'
|
||||
: 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';
|
||||
: !preserve_times || 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[8] = '.';
|
||||
n[9] = '\0';
|
||||
|
||||
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
|
||||
@@ -512,7 +616,8 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
int i;
|
||||
for (i = 2; n[i]; i++)
|
||||
n[i] = ch;
|
||||
} else if (n[0] == '.' || n[0] == 'h') {
|
||||
} else if (n[0] == '.' || n[0] == 'h'
|
||||
|| (n[0] == 'c' && n[1] == 'f')) {
|
||||
int i;
|
||||
for (i = 2; n[i]; i++) {
|
||||
if (n[i] != '.')
|
||||
@@ -594,7 +699,7 @@ void log_item(struct file_struct *file, struct stats *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, s_or_r,
|
||||
log_formatted(FNAME, log_format, s_or_r,
|
||||
file, initial_stats, iflags, hlink);
|
||||
}
|
||||
}
|
||||
@@ -603,9 +708,9 @@ void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
char *buf)
|
||||
{
|
||||
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
|
||||
int see_item = itemizing && (significant_flags || *buf || verbose > 1);
|
||||
int local_change = iflags & ITEM_LOCAL_CHANGE
|
||||
&& (!(iflags & ITEM_XNAME_FOLLOWS) || significant_flags);
|
||||
int see_item = itemizing && (significant_flags || *buf
|
||||
|| log_format_has_i > 1 || (verbose > 1 && log_format_has_i));
|
||||
int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
|
||||
if (am_server) {
|
||||
if (am_daemon && !dry_run && see_item)
|
||||
log_item(file, &stats, iflags, buf);
|
||||
@@ -642,7 +747,6 @@ void log_delete(char *fname, int mode)
|
||||
log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when the transfer is interrupted for some reason.
|
||||
*
|
||||
@@ -665,11 +769,11 @@ void log_exit(int code, const char *file, int line)
|
||||
|
||||
/* VANISHED is not an error, only a warning */
|
||||
if (code == RERR_VANISHED) {
|
||||
rprintf(FINFO, "rsync warning: %s (code %d) at %s(%d)\n",
|
||||
name, code, file, line);
|
||||
rprintf(FINFO, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n",
|
||||
name, code, file, line, who_am_i(), RSYNC_VERSION);
|
||||
} else {
|
||||
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d)\n",
|
||||
name, code, file, line);
|
||||
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n",
|
||||
name, code, file, line, who_am_i(), RSYNC_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
407
main.c
407
main.c
@@ -40,8 +40,8 @@ extern int kluge_around_eof;
|
||||
extern int do_stats;
|
||||
extern int log_got_error;
|
||||
extern int module_id;
|
||||
extern int orig_umask;
|
||||
extern int copy_links;
|
||||
extern int copy_dirlinks;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int protocol_version;
|
||||
@@ -62,15 +62,25 @@ extern char *shell_cmd;
|
||||
extern char *batch_name;
|
||||
|
||||
int local_server = 0;
|
||||
mode_t orig_umask = 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. */
|
||||
#define MAXCHILDPROCS 5
|
||||
#define MAXCHILDPROCS 7
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
# ifdef HAVE_SIGPROCMASK
|
||||
# define SIGACTMASK(n,h) SIGACTION(n,h), sigaddset(&sigmask,(n))
|
||||
# else
|
||||
# define SIGACTMASK(n,h) SIGACTION(n,h)
|
||||
# endif
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
struct pid_status {
|
||||
pid_t pid;
|
||||
int status;
|
||||
int status;
|
||||
} pid_stat_table[MAXCHILDPROCS];
|
||||
|
||||
static time_t starttime, endtime;
|
||||
@@ -78,38 +88,58 @@ static int64 total_read, total_written;
|
||||
|
||||
static void show_malloc_stats(void);
|
||||
|
||||
/****************************************************************************
|
||||
wait for a process to exit, calling io_flush while waiting
|
||||
****************************************************************************/
|
||||
void wait_process(pid_t pid, int *status)
|
||||
/* Works like waitpid(), but if we already harvested the child pid in our
|
||||
* remember_children(), we succeed instead of returning an error. */
|
||||
pid_t wait_process(pid_t pid, int *status_ptr, int flags)
|
||||
{
|
||||
pid_t waited_pid;
|
||||
int cnt;
|
||||
|
||||
while ((waited_pid = waitpid(pid, status, WNOHANG)) == 0) {
|
||||
msleep(20);
|
||||
io_flush(FULL_FLUSH);
|
||||
}
|
||||
pid_t waited_pid = waitpid(pid, status_ptr, flags);
|
||||
|
||||
if (waited_pid == -1 && errno == ECHILD) {
|
||||
/* status of requested child no longer available.
|
||||
* check to see if it was processed by the sigchld_handler.
|
||||
*/
|
||||
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
|
||||
/* Status of requested child no longer available: check to
|
||||
* see if it was processed by remember_children(). */
|
||||
int cnt;
|
||||
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
|
||||
if (pid == pid_stat_table[cnt].pid) {
|
||||
*status = pid_stat_table[cnt].status;
|
||||
*status_ptr = pid_stat_table[cnt].status;
|
||||
pid_stat_table[cnt].pid = 0;
|
||||
break;
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return waited_pid;
|
||||
}
|
||||
|
||||
/* Wait for a process to exit, calling io_flush while waiting. */
|
||||
static void wait_process_with_flush(pid_t pid, int *exit_code_ptr)
|
||||
{
|
||||
pid_t waited_pid;
|
||||
int status;
|
||||
|
||||
while ((waited_pid = wait_process(pid, &status, WNOHANG)) == 0) {
|
||||
msleep(20);
|
||||
io_flush(FULL_FLUSH);
|
||||
}
|
||||
|
||||
/* TODO: If the child exited on a signal, then log an
|
||||
* appropriate error message. Perhaps we should also accept a
|
||||
* message describing the purpose of the child. Also indicate
|
||||
* this to the caller so that thhey know something went
|
||||
* wrong. */
|
||||
*status = WEXITSTATUS(*status);
|
||||
* this to the caller so that they know something went wrong. */
|
||||
if (waited_pid < 0) {
|
||||
rsyserr(FERROR, errno, "waitpid");
|
||||
*exit_code_ptr = RERR_WAITCHILD;
|
||||
} else if (!WIFEXITED(status)) {
|
||||
#ifdef WCOREDUMP
|
||||
if (WCOREDUMP(status))
|
||||
*exit_code_ptr = RERR_CRASHED;
|
||||
else
|
||||
#endif
|
||||
if (WIFSIGNALED(status))
|
||||
*exit_code_ptr = RERR_TERMINATED;
|
||||
else
|
||||
*exit_code_ptr = RERR_WAITCHILD;
|
||||
} else
|
||||
*exit_code_ptr = WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
/* This function gets called from all 3 processes. We want the client side
|
||||
@@ -189,14 +219,14 @@ static void output_summary(void)
|
||||
rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
|
||||
rprintf(FINFO,"Number of files transferred: %d\n",
|
||||
stats.num_transferred_files);
|
||||
rprintf(FINFO,"Total file size: %.0f bytes\n",
|
||||
(double)stats.total_size);
|
||||
rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
|
||||
(double)stats.total_transferred_size);
|
||||
rprintf(FINFO,"Literal data: %.0f bytes\n",
|
||||
(double)stats.literal_data);
|
||||
rprintf(FINFO,"Matched data: %.0f bytes\n",
|
||||
(double)stats.matched_data);
|
||||
rprintf(FINFO,"Total file size: %s bytes\n",
|
||||
human_num(stats.total_size));
|
||||
rprintf(FINFO,"Total transferred file size: %s bytes\n",
|
||||
human_num(stats.total_transferred_size));
|
||||
rprintf(FINFO,"Literal data: %s bytes\n",
|
||||
human_num(stats.literal_data));
|
||||
rprintf(FINFO,"Matched data: %s bytes\n",
|
||||
human_num(stats.matched_data));
|
||||
rprintf(FINFO,"File list size: %d\n", stats.flist_size);
|
||||
if (stats.flist_buildtime) {
|
||||
rprintf(FINFO,
|
||||
@@ -206,19 +236,19 @@ static void output_summary(void)
|
||||
"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",
|
||||
(double)total_read);
|
||||
rprintf(FINFO,"Total bytes sent: %s\n",
|
||||
human_num(total_written));
|
||||
rprintf(FINFO,"Total bytes received: %s\n",
|
||||
human_num(total_read));
|
||||
}
|
||||
|
||||
if (verbose || do_stats) {
|
||||
rprintf(FINFO,
|
||||
"\nsent %.0f bytes received %.0f bytes %.2f bytes/sec\n",
|
||||
(double)total_written, (double)total_read,
|
||||
(total_written + total_read)/(0.5 + (endtime - starttime)));
|
||||
rprintf(FINFO, "total size is %.0f speedup is %.2f\n",
|
||||
(double)stats.total_size,
|
||||
"\nsent %s bytes received %s bytes %s bytes/sec\n",
|
||||
human_num(total_written), human_num(total_read),
|
||||
human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2));
|
||||
rprintf(FINFO, "total size is %s speedup is %.2f\n",
|
||||
human_num(stats.total_size),
|
||||
(double)stats.total_size / (total_written+total_read));
|
||||
}
|
||||
|
||||
@@ -273,10 +303,11 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
int i, argc = 0;
|
||||
char *args[MAX_ARGS];
|
||||
pid_t ret;
|
||||
char *tok, *dir = NULL;
|
||||
char *dir = NULL;
|
||||
int dash_l_set = 0;
|
||||
|
||||
if (!read_batch && !local_server) {
|
||||
char *t, *f, in_quote = '\0';
|
||||
char *rsh_env = getenv(RSYNC_RSH_ENV);
|
||||
if (!cmd)
|
||||
cmd = rsh_env;
|
||||
@@ -286,13 +317,39 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
if (!cmd)
|
||||
goto oom;
|
||||
|
||||
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " ")) {
|
||||
for (t = f = cmd; *f; f++) {
|
||||
if (*f == ' ')
|
||||
continue;
|
||||
/* Comparison leaves rooms for server_options(). */
|
||||
if (argc >= MAX_ARGS - MAX_SERVER_ARGS) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
args[argc++] = tok;
|
||||
args[argc++] = t;
|
||||
while (*f != ' ' || in_quote) {
|
||||
if (!*f) {
|
||||
if (in_quote) {
|
||||
rprintf(FERROR,
|
||||
"Missing trailing-%c in remote-shell command.\n",
|
||||
in_quote);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
f--;
|
||||
break;
|
||||
}
|
||||
if (*f == '\'' || *f == '"') {
|
||||
if (!in_quote) {
|
||||
in_quote = *f++;
|
||||
continue;
|
||||
}
|
||||
if (*f == in_quote && *++f != in_quote) {
|
||||
in_quote = '\0';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*t++ = *f++;
|
||||
}
|
||||
*t++ = '\0';
|
||||
}
|
||||
|
||||
/* check to see if we've already been given '-l user' in
|
||||
@@ -345,10 +402,9 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
args[argc] = NULL;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"cmd=");
|
||||
for (i = 0; i < argc; i++)
|
||||
rprintf(FINFO, "%s ", safe_fname(args[i]));
|
||||
rprintf(FINFO,"\n");
|
||||
rprintf(FINFO, "cmd[%d]=%s ", i, args[i]);
|
||||
rprintf(FINFO, "\n");
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
@@ -375,62 +431,122 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
|
||||
return ret;
|
||||
|
||||
oom:
|
||||
oom:
|
||||
out_of_memory("do_cmd");
|
||||
return 0; /* not reached */
|
||||
}
|
||||
|
||||
|
||||
static char *get_local_name(struct file_list *flist,char *name)
|
||||
/* The receiving side operates in one of two modes:
|
||||
*
|
||||
* 1. it receives any number of files into a destination directory,
|
||||
* placing them according to their names in the file-list.
|
||||
*
|
||||
* 2. it receives a single file and saves it using the name in the
|
||||
* destination path instead of its file-list name. This requires a
|
||||
* "local name" for writing out the destination file.
|
||||
*
|
||||
* So, our task is to figure out what mode/local-name we need and return
|
||||
* either a NULL for mode 1, or the local-name for mode 2. We also
|
||||
* change directory if there are any path components in dest_path. */
|
||||
static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
int e;
|
||||
char *cp;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"get_local_name count=%d %s\n",
|
||||
flist->count, NS(name));
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "get_local_name count=%d %s\n",
|
||||
flist->count, NS(dest_path));
|
||||
}
|
||||
|
||||
if (!name)
|
||||
if (!dest_path || list_only)
|
||||
return NULL;
|
||||
|
||||
if (do_stat(name,&st) == 0) {
|
||||
/* If the destination path refers to an existing directory, enter
|
||||
* it and use mode 1. If there is something other than a directory
|
||||
* at the destination path, we must be transferring one file
|
||||
* (anything at the destination will be overwritten). */
|
||||
if (do_stat(dest_path, &st) == 0) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (!push_dir(name)) {
|
||||
if (!push_dir(dest_path)) {
|
||||
rsyserr(FERROR, errno, "push_dir#1 %s failed",
|
||||
full_fname(name));
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (flist->count > 1) {
|
||||
rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
|
||||
rprintf(FERROR,
|
||||
"ERROR: destination must be a directory when"
|
||||
" copying more than 1 file\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
if (flist->count <= 1 && ((e = strlen(name)) <= 1 || name[e-1] != '/'))
|
||||
return name;
|
||||
|
||||
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
|
||||
rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "created directory %s\n", safe_fname(name));
|
||||
|
||||
if (dry_run) {
|
||||
dry_run++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!push_dir(name)) {
|
||||
rsyserr(FERROR, errno, "push_dir#2 %s failed",
|
||||
full_fname(name));
|
||||
/* Caution: flist->count could be 0! */
|
||||
if (flist->count == 1 && S_ISDIR(flist->files[0]->mode)) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: cannot overwrite non-directory"
|
||||
" with a directory\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
} else if (errno != ENOENT) {
|
||||
rsyserr(FERROR, errno, "cannot stat destination %s",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
cp = strrchr(dest_path, '/');
|
||||
|
||||
/* If the destination path ends in a slash or we are transferring
|
||||
* multiple files, create a directory at the destination path,
|
||||
* enter the new directory, and use mode 1. */
|
||||
if (flist->count > 1 || (cp && !cp[1])) {
|
||||
/* Lop off the final slash (if any). */
|
||||
if (cp && !cp[1])
|
||||
*cp = '\0';
|
||||
|
||||
if (mkdir_defmode(dest_path) != 0) {
|
||||
rsyserr(FERROR, errno, "mkdir %s failed",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
rprintf(FINFO, "created directory %s\n", dest_path);
|
||||
|
||||
if (dry_run) {
|
||||
/* Indicate that the destination directory doesn't
|
||||
* really exist and return mode 1. */
|
||||
dry_run++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!push_dir(dest_path)) {
|
||||
rsyserr(FERROR, errno, "push_dir#2 %s failed",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, we are writing a single file, possibly on top of an
|
||||
* existing non-directory. Change to the item's parent directory
|
||||
* (if it has a path component), return the basename of the
|
||||
* destination file as the local name, and use mode 2. */
|
||||
if (!cp)
|
||||
return dest_path;
|
||||
|
||||
if (cp == dest_path)
|
||||
dest_path = "/";
|
||||
|
||||
*cp = '\0';
|
||||
if (!push_dir(dest_path)) {
|
||||
rsyserr(FERROR, errno, "push_dir#3 %s failed",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
*cp = '/';
|
||||
|
||||
return cp + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -458,9 +574,8 @@ static void read_final_goodbye(int f_in, int f_out)
|
||||
}
|
||||
|
||||
|
||||
static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
struct file_list *flist;
|
||||
char *dir = argv[0];
|
||||
|
||||
@@ -489,14 +604,6 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (strcmp(dir,".")) {
|
||||
int l = strlen(dir);
|
||||
if (strcmp(dir,"/") == 0)
|
||||
l = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
argv[i] += l+1;
|
||||
}
|
||||
|
||||
if (argc == 0 && (recurse || list_only)) {
|
||||
argc = 1;
|
||||
argv--;
|
||||
@@ -525,12 +632,12 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
{
|
||||
int pid;
|
||||
int status = 0;
|
||||
int exit_code = 0;
|
||||
int error_pipe[2];
|
||||
|
||||
/* The receiving side mustn't obey this, or an existing symlink that
|
||||
* points to an identical file won't be replaced by the referent. */
|
||||
copy_links = 0;
|
||||
copy_links = copy_dirlinks = 0;
|
||||
|
||||
if (preserve_hard_links)
|
||||
init_hard_links();
|
||||
@@ -611,14 +718,14 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
|
||||
set_msg_fd_in(-1);
|
||||
kill(pid, SIGUSR2);
|
||||
wait_process(pid, &status);
|
||||
return status;
|
||||
wait_process_with_flush(pid, &exit_code);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
||||
static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
{
|
||||
int status;
|
||||
int exit_code;
|
||||
struct file_list *flist;
|
||||
char *local_name = NULL;
|
||||
char *dir = NULL;
|
||||
@@ -641,7 +748,6 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (argc > 0) {
|
||||
dir = argv[0];
|
||||
argc--;
|
||||
@@ -674,17 +780,11 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
}
|
||||
the_file_list = flist;
|
||||
|
||||
if (argc > 0) {
|
||||
if (strcmp(dir,".")) {
|
||||
argv[0] += strlen(dir);
|
||||
if (argv[0][0] == '/')
|
||||
argv[0]++;
|
||||
}
|
||||
if (argc > 0)
|
||||
local_name = get_local_name(flist,argv[0]);
|
||||
}
|
||||
|
||||
status = do_recv(f_in,f_out,flist,local_name);
|
||||
exit_cleanup(status);
|
||||
exit_code = do_recv(f_in,f_out,flist,local_name);
|
||||
exit_cleanup(exit_code);
|
||||
}
|
||||
|
||||
|
||||
@@ -702,6 +802,9 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
setup_protocol(f_out, f_in);
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
setup_iconv();
|
||||
#endif
|
||||
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_out();
|
||||
@@ -727,7 +830,7 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
{
|
||||
struct file_list *flist = NULL;
|
||||
int status = 0, status2 = 0;
|
||||
int exit_code = 0, exit_code2 = 0;
|
||||
char *local_name = NULL;
|
||||
|
||||
cleanup_child_pid = pid;
|
||||
@@ -738,6 +841,9 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
setup_protocol(f_out,f_in);
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
setup_iconv();
|
||||
#endif
|
||||
|
||||
if (protocol_version >= 23 && !read_batch)
|
||||
io_start_multiplex_in();
|
||||
@@ -779,11 +885,11 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
|
||||
io_flush(FULL_FLUSH);
|
||||
wait_process(pid, &status);
|
||||
wait_process_with_flush(pid, &exit_code);
|
||||
}
|
||||
output_summary();
|
||||
io_flush(FULL_FLUSH);
|
||||
exit_cleanup(status);
|
||||
exit_cleanup(exit_code);
|
||||
}
|
||||
|
||||
if (need_messages_from_generator && !read_batch)
|
||||
@@ -807,7 +913,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (flist && flist->count > 0) {
|
||||
local_name = get_local_name(flist, argv[0]);
|
||||
|
||||
status2 = do_recv(f_in, f_out, flist, local_name);
|
||||
exit_code2 = do_recv(f_in, f_out, flist, local_name);
|
||||
} else {
|
||||
handle_stats(-1);
|
||||
output_summary();
|
||||
@@ -817,10 +923,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
|
||||
io_flush(FULL_FLUSH);
|
||||
wait_process(pid, &status);
|
||||
wait_process_with_flush(pid, &exit_code);
|
||||
}
|
||||
|
||||
return MAX(status, status2);
|
||||
return MAX(exit_code, exit_code2);
|
||||
}
|
||||
|
||||
static int copy_argv (char *argv[])
|
||||
@@ -864,12 +970,12 @@ static int start_client(int argc, char *argv[])
|
||||
return rc;
|
||||
|
||||
if (!read_batch) { /* for read_batch, NO source is specified */
|
||||
argc--;
|
||||
shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
|
||||
if (shell_path) { /* source is remote */
|
||||
char *dummy1;
|
||||
int dummy2;
|
||||
if (argc && check_for_hostspec(argv[argc], &dummy1, &dummy2)) {
|
||||
if (--argc
|
||||
&& check_for_hostspec(argv[argc], &dummy1, &dummy2)) {
|
||||
rprintf(FERROR,
|
||||
"The source and destination cannot both be remote.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
@@ -894,12 +1000,14 @@ static int start_client(int argc, char *argv[])
|
||||
} else { /* source is local, check dest arg */
|
||||
am_sender = 1;
|
||||
|
||||
if (argc < 1) { /* destination required */
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
if (argc > 1)
|
||||
p = argv[--argc];
|
||||
else {
|
||||
p = ".";
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
shell_path = check_for_hostspec(argv[argc], &shell_machine, &rsync_port);
|
||||
shell_path = check_for_hostspec(p, &shell_machine, &rsync_port);
|
||||
if (shell_path && filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
@@ -914,7 +1022,7 @@ static int start_client(int argc, char *argv[])
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
shell_machine = NULL;
|
||||
shell_path = argv[argc];
|
||||
shell_path = p;
|
||||
} else if (rsync_port) {
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(shell_machine,
|
||||
@@ -944,10 +1052,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 ? safe_fname(shell_cmd) : "",
|
||||
shell_machine ? safe_fname(shell_machine) : "",
|
||||
shell_user ? safe_fname(shell_user) : "",
|
||||
shell_path ? safe_fname(shell_path) : "");
|
||||
shell_cmd ? shell_cmd : "",
|
||||
shell_machine ? shell_machine : "",
|
||||
shell_user ? shell_user : "",
|
||||
shell_path ? shell_path : "");
|
||||
}
|
||||
|
||||
/* for remote source, only single dest arg can remain ... */
|
||||
@@ -984,7 +1092,7 @@ static int start_client(int argc, char *argv[])
|
||||
|
||||
static RETSIGTYPE sigusr1_handler(UNUSED(int val))
|
||||
{
|
||||
exit_cleanup(RERR_SIGNAL);
|
||||
exit_cleanup(RERR_SIGNAL1);
|
||||
}
|
||||
|
||||
static RETSIGTYPE sigusr2_handler(UNUSED(int val))
|
||||
@@ -997,7 +1105,7 @@ static RETSIGTYPE sigusr2_handler(UNUSED(int val))
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
RETSIGTYPE remember_children(UNUSED(int val))
|
||||
{
|
||||
#ifdef WNOHANG
|
||||
int cnt, status;
|
||||
@@ -1006,8 +1114,7 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
* get him to explain why he put it in, so rather than taking it
|
||||
* out we're instead saving the child exit statuses for later use.
|
||||
* The waitpid() loop presumably eliminates all possibility of leaving
|
||||
* zombie children, maybe that's why he did it.
|
||||
*/
|
||||
* zombie children, maybe that's why he did it. */
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||
/* save the child's exit status */
|
||||
for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
|
||||
@@ -1019,6 +1126,9 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef HAVE_SIGACTION
|
||||
signal(SIGCHLD, remember_children);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1078,16 +1188,23 @@ int main(int argc,char *argv[])
|
||||
int ret;
|
||||
int orig_argc = argc;
|
||||
char **orig_argv = argv;
|
||||
#ifdef HAVE_SIGACTION
|
||||
# ifdef HAVE_SIGPROCMASK
|
||||
sigset_t sigmask;
|
||||
|
||||
signal(SIGUSR1, sigusr1_handler);
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
sigemptyset(&sigmask);
|
||||
# endif
|
||||
sigact.sa_flags = SA_NOCLDSTOP;
|
||||
#endif
|
||||
SIGACTMASK(SIGUSR1, sigusr1_handler);
|
||||
SIGACTMASK(SIGUSR2, sigusr2_handler);
|
||||
SIGACTMASK(SIGCHLD, remember_children);
|
||||
#ifdef MAINTAINER_MODE
|
||||
signal(SIGSEGV, rsync_panic_handler);
|
||||
signal(SIGFPE, rsync_panic_handler);
|
||||
signal(SIGABRT, rsync_panic_handler);
|
||||
signal(SIGBUS, rsync_panic_handler);
|
||||
#endif /* def MAINTAINER_MODE */
|
||||
SIGACTMASK(SIGSEGV, rsync_panic_handler);
|
||||
SIGACTMASK(SIGFPE, rsync_panic_handler);
|
||||
SIGACTMASK(SIGABRT, rsync_panic_handler);
|
||||
SIGACTMASK(SIGBUS, rsync_panic_handler);
|
||||
#endif
|
||||
|
||||
starttime = time(NULL);
|
||||
am_root = (MY_UID() == 0);
|
||||
@@ -1101,7 +1218,11 @@ int main(int argc,char *argv[])
|
||||
|
||||
/* we set a 0 umask so that correct file permissions can be
|
||||
* carried across */
|
||||
orig_umask = (int)umask(0);
|
||||
orig_umask = umask(0);
|
||||
|
||||
#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
|
||||
setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
|
||||
/* FIXME: We ought to call the same error-handling
|
||||
@@ -1110,16 +1231,18 @@ int main(int argc,char *argv[])
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
signal(SIGINT,SIGNAL_CAST sig_int);
|
||||
signal(SIGHUP,SIGNAL_CAST sig_int);
|
||||
signal(SIGTERM,SIGNAL_CAST sig_int);
|
||||
SIGACTMASK(SIGINT, sig_int);
|
||||
SIGACTMASK(SIGHUP, sig_int);
|
||||
SIGACTMASK(SIGTERM, sig_int);
|
||||
#if defined HAVE_SIGACTION && HAVE_SIGPROCMASK
|
||||
sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
|
||||
#endif
|
||||
|
||||
/* Ignore SIGPIPE; we consistently check error codes and will
|
||||
* see the EPIPE. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
|
||||
setlocale(LC_CTYPE, "");
|
||||
SIGACTION(SIGPIPE, SIG_IGN);
|
||||
#ifdef SIGXFSZ
|
||||
SIGACTION(SIGXFSZ, SIG_IGN);
|
||||
#endif
|
||||
|
||||
/* Initialize push_dir here because on some old systems getcwd
|
||||
|
||||
114
match.c
114
match.c
@@ -20,70 +20,47 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int checksum_seed;
|
||||
extern int append_mode;
|
||||
|
||||
int updating_basis_file;
|
||||
|
||||
typedef unsigned short tag;
|
||||
|
||||
#define TABLESIZE (1<<16)
|
||||
#define NULL_TAG (-1)
|
||||
|
||||
static int false_alarms;
|
||||
static int tag_hits;
|
||||
static int hash_hits;
|
||||
static int matches;
|
||||
static int64 data_transfer;
|
||||
|
||||
static int total_false_alarms;
|
||||
static int total_tag_hits;
|
||||
static int total_hash_hits;
|
||||
static int total_matches;
|
||||
|
||||
extern struct stats stats;
|
||||
|
||||
struct target {
|
||||
tag t;
|
||||
int32 i;
|
||||
};
|
||||
#define TABLESIZE (1<<16)
|
||||
|
||||
static struct target *targets;
|
||||
|
||||
static int32 *tag_table;
|
||||
|
||||
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
|
||||
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
|
||||
|
||||
static int compare_targets(struct target *t1,struct target *t2)
|
||||
{
|
||||
return (int)t1->t - (int)t2->t;
|
||||
}
|
||||
static int32 *hash_table;
|
||||
|
||||
#define SUM2HASH2(s1,s2) (((s1) + (s2)) & 0xFFFF)
|
||||
#define SUM2HASH(sum) SUM2HASH2((sum)&0xFFFF,(sum)>>16)
|
||||
|
||||
static void build_hash_table(struct sum_struct *s)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (!tag_table)
|
||||
tag_table = new_array(int32, TABLESIZE);
|
||||
|
||||
targets = new_array(struct target, s->count);
|
||||
if (!tag_table || !targets)
|
||||
out_of_memory("build_hash_table");
|
||||
|
||||
for (i = 0; i < s->count; i++) {
|
||||
targets[i].i = i;
|
||||
targets[i].t = gettag(s->sums[i].sum1);
|
||||
if (!hash_table) {
|
||||
hash_table = new_array(int32, TABLESIZE);
|
||||
if (!hash_table)
|
||||
out_of_memory("build_hash_table");
|
||||
}
|
||||
|
||||
qsort(targets,s->count,sizeof(targets[0]),(int (*)())compare_targets);
|
||||
memset(hash_table, 0xFF, TABLESIZE * sizeof hash_table[0]);
|
||||
|
||||
for (i = 0; i < TABLESIZE; i++)
|
||||
tag_table[i] = NULL_TAG;
|
||||
|
||||
for (i = s->count; i-- > 0; )
|
||||
tag_table[targets[i].t] = i;
|
||||
for (i = 0; i < s->count; i++) {
|
||||
uint32 t = SUM2HASH(s->sums[i].sum1);
|
||||
s->sums[i].chain = hash_table[t];
|
||||
hash_table[t] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +105,6 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
sum_update(map_ptr(buf, last_match + j, n1), n1);
|
||||
}
|
||||
|
||||
|
||||
if (i >= 0)
|
||||
last_match = offset + s->sums[i].len;
|
||||
else
|
||||
@@ -178,20 +154,22 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
}
|
||||
|
||||
do {
|
||||
tag t = gettag2(s1,s2);
|
||||
int done_csum2 = 0;
|
||||
int32 j = tag_table[t];
|
||||
int32 i;
|
||||
|
||||
if (verbose > 4)
|
||||
rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum);
|
||||
if (verbose > 4) {
|
||||
rprintf(FINFO, "offset=%.0f sum=%04x%04x\n",
|
||||
(double)offset, s2 & 0xFFFF, s1 & 0xFFFF);
|
||||
}
|
||||
|
||||
if (j == NULL_TAG)
|
||||
goto null_tag;
|
||||
i = hash_table[SUM2HASH2(s1,s2)];
|
||||
if (i < 0)
|
||||
goto null_hash;
|
||||
|
||||
sum = (s1 & 0xffff) | (s2 << 16);
|
||||
tag_hits++;
|
||||
hash_hits++;
|
||||
do {
|
||||
int32 l, i = targets[j].i;
|
||||
int32 l;
|
||||
|
||||
if (sum != s->sums[i].sum1)
|
||||
continue;
|
||||
@@ -207,9 +185,11 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
|
||||
continue;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
|
||||
(double)offset,(double)j,(double)i,sum);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"potential match at %.0f i=%ld sum=%08x\n",
|
||||
(double)offset, (long)i, sum);
|
||||
}
|
||||
|
||||
if (!done_csum2) {
|
||||
map = (schar *)map_ptr(buf,offset,l);
|
||||
@@ -226,8 +206,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the following want_i optimization. */
|
||||
if (updating_basis_file) {
|
||||
do {
|
||||
int32 i2 = targets[j].i;
|
||||
int32 i2;
|
||||
for (i2 = i; i2 >= 0; i2 = s->sums[i2].chain) {
|
||||
if (s->sums[i2].offset != offset)
|
||||
continue;
|
||||
if (i2 != i) {
|
||||
@@ -242,7 +222,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
* both the sender and the receiver. */
|
||||
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
|
||||
goto set_want_i;
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
}
|
||||
}
|
||||
|
||||
/* we've found a match, but now check to see
|
||||
@@ -268,9 +248,9 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
s2 = sum >> 16;
|
||||
matches++;
|
||||
break;
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
} while ((i = s->sums[i].chain) >= 0);
|
||||
|
||||
null_tag:
|
||||
null_hash:
|
||||
backup = offset - last_match;
|
||||
/* We sometimes read 1 byte prior to last_match... */
|
||||
if (backup < 0)
|
||||
@@ -325,7 +305,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
tag_hits = 0;
|
||||
hash_hits = 0;
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
@@ -334,12 +314,16 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
if (append_mode) {
|
||||
OFF_T j = 0;
|
||||
for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
|
||||
if (buf && do_progress)
|
||||
show_progress(last_match, buf->file_size);
|
||||
sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
|
||||
CHUNK_SIZE);
|
||||
last_match = j;
|
||||
}
|
||||
if (last_match < s->flength) {
|
||||
int32 len = s->flength - last_match;
|
||||
if (buf && do_progress)
|
||||
show_progress(last_match, buf->file_size);
|
||||
sum_update(map_ptr(buf, last_match, len), len);
|
||||
last_match = s->flength;
|
||||
}
|
||||
@@ -373,16 +357,11 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f,file_sum,MD4_SUM_LENGTH);
|
||||
|
||||
if (targets) {
|
||||
free(targets);
|
||||
targets=NULL;
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
|
||||
false_alarms, tag_hits, matches);
|
||||
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
|
||||
false_alarms, hash_hits, matches);
|
||||
|
||||
total_tag_hits += tag_hits;
|
||||
total_hash_hits += hash_hits;
|
||||
total_false_alarms += false_alarms;
|
||||
total_matches += matches;
|
||||
stats.literal_data += data_transfer;
|
||||
@@ -394,8 +373,7 @@ void match_report(void)
|
||||
return;
|
||||
|
||||
rprintf(FINFO,
|
||||
"total: matches=%d tag_hits=%d false_alarms=%d data=%.0f\n",
|
||||
total_matches,total_tag_hits,
|
||||
total_false_alarms,
|
||||
"total: matches=%d hash_hits=%d false_alarms=%d data=%.0f\n",
|
||||
total_matches, total_hash_hits, total_false_alarms,
|
||||
(double)stats.literal_data);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ BEGIN {
|
||||
next;
|
||||
}
|
||||
|
||||
!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^uchar|^short|^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|^RETSIGTYPE/ {
|
||||
next;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Summary: A program for synchronizing files over a network.
|
||||
Name: rsync
|
||||
Version: 2.6.6pre1
|
||||
Version: 2.6.8pre1
|
||||
Release: 1
|
||||
Group: Applications/Internet
|
||||
Source: ftp://rsync.samba.org/pub/rsync/rsync-%{version}.tar.gz
|
||||
|
||||
116
packaging/nightly-rsync
Executable file
116
packaging/nightly-rsync
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
|
||||
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
|
||||
# copy of the /home/ftp/pub/rsync dir on samba.org. It also requires a
|
||||
# pristine CVS checkout of rsync (don't use your normal rsync build dir
|
||||
# unless you're 100% sure that there are not unchecked-in changes).
|
||||
#
|
||||
# If this is run with -ctu, it will make an updated "nightly" tar file in
|
||||
# the nightly dir. It will also remove any old tar files, regenerate the
|
||||
# HTML man pages in the nightly dir, and then rsync the changes to the
|
||||
# samba.org server.
|
||||
|
||||
use Getopt::Long;
|
||||
use Date::Format;
|
||||
|
||||
# Choose any dir where a pristine rsync has been checked out of CVS.
|
||||
our $unpacked = $ENV{HOME} . '/release/nightly';
|
||||
# Where the local copy of /home/ftp/pub/rsync/nightly should be updated.
|
||||
our $nightly = $ENV{HOME} . '/samba-rsync-ftp/nightly';
|
||||
|
||||
our($cvs_update, $make_tar, $upload, $help_opt);
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'cvs-update|c' => \$cvs_update,
|
||||
'make-tar|t' => \$make_tar,
|
||||
'upload|u' => \$upload,
|
||||
'help|h' => \$help_opt,
|
||||
) || $help_opt;
|
||||
|
||||
our $name = time2str('rsync-HEAD-%Y%m%d-%H%M%Z', time, 'GMT');
|
||||
our $ztoday = time2str('%d %b %Y', time);
|
||||
our $today = $ztoday;
|
||||
|
||||
chdir($unpacked) or die $!;
|
||||
|
||||
if ($cvs_update) {
|
||||
print "Updating from cvs...\n";
|
||||
system 'cvs -q up' and die $!;
|
||||
}
|
||||
|
||||
if ($make_tar) {
|
||||
print "Generating list of active CVS files...\n";
|
||||
my($dir, @files);
|
||||
open(CVS, '-|', 'cvs status 2>&1') or die $!;
|
||||
while (<CVS>) {
|
||||
if (/^cvs status: Examining (.*)/) {
|
||||
if ($1 eq '.') {
|
||||
$dir = '';
|
||||
} else {
|
||||
push(@files, $1);
|
||||
$dir = $1 . '/';
|
||||
}
|
||||
} elsif (/^File: (.*?)\s+Status: (.*)/ && $1 ne '.cvsignore') {
|
||||
push(@files, $dir . $1);
|
||||
if ($2 ne 'Up-to-date') {
|
||||
print "*** Not up-to-date: $dir$1\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
close CVS;
|
||||
|
||||
print "Creating $unpacked/$name.tar.gz\n";
|
||||
chdir('..') or die $!;
|
||||
rename($unpacked, $name) or die $!;
|
||||
open(TAR, '|-', "fakeroot tar --files-from=- --no-recursion --mode=g-w -czf $nightly/$name.tar.gz $name") or die $!;
|
||||
foreach (@files) {
|
||||
print TAR "$name/$_\n";
|
||||
}
|
||||
close TAR;
|
||||
rename($name, $unpacked) or die $!;
|
||||
}
|
||||
|
||||
chdir($nightly) or die $!;
|
||||
|
||||
foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) {
|
||||
my $html_fn = $fn;
|
||||
$html_fn =~ s/\.yo/.html/;
|
||||
|
||||
open(IN, '<', "$unpacked/$fn") or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
|
||||
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
|
||||
#s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
|
||||
|
||||
open(OUT, '>', $fn) or die $!;
|
||||
print OUT $_;
|
||||
close OUT;
|
||||
|
||||
system "yodl2html -o $html_fn $fn";
|
||||
|
||||
unlink($fn);
|
||||
}
|
||||
|
||||
system "find . -name 'rsync-HEAD-*' -daystart -mtime +14 | xargs rm -f";
|
||||
system 'ls -ltr';
|
||||
|
||||
if ($upload) {
|
||||
$ENV{RSYNC_PARTIAL_DIR} = ''; # The rsync on samba.org is OLD.
|
||||
system "rsync -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/nightly";
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: nightly-rsync [OPTIONS]
|
||||
|
||||
-c, --cvs-update update $unpacked via CVS.
|
||||
-t, --make-tar create a new tar file in $nightly
|
||||
-u, --upload upload the revised nightly dir to samba.org
|
||||
-h, --help display this help
|
||||
EOT
|
||||
}
|
||||
317
packaging/release-rsync
Executable file
317
packaging/release-rsync
Executable file
@@ -0,0 +1,317 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
|
||||
# This script expects the directory ~/samba-rsync-ftp to exist and to
|
||||
# be a copy of the /home/ftp/pub/rsync dir on samba.org. If it is run
|
||||
# in test mode, it instead expects a dir named ~/tmp/samba-rsync-ftp
|
||||
# (e.g. copy ~/samba-rsync-ftp into ~/tmp and you can do a trial-run of
|
||||
# a release without affecting the files in the ~/samba-rsync-ftp dir).
|
||||
#
|
||||
# Run this as "release-rsync live" to affect ~/samba-rsync-ftp instead
|
||||
# of ~/tmp/samba-rsync-ftp.
|
||||
|
||||
use Date::Format;
|
||||
|
||||
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
|
||||
my $releasedir = $ENV{HOME} . '/release';
|
||||
my $cvsroot = $ENV{CVSROOT} = 'samba.org:/data/cvs';
|
||||
|
||||
my $ztoday = time2str('%d %b %Y', time);
|
||||
my $today = $ztoday;
|
||||
$today =~ s/^0//;
|
||||
|
||||
my $break = <<EOT;
|
||||
==========================================================================
|
||||
EOT
|
||||
my $note = <<EOT;
|
||||
== Note: type "-a u,n" if you want to auto-accept the U,N suggestions. ==
|
||||
EOT
|
||||
|
||||
my $live = shift;
|
||||
my $skipping = '';
|
||||
|
||||
print $break;
|
||||
if ($live) {
|
||||
print <<EOT;
|
||||
== This will release a new version of rsync onto an unsuspecting world. ==
|
||||
EOT
|
||||
} else {
|
||||
print <<EOT;
|
||||
== **** TESTMODE **** (Add "live" arg to avoid this.) ==
|
||||
EOT
|
||||
$dest =~ s#([^/]+$)#tmp/$1#;
|
||||
$skipping = ' ** SKIPPING **';
|
||||
}
|
||||
die "$dest does not exist\n" unless -d $dest;
|
||||
|
||||
print $break, "\nChecking out the latest rsync into $releasedir ...\n";
|
||||
|
||||
mkdir($releasedir, 0755) or die $! unless -d $releasedir;
|
||||
chdir($releasedir) or die $!;
|
||||
|
||||
system 'rm -rf rsync';
|
||||
|
||||
my(%dirs, @files);
|
||||
open(CVS, '-|', 'cvs checkout -P rsync') or die $!;
|
||||
while (<CVS>) {
|
||||
print $_;
|
||||
next if /\.(cvs)?ignore$/;
|
||||
if (m#^[UP] rsync/(.*)#) {
|
||||
my $fn = $1;
|
||||
my($dir) = $fn =~ m#^(.+)/#;
|
||||
push(@files, $dir) if defined($dir) && !$dirs{$1}++;
|
||||
push(@files, $fn);
|
||||
}
|
||||
}
|
||||
|
||||
chdir('rsync') or die $!;
|
||||
|
||||
my($version, $lastversion);
|
||||
open(IN, 'configure.in') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$version = $lastversion = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
|
||||
$lastversion =~ s/(\d+)cvs$/ $1 - 1 /e;
|
||||
$version =~ s/cvs/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
|
||||
|
||||
print $break, "\nPlease enter the version number of this release: [$version] ";
|
||||
chomp($_ = <STDIN>);
|
||||
if ($_ eq '.') {
|
||||
$version =~ s/pre\d+//;
|
||||
} elsif ($_ ne '') {
|
||||
$version = $_;
|
||||
}
|
||||
$version =~ s/[-.]*pre[-.]*/pre/;
|
||||
|
||||
$lastversion =~ s/(\d+)pre\d+$/ $1 - 1 /e unless $version =~ /pre/;
|
||||
|
||||
my $cvstag = "release-$version";
|
||||
$cvstag =~ s/[.]/-/g;
|
||||
$cvstag =~ s/pre/-pre/;
|
||||
|
||||
print "Enter the previous version to produce a patch against: [$lastversion] ";
|
||||
chomp($_ = <STDIN>);
|
||||
$lastversion = $_ if $_ ne '';
|
||||
$lastversion =~ s/[-.]*pre[-.]*/pre/;
|
||||
|
||||
my $release = 1;
|
||||
print "Please enter the RPM release number of this release: [$release] ";
|
||||
chomp($_ = <STDIN>);
|
||||
$release = $_ if $_ ne '';
|
||||
|
||||
my $diffdir;
|
||||
my $skipping2;
|
||||
if ($lastversion =~ /pre/) {
|
||||
if ($version !~ /pre/) {
|
||||
die "You should not diff a release version against a pre-release version.\n";
|
||||
}
|
||||
$diffdir = "$dest/old-previews";
|
||||
$skipping2 = ' ** SKIPPING **';
|
||||
} elsif ($version =~ /pre/) {
|
||||
$diffdir = $dest;
|
||||
$skipping2 = ' ** SKIPPING **';
|
||||
} else {
|
||||
$diffdir = "$dest/old-versions";
|
||||
$skipping2 = '';
|
||||
}
|
||||
|
||||
print "\n", $break, <<EOT;
|
||||
\$version is "$version"
|
||||
\$lastversion is "$lastversion"
|
||||
\$cvstag is "$cvstag"
|
||||
\$dest is "$dest"
|
||||
\$releasedir is "$releasedir"
|
||||
\$diffdir is "$diffdir"
|
||||
\$release is "$release"
|
||||
|
||||
About to:
|
||||
- make sure that configure, config.h.in, and proto.h are updated
|
||||
- tweak the version in configure.in, configure, and the spec files
|
||||
- tweak NEWS and OLDNEWS to update the release date$skipping2
|
||||
- tweak the date in the *.yo files and re-generate the man pages
|
||||
- make sure that the patches dir has been updated
|
||||
- page through the "cvs diff" output
|
||||
|
||||
EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
my $f_opt = /f/ ? ' -f' : '';
|
||||
|
||||
print $break;
|
||||
system "./prepare-source && touch proto.h";
|
||||
|
||||
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'),
|
||||
glob('*.yo'), qw( configure.in configure ) );
|
||||
if ($version !~ /pre/) {
|
||||
push(@tweak_files, qw( NEWS OLDNEWS ));
|
||||
}
|
||||
foreach my $fn (@tweak_files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
if ($fn =~ /configure/) {
|
||||
s/^RSYNC_VERSION.*/RSYNC_VERSION=$version/m;
|
||||
} elsif ($fn =~ /\.spec/) {
|
||||
s/^(Version:) .*/$1 $version/m;
|
||||
s/^(Release:) .*/$1 $release/m;
|
||||
} elsif ($fn =~ /\.yo/) {
|
||||
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
|
||||
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
|
||||
} else {
|
||||
s/^(NEWS for rsync \Q$version\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/m;
|
||||
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$version\E)/\t$ztoday$1/m;
|
||||
}
|
||||
open(OUT, '>', $fn) or die $!;
|
||||
print OUT $_;
|
||||
close OUT;
|
||||
}
|
||||
|
||||
system "yodl2man -o rsync.1 rsync.yo";
|
||||
system "yodl2man -o rsyncd.conf.5 rsyncd.conf.yo";
|
||||
#system "perl -pi -e \"s/\\\\\\'/\\\\&'/g\" rsync.1 rsyncd.conf.5";
|
||||
|
||||
mkdir('patches/tmp') or die $!;
|
||||
system "rsync -a --exclude=patches/ --exclude-from=.cvsignore . patches/tmp/cvsdir/";
|
||||
|
||||
print "\n", $break, $note, $break;
|
||||
system "patches/verify-patches -n -an$f_opt";
|
||||
|
||||
print $break;
|
||||
system "cvs -q diff | egrep -v '^(===============|RCS file: |retrieving revision |Index: )' | less -p '^diff .*'";
|
||||
|
||||
print $break, <<EOT;
|
||||
|
||||
About to:
|
||||
- "cvs commit" all changes$skipping
|
||||
- "cvs tag" this release as $cvstag$skipping
|
||||
- change the diffs in the patches dir to include generated files
|
||||
|
||||
EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
|
||||
if ($live) {
|
||||
system "cvs commit -m 'Preparing for release of $version'";
|
||||
system "cvs tag -F $cvstag .";
|
||||
}
|
||||
|
||||
if (!/skip/i) {
|
||||
print "\n", $break, $note, $break;
|
||||
system "patches/verify-patches -pun -an";
|
||||
}
|
||||
|
||||
my $tar_file = "$dest/rsync-$version.tar.gz";
|
||||
my $diff_file = "$dest/rsync-$lastversion-$version.diffs.gz";
|
||||
|
||||
print $break, <<EOT;
|
||||
|
||||
About to do the following in the samba-rsync-ftp dir:
|
||||
- move the old tar/diff files into the appropriate old-* dirs
|
||||
- hard-link moved tar/diff files to old files on samba.org$skipping
|
||||
- create release tar, "$tar_file"
|
||||
- create release diffs, "$diff_file"
|
||||
- update README, *NEWS, TODO, and cvs.log
|
||||
- update rsync*.html man pages
|
||||
|
||||
EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
|
||||
chdir($releasedir) or die $!;
|
||||
|
||||
print $break;
|
||||
system "rm -rf rsync-$version";
|
||||
rename('rsync', "rsync-$version") or die $!;
|
||||
|
||||
# When creating a pre-release after a normal release, there's nothing to move.
|
||||
if ($diffdir ne $dest) {
|
||||
chdir($dest) or die $!;
|
||||
|
||||
print "Shuffling old files ...\n";
|
||||
|
||||
# We need to run this regardless of $lastversion's "pre"ness.
|
||||
my @moved_files;
|
||||
foreach my $fn (glob('rsync*pre*.tar.gz*'), glob('rsync*pre*-NEWS')) {
|
||||
my $new_fn = "old-previews/$fn";
|
||||
rename($fn, $new_fn) or die $!;
|
||||
push(@moved_files, $new_fn);
|
||||
}
|
||||
|
||||
if ($version !~ /pre/) {
|
||||
foreach my $fn (glob('rsync*.tar.gz*'), glob('rsync*-NEWS')) {
|
||||
next if $fn =~ /^rsync.*pre/;
|
||||
my $new_fn = "old-versions/$fn";
|
||||
rename($fn, $new_fn) or die $!;
|
||||
push(@moved_files, $new_fn);
|
||||
}
|
||||
|
||||
foreach my $fn (glob('rsync*.diffs.gz*')) {
|
||||
next if $fn =~ /^rsync.*pre/;
|
||||
my $new_fn = "old-patches/$fn";
|
||||
rename($fn, $new_fn) or die $!;
|
||||
push(@moved_files, $new_fn);
|
||||
}
|
||||
}
|
||||
|
||||
# Optimize our future upload (in the absence of --detect-renamed) by
|
||||
# copying the above moved files on the remote server.
|
||||
if ($live) {
|
||||
my $remote_cmd = '';
|
||||
foreach (@moved_files) {
|
||||
my($path, $fn) = m#(.*)/([^/]+)$#;
|
||||
$remote_cmd .= "cp -p /home/ftp/pub/rsync/{$fn,$path};";
|
||||
}
|
||||
system "ssh samba.org '$remote_cmd'";
|
||||
}
|
||||
foreach (glob("rsync*pre*.diffs.gz*")) {
|
||||
unlink($_);
|
||||
}
|
||||
|
||||
chdir($releasedir) or die $!;
|
||||
}
|
||||
|
||||
print "Creating $tar_file ...\n";
|
||||
system "fakeroot tar czf $tar_file rsync-$version";
|
||||
open(TAR, '|-', "fakeroot tar --files-from=- --no-recursion --mode=g+w -czf $tar_file rsync-$version") or die $!;
|
||||
foreach (@files) {
|
||||
print TAR "rsync-$version/$_\n";
|
||||
}
|
||||
close TAR;
|
||||
|
||||
print "Creating $diff_file ...\n";
|
||||
system "rm -rf rsync-$version rsync-$lastversion";
|
||||
system "tar xzf $tar_file; tar xzf $diffdir/rsync-$lastversion.tar.gz";
|
||||
## TWEAK THE VERSIONS AS DESIRED HERE ##
|
||||
#mkdir("rsync-$lastversion/support", 0755) or die $!;
|
||||
#rename("rsync-$lastversion/rsyncstats", "rsync-$lastversion/support/rsyncstats");
|
||||
unlink("rsync-$lastversion/.ignore");
|
||||
## END ##
|
||||
system "diff -urN --exclude=patches rsync-$lastversion rsync-$version| gzip -9 >$diff_file";
|
||||
|
||||
print "Updating the other files in $dest ...\n";
|
||||
system "rsync -a rsync-$version/{README,NEWS,OLDNEWS,TODO} $dest";
|
||||
unlink("$dest/rsync-$version-NEWS");
|
||||
link("$dest/NEWS", "$dest/rsync-$version-NEWS");
|
||||
system "rsync -a $cvsroot/CVSROOT/rsync.updates $dest/cvs.log";
|
||||
|
||||
system "yodl2html -o $dest/rsync.html rsync-$version/rsync.yo";
|
||||
system "yodl2html -o $dest/rsyncd.conf.html rsync-$version/rsyncd.conf.yo";
|
||||
|
||||
system "rm -rf rsync-*";
|
||||
|
||||
if ($live) {
|
||||
chdir($dest) or die $!;
|
||||
system "gpg -ba rsync-$version.tar.gz";
|
||||
system "gpg -ba rsync-$lastversion-$version.diffs.gz";
|
||||
}
|
||||
|
||||
print $break, <<EOT;
|
||||
|
||||
All done. Remember to announce the release on *BOTH*
|
||||
rsync-announce\@lists.samba.org and rsync\@lists.samba.org!
|
||||
EOT
|
||||
4
params.c
4
params.c
@@ -491,8 +491,8 @@ static FILE *OpenConfFile( char *FileName )
|
||||
OpenedFile = fopen( FileName, "r" );
|
||||
if( NULL == OpenedFile )
|
||||
{
|
||||
rsyserr(FERROR, errno, "rsync: unable to open configuration file \"%s\"",
|
||||
safe_fname(FileName));
|
||||
rsyserr(FERROR, errno, "unable to open configuration file \"%s\"",
|
||||
FileName);
|
||||
}
|
||||
|
||||
return( OpenedFile );
|
||||
|
||||
21
pipe.c
21
pipe.c
@@ -24,11 +24,12 @@
|
||||
extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int blocking_io;
|
||||
extern int orig_umask;
|
||||
extern int filesfrom_fd;
|
||||
extern mode_t orig_umask;
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
|
||||
/**
|
||||
* Create a child connected to use on stdin/stdout.
|
||||
* Create a child connected to us via its stdin/stdout.
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
@@ -78,8 +79,7 @@ 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",
|
||||
safe_fname(command[0]));
|
||||
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
@@ -111,6 +111,9 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
|
||||
/* The parent process is always the sender for a local rsync. */
|
||||
assert(am_sender);
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 ||
|
||||
fd_pair(from_child_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
@@ -124,11 +127,10 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
am_sender = !am_sender;
|
||||
am_sender = 0;
|
||||
am_server = 1;
|
||||
|
||||
if (!am_sender)
|
||||
filesfrom_fd = -1;
|
||||
filesfrom_fd = -1;
|
||||
chmod_modes = NULL; /* Let the sending side handle this. */
|
||||
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
@@ -144,9 +146,6 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
if (!am_sender)
|
||||
filesfrom_fd = -1;
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 ||
|
||||
close(to_child_pipe[0]) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
|
||||
13
prepare-source
Executable file
13
prepare-source
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# Use autoconf, autoheader, yodl, etc. to ready the generated files
|
||||
# in the release. This is typically used after applying a diff from
|
||||
# "patches" directory in CVS.
|
||||
#
|
||||
# NOTE: if you use a diff from the "patches" directory in a release
|
||||
# tar, this is not needed (but doesn't hurt anything).
|
||||
dir=`dirname $0`
|
||||
if test x"$dir" = x -o x"$dir" = x.; then
|
||||
make -f prepare-source.mak
|
||||
else
|
||||
make -C "$dir" -f prepare-source.mak
|
||||
fi
|
||||
23
prepare-source.mak
Normal file
23
prepare-source.mak
Normal file
@@ -0,0 +1,23 @@
|
||||
gen: configure config.h.in proto.h man
|
||||
|
||||
configure: configure.in aclocal.m4
|
||||
autoconf
|
||||
|
||||
config.h.in: configure.in aclocal.m4
|
||||
autoheader && touch config.h.in
|
||||
|
||||
proto.h: *.c lib/compat.c
|
||||
cat *.c lib/compat.c | awk -f mkproto.awk >proto.h.new
|
||||
if diff proto.h proto.h.new >/dev/null; then \
|
||||
rm proto.h.new; \
|
||||
else \
|
||||
mv proto.h.new proto.h; \
|
||||
fi
|
||||
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 rsync.yo
|
||||
|
||||
rsyncd.conf.5: rsyncd.conf.yo
|
||||
yodl2man -o rsyncd.conf.5 rsyncd.conf.yo
|
||||
@@ -97,15 +97,14 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
remain_h = (int) (remain / 3600.0);
|
||||
|
||||
if (is_last) {
|
||||
snprintf(eol, sizeof eol, " (%d, %.1f%% of %d)\n",
|
||||
snprintf(eol, sizeof eol, " (xfer#%d, to-check=%d/%d)\n",
|
||||
stats.num_transferred_files,
|
||||
(float)((stats.current_file_index+1) * 100)
|
||||
/ stats.num_files,
|
||||
stats.num_files - stats.current_file_index - 1,
|
||||
stats.num_files);
|
||||
} else
|
||||
strcpy(eol, "\r");
|
||||
rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
|
||||
(double) ofs, pct, rate, units,
|
||||
rprintf(FINFO, "%12s %3d%% %7.2f%s %4d:%02d:%02d%s",
|
||||
human_num(ofs), pct, rate, units,
|
||||
remain_h, remain_m, remain_s, eol);
|
||||
}
|
||||
|
||||
|
||||
145
receiver.c
145
receiver.c
@@ -34,18 +34,14 @@ 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 io_error;
|
||||
extern int basis_dir_cnt;
|
||||
extern int make_backups;
|
||||
extern int cleanup_got_literal;
|
||||
extern int remove_sent_files;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int orig_umask;
|
||||
extern int append_mode;
|
||||
extern int sparse_files;
|
||||
extern int keep_partial;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
@@ -58,70 +54,9 @@ extern char *basis_dir[];
|
||||
extern struct file_list *the_file_list;
|
||||
extern struct filter_list_struct server_filter_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 struct bitbag *delayed_bits = NULL;
|
||||
static int phase = 0;
|
||||
|
||||
static void init_delayed_bits(int max_ndx)
|
||||
{
|
||||
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 void set_delayed_bit(int ndx)
|
||||
{
|
||||
int slot = ndx / PER_SLOT_BITS;
|
||||
ndx %= PER_SLOT_BITS;
|
||||
|
||||
if (!delayed_bits[slot]) {
|
||||
if (!(delayed_bits[slot] = (uint32*)calloc(PER_SLOT_INTS, 4)))
|
||||
out_of_memory("set_delayed_bit");
|
||||
}
|
||||
|
||||
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;
|
||||
for ( ; i < PER_SLOT_INTS; i++, mask = 0) {
|
||||
if (!(bits = delayed_bits[slot][i] & ~mask))
|
||||
continue;
|
||||
/* 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... */
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_tmpname() - create a tmp filename for a given filename
|
||||
@@ -172,8 +107,7 @@ 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",
|
||||
safe_fname(fname));
|
||||
rprintf(FERROR, "temporary filename too long: %s\n", fname);
|
||||
fnametmp[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
@@ -206,7 +140,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
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);
|
||||
fname_r, (double)size_r);
|
||||
}
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
@@ -219,12 +153,16 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
if (sum.remainder)
|
||||
sum.flength -= sum.blength - sum.remainder;
|
||||
for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) {
|
||||
if (do_progress)
|
||||
show_progress(offset, total_size);
|
||||
sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE),
|
||||
CHUNK_SIZE);
|
||||
offset = j;
|
||||
}
|
||||
if (offset < sum.flength) {
|
||||
int32 len = sum.flength - offset;
|
||||
if (do_progress)
|
||||
show_progress(offset, total_size);
|
||||
sum_update(map_ptr(mapbuf, offset, len), len);
|
||||
offset = sum.flength;
|
||||
}
|
||||
@@ -338,22 +276,22 @@ 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; ) {
|
||||
for (i = -1; (i = bitbag_next_bit(delayed_bits, i)) >= 0; ) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
fname = local_name ? local_name : f_name(file);
|
||||
fname = local_name ? local_name : f_name(file, NULL);
|
||||
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));
|
||||
partialptr, fname);
|
||||
}
|
||||
/* We don't use robust_rename() here because the
|
||||
* partial-dir must be on the same drive. */
|
||||
if (do_rename(partialptr, fname) < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"rename failed for %s (from %s)",
|
||||
full_fname(fname),
|
||||
safe_fname(partialptr));
|
||||
full_fname(fname), partialptr);
|
||||
} else {
|
||||
if (remove_sent_files
|
||||
|| (preserve_hard_links
|
||||
@@ -361,8 +299,7 @@ static void handle_delayed_updates(struct file_list *flist, char *local_name)
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_SUCCESS,numbuf,4);
|
||||
}
|
||||
handle_partial_dir(partialptr,
|
||||
PDIR_DELETE);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,7 +312,7 @@ static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i)
|
||||
rprintf(FINFO,
|
||||
"(No batched update for%s \"%s\")\n",
|
||||
phase ? " resend of" : "",
|
||||
safe_fname(f_name(the_file_list->files[next_gen_i])));
|
||||
f_name(the_file_list->files[next_gen_i], NULL));
|
||||
}
|
||||
next_gen_i = read_int(batch_gen_fd);
|
||||
if (next_gen_i == -1)
|
||||
@@ -418,7 +355,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
}
|
||||
|
||||
if (delay_updates)
|
||||
init_delayed_bits(flist->count);
|
||||
delayed_bits = bitbag_create(flist->count);
|
||||
|
||||
while (1) {
|
||||
cleanup_disable();
|
||||
@@ -440,7 +377,10 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = 0; /* prevents double backup */
|
||||
append_mode = 0;
|
||||
if (append_mode) {
|
||||
append_mode = 0;
|
||||
sparse_files = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -450,10 +390,10 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
continue;
|
||||
|
||||
file = flist->files[i];
|
||||
fname = local_name ? local_name : f_name_to(file, fbuf);
|
||||
fname = local_name ? local_name : f_name(file, fbuf);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
|
||||
rprintf(FINFO, "recv_files(%s)\n", fname);
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
@@ -494,8 +434,9 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
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));
|
||||
rprintf(FINFO,
|
||||
"(Skipping batched update for \"%s\")\n",
|
||||
fname);
|
||||
discard_receive_data(f_in, file->length);
|
||||
continue;
|
||||
}
|
||||
@@ -596,16 +537,16 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !preserve_perms) {
|
||||
/* if the file exists already and we aren't preserving
|
||||
* permissions then act as though the remote end sent
|
||||
* us the file permissions we already have */
|
||||
file->mode = st.st_mode;
|
||||
/* If we're not preserving permissions, change the file-list's
|
||||
* mode based on the local permissions and some heuristics. */
|
||||
if (!preserve_perms) {
|
||||
int exists = fd1 != -1;
|
||||
file->mode = dest_mode(file->mode, st.st_mode, exists);
|
||||
}
|
||||
|
||||
/* We now check to see if we are writing file "inplace" */
|
||||
if (inplace) {
|
||||
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0);
|
||||
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "open %s failed",
|
||||
full_fname(fname));
|
||||
@@ -634,7 +575,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT
|
||||
&& create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
&& create_directory_path(fnametmp) == 0) {
|
||||
/* Get back to name with XXXXXX in it. */
|
||||
get_tmpname(fnametmp, fname);
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
@@ -648,7 +589,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (partialptr)
|
||||
if (keep_partial)
|
||||
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
|
||||
}
|
||||
|
||||
@@ -656,7 +597,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
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));
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
@@ -674,17 +615,20 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
}
|
||||
|
||||
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
|
||||
finish_transfer(fname, fnametmp, file, recv_ok, 1);
|
||||
if (partialptr != fname && fnamecmp == partialptr) {
|
||||
if (partialptr == fname || *partial_dir == '/')
|
||||
partialptr = NULL;
|
||||
finish_transfer(fname, fnametmp, partialptr,
|
||||
file, recv_ok, 1);
|
||||
if (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);
|
||||
finish_transfer(partialptr, fnametmp, NULL,
|
||||
file, recv_ok, !partial_dir);
|
||||
if (delay_updates && recv_ok) {
|
||||
set_delayed_bit(i);
|
||||
bitbag_set_bit(delayed_bits, i);
|
||||
recv_ok = -1;
|
||||
}
|
||||
} else {
|
||||
@@ -719,8 +663,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
}
|
||||
rprintf(msgtype,
|
||||
"%s: %s failed verification -- update %s%s.\n",
|
||||
errstr, safe_fname(fname),
|
||||
keptstr, redostr);
|
||||
errstr, fname, keptstr, redostr);
|
||||
}
|
||||
if (!phase) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
|
||||
151
rsync.c
151
rsync.c
@@ -21,10 +21,20 @@
|
||||
process */
|
||||
|
||||
#include "rsync.h"
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
#include <libcharset.h>
|
||||
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int daemon_log_format_has_i;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_executability;
|
||||
extern int preserve_times;
|
||||
extern int omit_dir_times;
|
||||
extern int am_root;
|
||||
@@ -32,13 +42,53 @@ extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int am_starting_up;
|
||||
extern int allow_8bit_chars;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int inplace;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
extern struct chmod_mode_struct *daemon_chmod_modes;
|
||||
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
iconv_t ic_chck = (iconv_t)-1;
|
||||
|
||||
static const char *default_charset(void)
|
||||
{
|
||||
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
return locale_charset();
|
||||
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
return nl_langinfo(CODESET);
|
||||
#else
|
||||
return ""; /* Works with (at the very least) gnu iconv... */
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup_iconv()
|
||||
{
|
||||
if (!am_server && !allow_8bit_chars) {
|
||||
const char *defset = default_charset();
|
||||
|
||||
/* It's OK if this fails... */
|
||||
ic_chck = iconv_open(defset, defset);
|
||||
|
||||
if (verbose > 3) {
|
||||
if (ic_chck == (iconv_t)-1) {
|
||||
rprintf(FINFO,
|
||||
"note: iconv_open(\"%s\", \"%s\") failed (%d)"
|
||||
" -- using isprint() instead of iconv().\n",
|
||||
defset, defset, errno);
|
||||
} else {
|
||||
rprintf(FINFO,
|
||||
"note: iconv_open(\"%s\", \"%s\") succeeded.\n",
|
||||
defset, defset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
free a sums struct
|
||||
@@ -49,9 +99,31 @@ void free_sums(struct sum_struct *s)
|
||||
free(s);
|
||||
}
|
||||
|
||||
/* This is only called when we aren't preserving permissions. Figure out what
|
||||
* the permissions should be and return them merged back into the mode. */
|
||||
mode_t dest_mode(mode_t flist_mode, mode_t cur_mode, int exists)
|
||||
{
|
||||
/* If the file already exists, we'll return the local permissions,
|
||||
* possibly tweaked by the --executability option. */
|
||||
if (exists) {
|
||||
if (preserve_executability && S_ISREG(flist_mode)) {
|
||||
/* If the source file is executable, grant execute
|
||||
* rights to everyone who can read, but ONLY if the
|
||||
* file isn't already executable. */
|
||||
if (!(flist_mode & 0111))
|
||||
cur_mode &= ~0111;
|
||||
else if (!(cur_mode & 0111))
|
||||
cur_mode |= (cur_mode & 0444) >> 2;
|
||||
}
|
||||
} else
|
||||
cur_mode = flist_mode & ACCESSPERMS & ~orig_umask;
|
||||
if (daemon_chmod_modes && !S_ISLNK(flist_mode))
|
||||
cur_mode = tweak_mode(cur_mode, daemon_chmod_modes);
|
||||
return (flist_mode & ~CHMOD_BITS) | (cur_mode & CHMOD_BITS);
|
||||
}
|
||||
|
||||
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
int flags)
|
||||
int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
|
||||
int flags)
|
||||
{
|
||||
int updated = 0;
|
||||
STRUCT_STAT st2;
|
||||
@@ -66,12 +138,18 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
return 0;
|
||||
}
|
||||
st = &st2;
|
||||
if (!preserve_perms && S_ISDIR(file->mode)
|
||||
&& st->st_mode & S_ISGID) {
|
||||
/* We just created this directory and its setgid
|
||||
* bit is on, so make sure it stays on. */
|
||||
file->mode |= S_ISGID;
|
||||
}
|
||||
}
|
||||
|
||||
if (!preserve_times || (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) {
|
||||
flags |= ATTRS_SKIP_MTIME;
|
||||
if (!(flags & ATTRS_SKIP_MTIME)
|
||||
&& cmp_time(st->st_mtime, file->modtime) != 0) {
|
||||
int ret = set_modtime(fname, file->modtime, st->st_mode);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR, errno, "failed to set times on %s",
|
||||
@@ -95,13 +173,13 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
if (change_uid) {
|
||||
rprintf(FINFO,
|
||||
"set uid of %s from %ld to %ld\n",
|
||||
safe_fname(fname),
|
||||
fname,
|
||||
(long)st->st_uid, (long)file->uid);
|
||||
}
|
||||
if (change_gid) {
|
||||
rprintf(FINFO,
|
||||
"set gid of %s from %ld to %ld\n",
|
||||
safe_fname(fname),
|
||||
fname,
|
||||
(long)st->st_gid, (long)file->gid);
|
||||
}
|
||||
}
|
||||
@@ -139,19 +217,18 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (verbose > 1 && flags & PERMS_REPORT) {
|
||||
if (verbose > 1 && flags & ATTRS_REPORT) {
|
||||
enum logcode code = daemon_log_format_has_i || dry_run
|
||||
? FCLIENT : FINFO;
|
||||
if (updated)
|
||||
rprintf(code, "%s\n", safe_fname(fname));
|
||||
rprintf(code, "%s\n", fname);
|
||||
else
|
||||
rprintf(code, "%s is uptodate\n", safe_fname(fname));
|
||||
rprintf(code, "%s is uptodate\n", fname);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
|
||||
void sig_int(void)
|
||||
RETSIGTYPE sig_int(UNUSED(int val))
|
||||
{
|
||||
/* KLUGE: if the user hits Ctrl-C while ssh is prompting
|
||||
* for a password, then our cleanup's sending of a SIGUSR1
|
||||
@@ -165,36 +242,39 @@ void sig_int(void)
|
||||
exit_cleanup(RERR_SIGNAL);
|
||||
}
|
||||
|
||||
|
||||
/* 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 overwriting_basis)
|
||||
/* Finish off a file transfer: renaming the file and setting the file's
|
||||
* attributes (e.g. permissions, ownership, etc.). If partialptr is not
|
||||
* NULL and the robust_rename() call is forced to copy the temp file, we
|
||||
* stage the file into the partial-dir and then rename it into place. */
|
||||
void finish_transfer(char *fname, char *fnametmp, char *partialptr,
|
||||
struct file_struct *file, int ok_to_set_time,
|
||||
int overwriting_basis)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inplace) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "finishing %s\n", safe_fname(fname));
|
||||
goto do_set_perms;
|
||||
rprintf(FINFO, "finishing %s\n", fname);
|
||||
fnametmp = fname;
|
||||
goto do_set_file_attrs;
|
||||
}
|
||||
|
||||
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);
|
||||
set_file_attrs(fnametmp, file, NULL,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
|
||||
/* move tmp file over real file */
|
||||
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 (verbose > 2)
|
||||
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
|
||||
ret = robust_rename(fnametmp, fname, partialptr,
|
||||
file->mode & INITACCESSPERMS);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR, errno, "%s %s -> \"%s\"",
|
||||
ret == -2 ? "copy" : "rename",
|
||||
full_fname(fnametmp), safe_fname(fname));
|
||||
ret == -2 ? "copy" : "rename",
|
||||
full_fname(fnametmp), fname);
|
||||
do_unlink(fnametmp);
|
||||
return;
|
||||
}
|
||||
@@ -202,8 +282,21 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
|
||||
/* The file was moved into place (not copied), so it's done. */
|
||||
return;
|
||||
}
|
||||
do_set_perms:
|
||||
set_perms(fname, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
|
||||
/* The file was copied, so tweak the perms of the copied file. If it
|
||||
* was copied to partialptr, move it into its final destination. */
|
||||
fnametmp = partialptr ? partialptr : fname;
|
||||
|
||||
do_set_file_attrs:
|
||||
set_file_attrs(fnametmp, file, NULL,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
|
||||
if (partialptr) {
|
||||
if (do_rename(fnametmp, fname) < 0) {
|
||||
rsyserr(FERROR, errno, "rename %s -> \"%s\"",
|
||||
full_fname(fnametmp), fname);
|
||||
} else
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
|
||||
88
rsync.h
88
rsync.h
@@ -58,12 +58,12 @@
|
||||
/* These flags are used in the live flist data. */
|
||||
|
||||
#define FLAG_TOP_DIR (1<<0)
|
||||
#define FLAG_SENT (1<<1) /* sender */
|
||||
#define FLAG_HLINK_EOL (1<<1) /* receiver/generator */
|
||||
#define FLAG_MOUNT_POINT (1<<2) /* sender */
|
||||
#define FLAG_NO_FUZZY (1<<2) /* generator */
|
||||
#define FLAG_MOUNT_POINT (1<<2) /* sender/generator */
|
||||
#define FLAG_DEL_HERE (1<<3) /* receiver/generator */
|
||||
#define FLAG_SENT (1<<3) /* sender */
|
||||
#define FLAG_HLINK_TOL (1<<4) /* receiver/generator */
|
||||
#define FLAG_NO_FUZZY (1<<5) /* generator */
|
||||
|
||||
/* update this if you make incompatible changes */
|
||||
#define PROTOCOL_VERSION 29
|
||||
@@ -115,9 +115,10 @@
|
||||
#define XFLG_FATAL_ERRORS (1<<0)
|
||||
#define XFLG_OLD_PREFIXES (1<<1)
|
||||
#define XFLG_ANCHORED2ABS (1<<2)
|
||||
#define XFLG_ABS_IF_SLASH (1<<3)
|
||||
|
||||
#define PERMS_REPORT (1<<0)
|
||||
#define PERMS_SKIP_MTIME (1<<1)
|
||||
#define ATTRS_REPORT (1<<0)
|
||||
#define ATTRS_SKIP_MTIME (1<<1)
|
||||
|
||||
#define FULL_FLUSH 1
|
||||
#define NORMAL_FLUSH 0
|
||||
@@ -133,26 +134,22 @@
|
||||
#define FNAMECMP_BACKUP 0x82
|
||||
#define FNAMECMP_FUZZY 0x83
|
||||
|
||||
/* 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_ATIME (1<<0)
|
||||
#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_REPORT_ACL (1<<7)
|
||||
#define ITEM_REPORT_XATTR (1<<8)
|
||||
#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() */
|
||||
|
||||
@@ -160,16 +157,17 @@
|
||||
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 };
|
||||
/* Log-message categories. Only FERROR and FINFO get sent over the socket.
|
||||
* FLOG and FCLIENT are only used on the daemon side for custom logging,
|
||||
* while FNAME is only used on the client side. */
|
||||
enum logcode { FERROR=1, FINFO=2, FLOG=3, FCLIENT=4, FNAME=5, FSOCKERR=6 };
|
||||
|
||||
/* Messages types that are sent over the message channel. The logcode
|
||||
* values must all be present here with identical numbers. */
|
||||
enum msgcode {
|
||||
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_LOG=FLOG, MSG_SOCKERR=FSOCKERR, /* 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 */
|
||||
@@ -319,6 +317,10 @@ enum msgcode {
|
||||
#include <compat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "lib/pool_alloc.h"
|
||||
@@ -463,6 +465,14 @@ struct idev {
|
||||
#define MAXPATHLEN 1024
|
||||
#endif
|
||||
|
||||
/* We want a roomy line buffer that can hold more than MAXPATHLEN,
|
||||
* and significantly more than an overly short MAXPATHLEN. */
|
||||
#if MAXPATHLEN < 4096
|
||||
#define BIGPATHBUFLEN (4096+1024)
|
||||
#else
|
||||
#define BIGPATHBUFLEN (MAXPATHLEN+1024)
|
||||
#endif
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 255
|
||||
#endif
|
||||
@@ -552,6 +562,7 @@ struct sum_buf {
|
||||
OFF_T offset; /**< offset in file of this chunk */
|
||||
int32 len; /**< length of chunk of file */
|
||||
uint32 sum1; /**< simple checksum */
|
||||
int32 chain; /**< next hash-table collision */
|
||||
short flags; /**< flag bits */
|
||||
char sum2[SUM_LENGTH]; /**< checksum */
|
||||
};
|
||||
@@ -579,11 +590,11 @@ struct map_struct {
|
||||
|
||||
#define MATCHFLG_WILD (1<<0) /* pattern has '*', '[', and/or '?' */
|
||||
#define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */
|
||||
#define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with '**' */
|
||||
#define MATCHFLG_ABS_PATH (1<<3) /* path-match on absolute path */
|
||||
#define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
|
||||
#define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */
|
||||
#define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */
|
||||
#define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with "**" */
|
||||
#define MATCHFLG_WILD3_SUFFIX (1<<3) /* pattern ends with "***" */
|
||||
#define MATCHFLG_ABS_PATH (1<<4) /* path-match on absolute path */
|
||||
#define MATCHFLG_INCLUDE (1<<5) /* this is an include, not an exclude */
|
||||
#define MATCHFLG_DIRECTORY (1<<6) /* this matches only directories */
|
||||
#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 */
|
||||
@@ -595,6 +606,7 @@ struct map_struct {
|
||||
#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 MATCHFLG_CLEAR_LIST (1<<18)/* this item is the "!" token */
|
||||
|
||||
#define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \
|
||||
| MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \
|
||||
@@ -631,6 +643,7 @@ struct stats {
|
||||
int current_file_index;
|
||||
};
|
||||
|
||||
struct chmod_mode_struct;
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "lib/mdfour.h"
|
||||
@@ -638,6 +651,15 @@ struct stats {
|
||||
#include "lib/permstring.h"
|
||||
#include "lib/addrinfo.h"
|
||||
|
||||
#if !defined __GNUC__ || defined __APPLE__
|
||||
/* Apparently the OS X port of gcc gags on __attribute__.
|
||||
*
|
||||
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
/* We have replacement versions of these if they're missing. */
|
||||
@@ -681,7 +703,12 @@ extern int errno;
|
||||
#define SUPPORT_HARD_LINKS 1
|
||||
#endif
|
||||
|
||||
#define SIGNAL_CAST (RETSIGTYPE (*)())
|
||||
#ifdef HAVE_SIGACTION
|
||||
#define SIGACTION(n,h) sigact.sa_handler=(h), sigaction((n),&sigact,NULL)
|
||||
#define signal(n,h) we_need_to_call_SIGACTION_not_signal(n,h)
|
||||
#else
|
||||
#define SIGACTION(n,h) signal(n,h)
|
||||
#endif
|
||||
|
||||
#ifndef EWOULDBLOCK
|
||||
#define EWOULDBLOCK EAGAIN
|
||||
@@ -778,7 +805,8 @@ extern int errno;
|
||||
#define INADDR_NONE 0xffffffff
|
||||
#endif
|
||||
|
||||
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
|
||||
#define IS_SPECIAL(mode) (S_ISSOCK(mode) || S_ISFIFO(mode))
|
||||
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode))
|
||||
|
||||
/* Initial mask on permissions given to temporary files. Mask off setuid
|
||||
bits and group access because of potential race-condition security
|
||||
@@ -786,15 +814,7 @@ extern int errno;
|
||||
#define INITACCESSPERMS 0700
|
||||
|
||||
/* handler for null strings in printf format */
|
||||
#define NS(s) ((s)?safe_fname(s):"<NULL>")
|
||||
|
||||
#if !defined __GNUC__ || defined __APPLE__
|
||||
/* Apparently the OS X port of gcc gags on __attribute__.
|
||||
*
|
||||
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
|
||||
#define __attribute__(x)
|
||||
|
||||
#endif
|
||||
#define NS(s) ((s)?(s):"<NULL>")
|
||||
|
||||
/* Convenient wrappers for malloc and realloc. Use them. */
|
||||
#define new(type) ((type *)malloc(sizeof(type)))
|
||||
@@ -860,7 +880,3 @@ int inet_pton(int af, const char *src, void *dst);
|
||||
#ifdef MAINTAINER_MODE
|
||||
const char *get_panic_action(void);
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
|
||||
extern const char *io_write_phase, *io_read_phase;
|
||||
|
||||
105
rsyncd.conf.yo
105
rsyncd.conf.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(7 Jul 2005)()()
|
||||
manpage(rsyncd.conf)(5)(12 Apr 2006)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -86,7 +86,7 @@ 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
|
||||
useful on systems (such as AIX) where code(syslog()) doesn't work for
|
||||
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
|
||||
@@ -114,9 +114,10 @@ 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
|
||||
slower!). Read the man page for the setsockopt() system call for
|
||||
slower!). Read the man page for the code(setsockopt()) system call for
|
||||
details on some of the options you may be able to set. By default no
|
||||
special socket options are set.
|
||||
special socket options are set. These settings are superseded by the
|
||||
bf(--sockopts) command-line option.
|
||||
|
||||
enddit()
|
||||
|
||||
@@ -153,7 +154,7 @@ The default for "use chroot" is true.
|
||||
|
||||
In order to preserve usernames and groupnames, rsync needs to be able to
|
||||
use the standard library functions for looking up names and IDs (i.e.
|
||||
getpwuid(), getgrgid(), getpwname(), and getgrnam()). This means a
|
||||
code(getpwuid()), code(getgrgid()), code(getpwname()), and code(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
|
||||
@@ -163,7 +164,7 @@ 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
|
||||
being downloaded/uploaded by adding an exclude rule to the rsyncd.conf file
|
||||
(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
|
||||
@@ -262,6 +263,25 @@ only superficially equivalent to the client specifying the
|
||||
bf(--include-from) option with a equivalent file.
|
||||
See the "exclude" option above.
|
||||
|
||||
dit(bf(incoming chmod)) This option allows you to specify a set of
|
||||
comma-separated chmod strings that will affect the permissions of all
|
||||
incoming files (files that are being received by the daemon). These
|
||||
changes happen after all other permission calculations, and this will
|
||||
even override destination-default and/or existing permissions when the
|
||||
client does not specify bf(--perms).
|
||||
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
|
||||
manpage for information on the format of this string.
|
||||
|
||||
dit(bf(outgoing chmod)) This option allows you to specify a set of
|
||||
comma-separated chmod strings that will affect the permissions of all
|
||||
outgoing files (files that are being sent out from the daemon). These
|
||||
changes happen first, making the sent permissions appear to be different
|
||||
than those stored in the filesystem itself. For instance, you could
|
||||
disable group write permissions on the server while having it appear to
|
||||
be on to the clients.
|
||||
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
|
||||
manpage for information on the format of this string.
|
||||
|
||||
dit(bf(auth users)) The "auth users" option specifies a comma and
|
||||
space-separated list of usernames that will be allowed to connect to
|
||||
this module. The usernames do not need to exist on the local
|
||||
@@ -269,12 +289,12 @@ system. The usernames may also contain shell wildcard characters. If
|
||||
"auth users" is set then the client will be challenged to supply a
|
||||
username and password to connect to the module. A challenge response
|
||||
authentication protocol is used for this exchange. The plain text
|
||||
usernames are passwords are stored in the file specified by the
|
||||
usernames and 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 "CONNECTING TO AN RSYNC DAEMON OVER A REMOTE SHELL
|
||||
PROGRAM" section in rsync(1) for information on how handle an
|
||||
PROGRAM" section in bf(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 daemon.
|
||||
|
||||
@@ -386,24 +406,25 @@ rsyncstats.)
|
||||
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 "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
|
||||
it() %u for the authenticated username (or the null string)
|
||||
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() %a the remote IP address
|
||||
it() %b the number of bytes actually transferred
|
||||
it() %B the permission bits of the file (e.g. rwxrwxrwt)
|
||||
it() %c the checksum bytes received for this file (only when sending)
|
||||
it() %f the filename (long form on sender; no trailing "/")
|
||||
it() %G the gid of the file (decimal) or "DEFAULT"
|
||||
it() %h the remote host name
|
||||
it() %i an itemized list of what is being updated
|
||||
it() %l the length of the file in bytes
|
||||
it() %L the string " -> SYMLINK", " => HARDLINK", or "" (where bf(SYMLINK) or bf(HARDLINK) is a filename)
|
||||
it() %m the module name
|
||||
it() %M the last-modified time of the file
|
||||
it() %n the filename (short form; trailing "/" on dir)
|
||||
it() %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period)
|
||||
it() %p the process ID of this rsync session
|
||||
it() %P the module path
|
||||
it() %t the current date time
|
||||
it() %u the authenticated username or an empty string
|
||||
it() %U the uid of the file (decimal)
|
||||
))
|
||||
|
||||
For a list of what the characters mean that are output by "%i", see the
|
||||
@@ -458,7 +479,8 @@ dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run
|
||||
before and/or after the transfer. If the bf(pre-xfer exec) command fails, the
|
||||
transfer is aborted before it begins.
|
||||
|
||||
The following environment variables are set for both commands:
|
||||
The following environment variables will be set, though some are
|
||||
specific to the pre-xfer or the post-xfer environment:
|
||||
|
||||
quote(itemize(
|
||||
it() bf(RSYNC_MODULE_NAME): The name of the module being accessed.
|
||||
@@ -466,33 +488,32 @@ quote(itemize(
|
||||
it() bf(RSYNC_HOST_ADDR): The accessing host's IP address.
|
||||
it() bf(RSYNC_HOST_NAME): The accessing host's name.
|
||||
it() bf(RSYNC_USER_NAME): The accessing user's name (empty if no user).
|
||||
))
|
||||
|
||||
These environment variables will also be set for the bf(post-xfer exec)
|
||||
command:
|
||||
|
||||
quote(itemize(
|
||||
it() bf(RSYNC_EXIT_STATUS): rsync's exit value. This will be 0 for a
|
||||
it() bf(RSYNC_REQUEST): (pre-xfer only) The module/path info specified
|
||||
by the user (note that the user can specify multiple source files,
|
||||
so the request can be something like "mod/path1 mod/path2", etc.).
|
||||
it() bf(RSYNC_ARG#): (pre-xfer only) The pre-request arguments are set
|
||||
in these numbered values. RSYNC_ARG0 is always "rsyncd", and the last
|
||||
value contains a single period.
|
||||
it() bf(RSYNC_EXIT_STATUS): (post-xfer only) rsync's exit value. This will be 0 for a
|
||||
successful run, a positive value for an error that rsync returned
|
||||
(e.g. 23=partial xfer), or a -1 if rsync failed to exit properly.
|
||||
it() bf(RSYNC_RAW_STATUS): the raw exit value from waitpid().
|
||||
it() bf(RSYNC_RAW_STATUS): (post-xfer only) the raw exit value from code(waitpid()).
|
||||
))
|
||||
|
||||
Even though the commands can be associated with a particular module, they
|
||||
are run using the permissions of the user that started the daemon (not the
|
||||
module's uid/gid setting) without any chroot restrictions (even if the
|
||||
module will/has run chroot()ed).
|
||||
module's uid/gid setting) without any chroot restrictions.
|
||||
|
||||
enddit()
|
||||
|
||||
manpagesection(AUTHENTICATION STRENGTH)
|
||||
|
||||
The authentication protocol used in rsync is a 128 bit MD4 based
|
||||
challenge response system. Although I believe that no one has ever
|
||||
demonstrated a brute-force break of this sort of system you should
|
||||
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.
|
||||
challenge response system. This is fairly weak protection, though (with
|
||||
at least one brute-force hash-finding algorithm publicly available), so
|
||||
if you want really top-quality security, then I recommend that you run
|
||||
rsync over ssh. (Yes, a future version of rsync will switch over to a
|
||||
stronger hashing method.)
|
||||
|
||||
Also note that the rsync daemon protocol does not currently provide any
|
||||
encryption of the data that is transferred over the connection. Only
|
||||
@@ -570,7 +591,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 2.6.6pre1 of rsync.
|
||||
This man page is current for version 2.6.8pre1 of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
|
||||
18
runtests.sh
18
runtests.sh
@@ -85,7 +85,7 @@
|
||||
# they're explicitly given on the command line.
|
||||
|
||||
# Also, we can't count on 'cp -a' or 'mkdir -p', although they're
|
||||
# pretty handy.
|
||||
# pretty handy (see function makepath for the latter).
|
||||
|
||||
# I think some of the GNU documentation suggests that we shouldn't
|
||||
# rely on shell functions. However, the Bash manual seems to say that
|
||||
@@ -100,6 +100,8 @@
|
||||
# You cannot do "export VAR=VALUE" all on one line; the export must be
|
||||
# separate from the assignment. (SCO SysV)
|
||||
|
||||
# Don't rely on grep -q, as that doesn't work everywhere -- just redirect
|
||||
# stdout to /dev/null to keep it quiet.
|
||||
|
||||
|
||||
# STILL TO DO:
|
||||
@@ -124,6 +126,7 @@ set -e
|
||||
. "./shconfig"
|
||||
|
||||
RUNSHFLAGS='-e'
|
||||
export RUNSHFLAGS
|
||||
|
||||
# for Solaris
|
||||
[ -d /usr/xpg4/bin ] && PATH="/usr/xpg4/bin/:$PATH"
|
||||
@@ -160,6 +163,14 @@ else
|
||||
echo " preserve_scratch=no"
|
||||
fi
|
||||
|
||||
# Check if setfacl is around and if it supports the -k or -s option.
|
||||
if setfacl --help 2>/dev/null | grep ' -k,' >/dev/null; then
|
||||
setfacl_nodef='setfacl -k'
|
||||
elif setfacl -s u::7,g::5,o:5 testsuite 2>/dev/null; then
|
||||
setfacl_nodef='setfacl -s u::7,g::5,o:5'
|
||||
else
|
||||
setfacl_nodef=true
|
||||
fi
|
||||
|
||||
if [ ! -f "$rsync_bin" ]; then
|
||||
echo "rsync_bin $rsync_bin is not a file" >&2
|
||||
@@ -174,7 +185,7 @@ fi
|
||||
RSYNC="$rsync_bin"
|
||||
#RSYNC="valgrind --tool=addrcheck $rsync_bin"
|
||||
|
||||
export rsync_bin RSYNC
|
||||
export rsync_bin RSYNC setfacl_nodef
|
||||
|
||||
skipped=0
|
||||
missing=0
|
||||
@@ -194,6 +205,9 @@ export scratchdir suitedir
|
||||
prep_scratch() {
|
||||
[ -d "$scratchdir" ] && rm -rf "$scratchdir"
|
||||
mkdir "$scratchdir"
|
||||
# Get rid of default ACLs and dir-setgid to avoid confusing some tests.
|
||||
$setfacl_nodef "$scratchdir"
|
||||
chmod g-s "$scratchdir"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
26
sender.c
26
sender.c
@@ -133,11 +133,9 @@ void successful_send(int ndx)
|
||||
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));
|
||||
}
|
||||
f_name(file, fname + offset);
|
||||
if (remove_sent_files && do_unlink(fname) == 0 && verbose > 1)
|
||||
rprintf(FINFO, "sender removed %s\n", fname + offset);
|
||||
}
|
||||
|
||||
static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
|
||||
@@ -256,7 +254,7 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
fname[offset++] = '/';
|
||||
} else
|
||||
offset = 0;
|
||||
fname2 = f_name_to(file, fname + offset);
|
||||
fname2 = f_name(file, fname + offset);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
|
||||
@@ -331,22 +329,20 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
|
||||
safe_fname(fname), (double)st.st_size);
|
||||
fname, (double)st.st_size);
|
||||
}
|
||||
|
||||
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 (verbose > 2)
|
||||
rprintf(FINFO, "calling match_sums %s\n", fname);
|
||||
|
||||
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));
|
||||
rprintf(FINFO, "%s\n", fname2);
|
||||
|
||||
set_compression(fname);
|
||||
|
||||
@@ -370,10 +366,8 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
|
||||
free_sums(s);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "sender finished %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "sender finished %s\n", fname);
|
||||
|
||||
/* Flag that we actually sent this entry. */
|
||||
file->flags |= FLAG_SENT;
|
||||
|
||||
49
socket.c
49
socket.c
@@ -32,10 +32,16 @@
|
||||
**/
|
||||
|
||||
#include "rsync.h"
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Establish a proxy connection on an open socket to a web proxy by
|
||||
* using the CONNECT method. If proxy_user and proxy_pass are not NULL,
|
||||
@@ -54,13 +60,13 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
proxy_user, ":", proxy_pass, NULL);
|
||||
len = strlen(buffer);
|
||||
|
||||
if ((len*8 + 5) / 6 >= (int)sizeof authbuf) {
|
||||
if ((len*8 + 5) / 6 >= (int)sizeof authbuf - 3) {
|
||||
rprintf(FERROR,
|
||||
"authentication information is too long\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
base64_encode(buffer, len, authbuf);
|
||||
base64_encode(buffer, len, authbuf, 1);
|
||||
authhdr = "\r\nProxy-Authorization: Basic ";
|
||||
} else {
|
||||
*authbuf = '\0';
|
||||
@@ -329,9 +335,9 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
int one = 1;
|
||||
int s, *socks, maxs, i;
|
||||
int s, *socks, maxs, i, ecnt;
|
||||
struct addrinfo hints, *all_ai, *resp;
|
||||
char portbuf[10];
|
||||
char portbuf[10], **errmsgs;
|
||||
int error;
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
@@ -349,17 +355,25 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
/* Count max number of sockets we might open. */
|
||||
for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
|
||||
|
||||
if (!(socks = new_array(int, maxs + 1)))
|
||||
socks = new_array(int, maxs + 1);
|
||||
errmsgs = new_array(char *, maxs);
|
||||
if (!socks || !errmsgs)
|
||||
out_of_memory("open_socket_in");
|
||||
|
||||
/* We may not be able to create the socket, if for example the
|
||||
* machine knows about IPv6 in the C library, but not in the
|
||||
* kernel. */
|
||||
for (resp = all_ai, i = 0; resp; resp = resp->ai_next) {
|
||||
for (resp = all_ai, i = ecnt = 0; resp; resp = resp->ai_next) {
|
||||
s = socket(resp->ai_family, resp->ai_socktype,
|
||||
resp->ai_protocol);
|
||||
|
||||
if (s == -1) {
|
||||
int r = asprintf(&errmsgs[ecnt++],
|
||||
"socket(%d,%d,%d) failed: %s\n",
|
||||
(int)resp->ai_family, (int)resp->ai_socktype,
|
||||
(int)resp->ai_protocol, strerror(errno));
|
||||
if (r < 0)
|
||||
out_of_memory("open_socket_in");
|
||||
/* See if there's another address that will work... */
|
||||
continue;
|
||||
}
|
||||
@@ -381,6 +395,11 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
/* Now we've got a socket - we need to bind it. */
|
||||
if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
|
||||
/* Nope, try another */
|
||||
int r = asprintf(&errmsgs[ecnt++],
|
||||
"bind() failed: %s (address-family %d)\n",
|
||||
strerror(errno), (int)resp->ai_family);
|
||||
if (r < 0)
|
||||
out_of_memory("open_socket_in");
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
@@ -392,6 +411,15 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
if (all_ai)
|
||||
freeaddrinfo(all_ai);
|
||||
|
||||
/* Only output the socket()/bind() messages if we were totally
|
||||
* unsuccessful, or if the daemon is being run with -vv. */
|
||||
for (s = 0; s < ecnt; s++) {
|
||||
if (!i || verbose > 1)
|
||||
rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]));
|
||||
free(errmsgs[s]);
|
||||
}
|
||||
free(errmsgs);
|
||||
|
||||
if (!i) {
|
||||
rprintf(FERROR,
|
||||
"unable to bind any inbound sockets on port %d\n",
|
||||
@@ -433,7 +461,9 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
#ifdef WNOHANG
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0) {}
|
||||
#endif
|
||||
#ifndef HAVE_SIGACTION
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -442,6 +472,10 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
fd_set deffds;
|
||||
int *sp, maxfd, i;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
sigact.sa_flags = SA_NOCLDSTOP;
|
||||
#endif
|
||||
|
||||
/* open an incoming socket */
|
||||
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
if (sp == NULL)
|
||||
@@ -465,7 +499,6 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
maxfd = sp[i];
|
||||
}
|
||||
|
||||
|
||||
/* now accept incoming connections - forking a new process
|
||||
* for each incoming connection */
|
||||
while (1) {
|
||||
@@ -500,7 +533,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
SIGACTION(SIGCHLD, sigchld_handler);
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
int ret;
|
||||
|
||||
172
support/file-attr-restore
Executable file
172
support/file-attr-restore
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/perl
|
||||
# This script will parse the output of "find ARG [ARG...] -ls" and
|
||||
# apply (at your discretion) the permissions, owner, and group info
|
||||
# it reads onto any existing files and dirs (it doesn't try to affect
|
||||
# symlinks). Run this with --help (-h) for a usage summary.
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
our($p_opt, $o_opt, $g_opt, $map_file, $dry_run, $verbosity, $help_opt);
|
||||
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'all|a' => sub { $p_opt = $o_opt = $g_opt = 1 },
|
||||
'perms|p' => \$p_opt,
|
||||
'owner|o' => \$o_opt,
|
||||
'groups|g' => \$g_opt,
|
||||
'map|m=s' => \$map_file,
|
||||
'dry-run|n' => \$dry_run,
|
||||
'help|h' => \$help_opt,
|
||||
'verbose|v+' => \$verbosity,
|
||||
) || $help_opt;
|
||||
|
||||
our(%uid_hash, %gid_hash);
|
||||
|
||||
$" = ', '; # How to join arrays referenced in double-quotes.
|
||||
|
||||
&parse_map_file($map_file) if defined $map_file;
|
||||
|
||||
my $detail_line = qr{
|
||||
^ \s* \d+ \s+ # ignore inode
|
||||
\d+ \s+ # ignore size
|
||||
([-bcdlps]) # 1. File type
|
||||
( [-r][-w][-xsS] # 2. user-permissions
|
||||
[-r][-w][-xsS] # 3. group-permissions
|
||||
[-r][-w][-xtT] ) \s+ # 4. other-permissions
|
||||
\d+ \s+ # ignore number of links
|
||||
(\S+) \s+ # 5. owner
|
||||
(\S+) \s+ # 6. group
|
||||
(?: \d+ \s+ )? # ignore size (when present)
|
||||
\w+ \s+ \d+ \s+ # ignore month and date
|
||||
\d+ (?: : \d+ )? \s+ # ignore time or year
|
||||
([^\r\n]+) $ # 7. name
|
||||
}x;
|
||||
|
||||
while (<>) {
|
||||
my($type, $perms, $owner, $group, $name) = /$detail_line/;
|
||||
die "Invalid input line $.:\n$_" unless defined $name;
|
||||
die "A filename is not properly escaped:\n$_" unless $name =~ /^[^"\\]*(\\(\d\d\d|\D)[^"\\]*)*$/;
|
||||
my $fn = eval "\"$name\"";
|
||||
if ($type eq '-') {
|
||||
undef $type unless -f $fn;
|
||||
} elsif ($type eq 'd') {
|
||||
undef $type unless -d $fn;
|
||||
} elsif ($type eq 'b') {
|
||||
undef $type unless -b $fn;
|
||||
} elsif ($type eq 'c') {
|
||||
undef $type unless -c $fn;
|
||||
} elsif ($type eq 'p') {
|
||||
undef $type unless -p $fn;
|
||||
} elsif ($type eq 's') {
|
||||
undef $type unless -S $fn;
|
||||
} else {
|
||||
if ($verbosity) {
|
||||
if ($type eq 'l') {
|
||||
$name =~ s/ -> .*//;
|
||||
$type = 'symlink';
|
||||
} else {
|
||||
$type = "type '$type'";
|
||||
}
|
||||
print "Skipping $name ($type ignored)\n";
|
||||
}
|
||||
next;
|
||||
}
|
||||
if (!defined $type) {
|
||||
my $reason = -e _ ? "types don't match" : 'missing';
|
||||
print "Skipping $name ($reason)\n";
|
||||
next;
|
||||
}
|
||||
my($cur_mode, $cur_uid, $cur_gid) = (stat(_))[2,4,5];
|
||||
$cur_mode &= 07777;
|
||||
my $highs = join('', $perms =~ /..(.)..(.)..(.)/);
|
||||
$highs =~ tr/-rwxSTst/00001111/;
|
||||
$perms =~ tr/-STrwxst/00011111/;
|
||||
my $mode = $p_opt ? oct('0b' . $highs . $perms) : $cur_mode;
|
||||
my $uid = $o_opt ? $uid_hash{$owner} : $cur_uid;
|
||||
if (!defined $uid) {
|
||||
if ($owner =~ /^\d+$/) {
|
||||
$uid = $owner;
|
||||
} else {
|
||||
$uid = getpwnam($owner);
|
||||
}
|
||||
$uid_hash{$owner} = $uid;
|
||||
}
|
||||
my $gid = $g_opt ? $gid_hash{$group} : $cur_gid;
|
||||
if (!defined $gid) {
|
||||
if ($group =~ /^\d+$/) {
|
||||
$gid = $group;
|
||||
} else {
|
||||
$gid = getgrnam($group);
|
||||
}
|
||||
$gid_hash{$group} = $gid;
|
||||
}
|
||||
|
||||
my @changes;
|
||||
if ($mode != $cur_mode) {
|
||||
push(@changes, 'permissions');
|
||||
if (!$dry_run && !chmod($mode, $fn)) {
|
||||
warn "chmod($mode, \"$name\") failed: $!\n";
|
||||
}
|
||||
}
|
||||
if ($uid != $cur_uid || $gid != $cur_gid) {
|
||||
push(@changes, 'owner') if $uid != $cur_uid;
|
||||
push(@changes, 'group') if $gid != $cur_gid;
|
||||
if (!$dry_run) {
|
||||
if (!chown($uid, $gid, $fn)) {
|
||||
warn "chown($uid, $gid, \"$name\") failed: $!\n";
|
||||
}
|
||||
if (($mode & 06000) && !chmod($mode, $fn)) {
|
||||
warn "post-chown chmod($mode, \"$name\") failed: $!\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (@changes) {
|
||||
print "$name: changed @changes\n";
|
||||
} elsif ($verbosity) {
|
||||
print "$name: OK\n";
|
||||
}
|
||||
}
|
||||
exit;
|
||||
|
||||
sub parse_map_file
|
||||
{
|
||||
my($fn) = @_;
|
||||
open(IN, $fn) or die "Unable to open $fn: $!\n";
|
||||
while (<IN>) {
|
||||
if (/^user\s+(\S+)\s+(\S+)/) {
|
||||
$uid_hash{$1} = $2;
|
||||
} elsif (/^group\s+(\S+)\s+(\S+)/) {
|
||||
$gid_hash{$1} = $2;
|
||||
} else {
|
||||
die "Invalid line #$. in mapfile `$fn':\n$_";
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: file-attr-restore [OPTIONS] FILE [FILE...]
|
||||
-a, --all Restore all the attributes (-pog)
|
||||
-p, --perms Restore the permissions
|
||||
-o, --owner Restore the ownership
|
||||
-g, --groups Restore the group
|
||||
-m, --map=FILE Read user/group mappings from FILE
|
||||
-n, --dry-run Don't actually make the changes
|
||||
-v, --verbose Increase verbosity
|
||||
-h, --help Show this help text
|
||||
|
||||
The FILE arg(s) should have been created by running the "find"
|
||||
program with "-ls" as the output specifier.
|
||||
|
||||
The input file for the --map option must be in this format:
|
||||
|
||||
user FROM TO
|
||||
group FROM TO
|
||||
|
||||
The "FROM" should be an user/group mentioned in the input, and the TO
|
||||
should be either a uid/gid number, or a local user/group name.
|
||||
EOT
|
||||
}
|
||||
27
support/files-to-excludes
Executable file
27
support/files-to-excludes
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/perl
|
||||
# This script takes an input of filenames and outputs a set of
|
||||
# include/exclude directives that can be used by rsync to copy
|
||||
# just the indicated files using an --exclude-from=FILE option.
|
||||
use strict;
|
||||
|
||||
my %hash;
|
||||
|
||||
while (<>) {
|
||||
chomp;
|
||||
s#^/+##;
|
||||
my $path = '/';
|
||||
while (m#([^/]+/)/*#g) {
|
||||
$path .= $1;
|
||||
print "+ $path\n" unless $hash{$path}++;
|
||||
}
|
||||
if (m#([^/]+)$#) {
|
||||
print "+ $path$1\n";
|
||||
} else {
|
||||
delete $hash{$path};
|
||||
}
|
||||
}
|
||||
|
||||
foreach (sort keys %hash) {
|
||||
print "- $_*\n";
|
||||
}
|
||||
print "- /*\n";
|
||||
34
support/logfilter
Executable file
34
support/logfilter
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/perl
|
||||
# Filter the rsync daemon log messages by module name. The log file can be
|
||||
# in either syslog format or rsync's own log-file format. Note that the
|
||||
# MODULE_NAME parameter is used in a regular-expression match in order to
|
||||
# allow regex wildcards to be used. You can also limit the output by
|
||||
# directory hierarchy in a module. Examples:
|
||||
#
|
||||
# logfilter foo /var/log/rsyncd.log # output lines for module foo
|
||||
# logfilter foo/dir /var/log/syslog # limit lines to those in dir of foo
|
||||
|
||||
use strict;
|
||||
|
||||
my $match = shift;
|
||||
die "Usage: logfilter MODULE_NAME [LOGFILE ...]\n" unless defined $match;
|
||||
|
||||
my $syslog_prefix = '\w\w\w +\d+ \d\d:\d\d:\d\d \S+ rsyncd';
|
||||
my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
|
||||
|
||||
my %pids;
|
||||
|
||||
while (<>) {
|
||||
my($pid,$msg) = /^(?:$syslog_prefix|$rsyncd_prefix)\[(\d+)\]:? (.*)/o;
|
||||
next unless defined $pid;
|
||||
my($mod_spec) = $msg =~ /^rsync (?:on|to) (\S+) from /;
|
||||
if (defined $mod_spec) {
|
||||
if ($mod_spec =~ /^$match(\/\S*)?$/o) {
|
||||
$pids{$pid} = 1;
|
||||
} else {
|
||||
delete $pids{$pid};
|
||||
}
|
||||
}
|
||||
next unless $pids{$pid};
|
||||
print $_;
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
use Getopt::Long;
|
||||
|
||||
# You may wish to edit the next line to customize for your default log file.
|
||||
$usage_file = "/var/adm/rsyncd.log";
|
||||
$usage_file = "/var/log/rsyncd.log";
|
||||
|
||||
# Edit the following lines for default report settings.
|
||||
# Entries defined here will be over-ridden by the command line.
|
||||
@@ -52,9 +52,22 @@ if ($only_section) {
|
||||
|
||||
line: while (<LOG>) {
|
||||
|
||||
my $syslog_prefix = '\w\w\w +\d+ \d\d:\d\d:\d\d \S+ rsyncd';
|
||||
my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d ';
|
||||
|
||||
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;
|
||||
= m{^
|
||||
( \w\w\w\s+\d+ | \d+/\d\d/\d\d ) \s+ # day
|
||||
(\d\d:\d\d:\d\d) \s+ # time
|
||||
[^[]* \[\d+\]:? \s+ # pid (ignored)
|
||||
(send|recv|[<>]f\S+) \s+ # op (%o or %i)
|
||||
(\S+) \s+ # host
|
||||
\[\d+\.\d+\.\d+\.\d+\] \s+ # IP (ignored)
|
||||
(\S+) \s+ # module
|
||||
\(\S*\) \s+ # user (ignored)
|
||||
(.*) \s+ # file name
|
||||
(\d+) # file length in bytes
|
||||
$ }x;
|
||||
|
||||
# TODO actually divide the data by into send/recv categories
|
||||
if ($op =~ /^>/) {
|
||||
|
||||
@@ -7,20 +7,13 @@
|
||||
* -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):
|
||||
* the following commands (the resulting files should be identical):
|
||||
*
|
||||
* rsync -av --rsh="savetransfer -i /tmp/from.sender ssh"
|
||||
* --rsync-path="savetransfer -i /tmp/to.receiver rsync" FILES HOST:DEST
|
||||
* rsync -av --rsh="savetransfer -i /tmp/to.server ssh"
|
||||
* --rsync-path="savetransfer -i /tmp/from.client rsync" SOURCE 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
|
||||
* rsync -av --rsh="savetransfer -o /tmp/from.server ssh"
|
||||
* --rsync-path="savetransfer -o /tmp/to.client rsync" SOURCE 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
|
||||
|
||||
19
syscall.c
19
syscall.c
@@ -45,14 +45,14 @@ extern int preserve_perms;
|
||||
|
||||
#define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
|
||||
|
||||
int do_unlink(char *fname)
|
||||
int do_unlink(const char *fname)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return unlink(fname);
|
||||
}
|
||||
|
||||
int do_symlink(char *fname1, char *fname2)
|
||||
int do_symlink(const char *fname1, const char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
@@ -60,7 +60,7 @@ int do_symlink(char *fname1, char *fname2)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINK
|
||||
int do_link(char *fname1, char *fname2)
|
||||
int do_link(const char *fname1, const char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
@@ -118,14 +118,14 @@ int do_mknod(char *pathname, mode_t mode, dev_t dev)
|
||||
#endif
|
||||
}
|
||||
|
||||
int do_rmdir(char *pathname)
|
||||
int do_rmdir(const char *pathname)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return rmdir(pathname);
|
||||
}
|
||||
|
||||
int do_open(char *pathname, int flags, mode_t mode)
|
||||
int do_open(const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
if (flags != O_RDONLY) {
|
||||
RETURN_ERROR_IF(dry_run, 0);
|
||||
@@ -155,14 +155,13 @@ int do_chmod(const char *path, mode_t mode)
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_rename(char *fname1, char *fname2)
|
||||
int do_rename(const char *fname1, const char *fname2)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
return rename(fname1, fname2);
|
||||
}
|
||||
|
||||
|
||||
void trim_trailing_slashes(char *name)
|
||||
{
|
||||
int l;
|
||||
@@ -181,7 +180,6 @@ void trim_trailing_slashes(char *name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int do_mkdir(char *fname, mode_t mode)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
@@ -190,7 +188,6 @@ int do_mkdir(char *fname, mode_t mode)
|
||||
return mkdir(fname, mode);
|
||||
}
|
||||
|
||||
|
||||
/* like mkstemp but forces permissions */
|
||||
int do_mkstemp(char *template, mode_t perms)
|
||||
{
|
||||
@@ -255,7 +252,11 @@ int do_fstat(int fd, STRUCT_STAT *st)
|
||||
OFF_T do_lseek(int fd, OFF_T offset, int whence)
|
||||
{
|
||||
#ifdef HAVE_LSEEK64
|
||||
#if !SIZEOF_OFF64_T
|
||||
OFF_T lseek64();
|
||||
#else
|
||||
off64_t lseek64();
|
||||
#endif
|
||||
return lseek64(fd, offset, whence);
|
||||
#else
|
||||
return lseek(fd, offset, whence);
|
||||
|
||||
3
t_stub.c
3
t_stub.c
@@ -28,6 +28,9 @@
|
||||
|
||||
int modify_window = 0;
|
||||
int module_id = -1;
|
||||
int relative_paths = 0;
|
||||
int human_readable = 0;
|
||||
mode_t orig_umask = 002;
|
||||
char *partial_dir;
|
||||
struct filter_list_struct server_filter_list;
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
cd "$tmpdir"
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
mygrps="`rsync_getgroups`" || fail "Can't get groups"
|
||||
|
||||
42
testsuite/chmod-option.test
Normal file
42
testsuite/chmod-option.test
Normal file
@@ -0,0 +1,42 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that the --chmod option functions correctly.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
# Build some files
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
checkdir="$scratchdir/check"
|
||||
|
||||
mkdir "$fromdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
dir1="$fromdir/dir1"
|
||||
dir2="$fromdir/dir2"
|
||||
echo "This is the file" > "$name1"
|
||||
echo "This is the other file" > "$name2"
|
||||
mkdir "$dir1" "$dir2"
|
||||
|
||||
chmod 4700 "$name1" || test_skipped "Can't chmod"
|
||||
chmod 700 "$dir1"
|
||||
chmod 770 "$dir2"
|
||||
|
||||
# Copy the files we've created over to another directory
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
|
||||
|
||||
# And then manually make the changes which should occur
|
||||
umask 002
|
||||
chmod ug-s,a+rX "$checkdir"/*
|
||||
chmod +w "$checkdir" "$checkdir"/dir*
|
||||
|
||||
checkit "$RSYNC -avv --chmod ug-s,a+rX,D+w \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that various read-only and set[ug]id permissions work properly,
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
tmpdir2=/tmp
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that various read-only and set[ug]id permissions work properly,
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
chmod 440 "$fromdir/text"
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of the --compare-dest option.
|
||||
@@ -14,8 +14,6 @@ alt2dir="$tmpdir/alt2"
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
# Setup the alt and chk dirs
|
||||
|
||||
@@ -26,8 +26,6 @@ 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,8 +20,6 @@ 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.
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
# Copyright (C) 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# 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"
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
chkfile="$scratchdir/rsync.chk"
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
case `id -u` in
|
||||
@@ -16,7 +19,7 @@ case `id -u` in
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh "$0"
|
||||
exec /usr/bin/fakeroot /bin/sh $RUNSHFLAGS "$0"
|
||||
fi
|
||||
test_skipped "Rsync won't copy devices unless we're root"
|
||||
;;
|
||||
@@ -25,15 +28,66 @@ esac
|
||||
# TODO: Need to test whether hardlinks are possible on this OS/filesystem
|
||||
|
||||
mkdir "$fromdir"
|
||||
mkdir "$todir"
|
||||
mknod "$fromdir/char" c 41 67 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/char2" c 42 68 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node unless root"
|
||||
mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node unless root"
|
||||
mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node unless root"
|
||||
mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node unless root"
|
||||
ln "$fromdir/block3" "$fromdir/block2.5" || echo "Skipping hard-linked device test..."
|
||||
mkfifo "$fromdir/fifo" || test_skipped "Can't run mkfifo"
|
||||
touch -r "$fromdir/block" "$fromdir/block2"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" skip_file_diff
|
||||
$RSYNC -ai "$fromdir/block" "$todir/block2" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD+++++++ block
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
|
||||
|
||||
$RSYNC -ai "$fromdir/block2" "$todir/block" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD+++++++ block2
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
|
||||
|
||||
sleep 1
|
||||
|
||||
$RSYNC -Di "$fromdir/block3" "$todir/block" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD..T.... block3
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
$RSYNC -aiHvv "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
.d..t.... ./
|
||||
cD..t.... block
|
||||
cD....... block2
|
||||
cD+++++++ block3
|
||||
hD+++++++ block2.5 => block3
|
||||
cD+++++++ char
|
||||
cD+++++++ char2
|
||||
cD+++++++ char3
|
||||
cS+++++++ fifo
|
||||
EOT
|
||||
if test ! -b "$fromdir/block2.5"; then
|
||||
sed -e '/block2\.5/d' \
|
||||
<"$chkfile" >"$chkfile.new"
|
||||
mv "$chkfile.new" "$chkfile"
|
||||
fi
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
|
||||
|
||||
echo "check how the directory listings compare with diff:"
|
||||
echo ""
|
||||
( cd "$fromdir" && rsync_ls_lR . ) > "$tmpdir/ls-from"
|
||||
( cd "$todir" && rsync_ls_lR . ) > "$tmpdir/ls-to"
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
41
testsuite/dir-sgid.test
Normal file
41
testsuite/dir-sgid.test
Normal file
@@ -0,0 +1,41 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that rsync obeys directory setgid. -- Matt McCutchen
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
umask 077
|
||||
|
||||
# Call as: testit <dirname> <dirperms> <file-expected> <program-expected> <dir-expected>
|
||||
testit() {
|
||||
todir="$scratchdir/$1"
|
||||
mkdir "$todir"
|
||||
chmod $2 "$todir"
|
||||
# Make sure we obey directory setgid when creating a directory to hold multiple transferred files,
|
||||
# even though the directory itself is outside the transfer
|
||||
$RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/"
|
||||
check_perms "$todir/to" $5 "Target $1"
|
||||
check_perms "$todir/to/dir" $5 "Target $1"
|
||||
check_perms "$todir/to/file" $3 "Target $1"
|
||||
check_perms "$todir/to/program" $4 "Target $1"
|
||||
}
|
||||
|
||||
echo "File!" >"$scratchdir/file"
|
||||
echo "#!/bin/sh" >"$scratchdir/program"
|
||||
mkdir "$scratchdir/dir"
|
||||
chmod 2764 "$scratchdir/dir" || test_skipped "Can't chmod"
|
||||
chmod 664 "$scratchdir/file"
|
||||
chmod 775 "$scratchdir/program"
|
||||
[ -g "$scratchdir/dir" ] || test_skipped "The directory setgid bit vanished!"
|
||||
mkdir "$scratchdir/dir/blah"
|
||||
[ -g "$scratchdir/dir/blah" ] || test_skipped "Your filesystem doesn't use directory setgid; maybe it's BSD."
|
||||
|
||||
# Test some target directories
|
||||
testit setgid-off 700 rw------- rwx------ rwx------
|
||||
testit setgid-on 2700 rw------- rwx------ rwx--S---
|
||||
|
||||
# Hooray
|
||||
exit 0
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Copyright (C) 2002 by Martin Pool <mbp@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of duplicate filenames.
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
mkdir "$fromdir"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of exclude/include directives.
|
||||
@@ -12,18 +12,18 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
HOME="$scratchdir"
|
||||
CVSIGNORE='*.junk'
|
||||
export HOME CVSIGNORE
|
||||
|
||||
set -x
|
||||
export CVSIGNORE
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
makepath "$fromdir/foo/down/to/you"
|
||||
makepath "$fromdir/foo/sub"
|
||||
makepath "$fromdir/bar/down/to/foo/too"
|
||||
makepath "$fromdir/bar/down/to/bar/baz"
|
||||
makepath "$fromdir/mid/for/foo/and/that/is/who"
|
||||
makepath "$fromdir/new/keep/this"
|
||||
makepath "$fromdir/new/lose/this"
|
||||
cat >"$fromdir/.filt" <<EOF
|
||||
exclude down
|
||||
: .filt-temp
|
||||
@@ -32,13 +32,14 @@ clear
|
||||
- *.bak
|
||||
- *.old
|
||||
EOF
|
||||
echo kept >"$fromdir/foo/file1"
|
||||
echo filtered-1 >"$fromdir/foo/file1"
|
||||
echo removed >"$fromdir/foo/file2"
|
||||
echo cvsout >"$fromdir/foo/file2.old"
|
||||
cat >"$fromdir/foo/.filt" <<EOF
|
||||
include .filt
|
||||
- file1
|
||||
- /file1
|
||||
EOF
|
||||
echo not-filtered-1 >"$fromdir/foo/sub/file1"
|
||||
cat >"$fromdir/bar/.filt" <<EOF
|
||||
- home-cvs-exclude
|
||||
dir-merge .filt2
|
||||
@@ -87,8 +88,12 @@ cat >"$excl" <<EOF
|
||||
- /bar
|
||||
# This should match against the whole path, not just the name.
|
||||
+ foo**too
|
||||
# This should float at the end of the path.
|
||||
# These should float at the end of the path.
|
||||
+ foo/s?b/
|
||||
- foo/*/
|
||||
# Test how /** differs from /***
|
||||
- new/keep/**
|
||||
- new/lose/***
|
||||
# Test some normal excludes. Competing lines are paired.
|
||||
+ t[o]/
|
||||
- to
|
||||
@@ -109,6 +114,8 @@ sleep 1 # Ensures that the rm commands will tweak the directory times.
|
||||
|
||||
rm -r "$chkdir"/foo/down
|
||||
rm -r "$chkdir"/mid/for/foo/and
|
||||
rm -r "$chkdir"/new/keep/this
|
||||
rm -r "$chkdir"/new/lose
|
||||
rm "$chkdir"/foo/file[235-9]
|
||||
rm "$chkdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo/file[235-9]
|
||||
rm "$chkdir"/mid/for/foo/extra
|
||||
@@ -196,5 +203,13 @@ $RSYNC -av --delete-excluded --exclude='*' "$fromdir/" "$todir/"
|
||||
checkit "$RSYNC -avv -f dir-merge,-_.excl \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
relative_opts='--relative --chmod=Du+w --copy-unsafe-links'
|
||||
$RSYNC -av $relative_opts "$fromdir/foo" "$chkdir/"
|
||||
rm -rf "$chkdir$fromdir/foo/down"
|
||||
$RSYNC -av $relative_opts --existing --filter='-! */' "$fromdir/foo" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avv $relative_opts --exclude=\"$fromdir/foo/down\" \
|
||||
\"$fromdir/foo\" \"$todir\"" "$chkdir$fromdir/foo" "$todir$fromdir/foo"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
47
testsuite/executability.test
Normal file
47
testsuite/executability.test
Normal file
@@ -0,0 +1,47 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test the --executability or -E option. -- Matt McCutchen
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
# Put some files in the From directory
|
||||
mkdir "$fromdir"
|
||||
cat <<EOF >"$fromdir/1"
|
||||
#!/bin/sh
|
||||
echo 'Program One!'
|
||||
EOF
|
||||
cat <<EOF >"$fromdir/2"
|
||||
#!/bin/sh
|
||||
echo 'Program Two!'
|
||||
EOF
|
||||
|
||||
chmod 1700 "$fromdir/1" || test_skipped "Can't chmod"
|
||||
chmod 600 "$fromdir/2"
|
||||
|
||||
$RSYNC -rvv "$fromdir/" "$todir/"
|
||||
|
||||
check_perms "$todir/1" rwx------ 1
|
||||
check_perms "$todir/2" rw------- 1
|
||||
|
||||
# Mix up the permissions a bit
|
||||
chmod 600 "$fromdir/1"
|
||||
chmod 601 "$fromdir/2"
|
||||
chmod 604 "$todir/2"
|
||||
|
||||
$RSYNC -rvv "$fromdir/" "$todir/"
|
||||
|
||||
# No -E, so nothing should have changed
|
||||
check_perms "$todir/1" rwx------ 2
|
||||
check_perms "$todir/2" rw----r-- 2
|
||||
|
||||
$RSYNC -rvvE "$fromdir/" "$todir/"
|
||||
|
||||
# Now things should have happened!
|
||||
check_perms "$todir/1" rw------- 3
|
||||
check_perms "$todir/2" rwx---r-x 3
|
||||
|
||||
# Hooray
|
||||
exit 0
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
# Copyright (C) 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# 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"
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Copyright (C) 2005 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test the output of various copy commands to ensure itemized output
|
||||
@@ -10,26 +10,11 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
lddir="$tmpdir/ld"
|
||||
|
||||
chkfile="$scratchdir/rsync.chk"
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
# This is only called if rsync was run with -v or -vv (not -i alone).
|
||||
# Higher levels of -v would require more filtering.
|
||||
filter_outfile() {
|
||||
sed -e '/^building file list /d' \
|
||||
-e '/^created directory /d' \
|
||||
-e '/^done$/d' \
|
||||
-e '/ --whole-file$/d' \
|
||||
-e '/^total: /d' \
|
||||
-e '/^$/,$d' \
|
||||
<"$outfile" >"$outfile.new"
|
||||
mv "$outfile.new" "$outfile"
|
||||
}
|
||||
|
||||
makepath "$fromdir/foo"
|
||||
makepath "$fromdir/bar/baz"
|
||||
cp -p "$srcdir/configure.in" "$fromdir/foo/config1"
|
||||
@@ -152,15 +137,62 @@ cat <<EOT >"$chkfile"
|
||||
.d..t.... ./
|
||||
cd+++++++ bar/
|
||||
cd+++++++ bar/baz/
|
||||
cf....... bar/baz/rsync
|
||||
cf bar/baz/rsync
|
||||
cd+++++++ foo/
|
||||
cf....... foo/config1
|
||||
cf....... foo/config2
|
||||
hf+++++++ foo/extra => foo/config1
|
||||
cL+++++++ foo/sym -> ../bar/baz/rsync
|
||||
cf foo/config1
|
||||
cf foo/config2
|
||||
hf foo/extra => foo/config1
|
||||
cL..T.... foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -iplrtH --copy-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
.d..t.... ./
|
||||
cd+++++++ bar/
|
||||
cd+++++++ bar/baz/
|
||||
cd+++++++ foo/
|
||||
hf foo/extra => foo/config1
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -vvplrtH --copy-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
./
|
||||
bar/
|
||||
bar/baz/
|
||||
bar/baz/rsync is uptodate
|
||||
foo/
|
||||
foo/config1 is uptodate
|
||||
foo/config2 is uptodate
|
||||
"foo/extra" is a hard link
|
||||
foo/extra => foo/config1
|
||||
foo/sym is uptodate
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 10 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -ivvplrtH --link-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
.d..t.... ./
|
||||
cd+++++++ bar/
|
||||
cd+++++++ bar/baz/
|
||||
hf bar/baz/rsync
|
||||
cd+++++++ foo/
|
||||
hf foo/config1
|
||||
hf foo/config2
|
||||
hf foo/extra => foo/config1
|
||||
hL foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -iplrtH --link-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
@@ -169,10 +201,71 @@ cat <<EOT >"$chkfile"
|
||||
cd+++++++ bar/
|
||||
cd+++++++ bar/baz/
|
||||
cd+++++++ foo/
|
||||
hf+++++++ foo/extra => foo/config1
|
||||
cL+++++++ foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 12 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -vvplrtH --link-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
./
|
||||
bar/
|
||||
bar/baz/
|
||||
bar/baz/rsync is uptodate
|
||||
foo/
|
||||
foo/config1 is uptodate
|
||||
foo/config2 is uptodate
|
||||
"foo/extra" is a hard link
|
||||
foo/sym is uptodate
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 13 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -ivvplrtH --compare-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
# TODO fix really-old problem when combining -H with --compare-dest:
|
||||
# missing output for foo/extra hard-link (and it might not be updated)!
|
||||
cat <<EOT >"$chkfile"
|
||||
.d..t.... ./
|
||||
cd+++++++ bar/
|
||||
cd+++++++ bar/baz/
|
||||
.f bar/baz/rsync
|
||||
cd+++++++ foo/
|
||||
.f foo/config1
|
||||
.f foo/config2
|
||||
.L foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 14 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -iplrtH --compare-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
.d..t.... ./
|
||||
cd+++++++ bar/
|
||||
cd+++++++ bar/baz/
|
||||
cd+++++++ foo/
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"
|
||||
|
||||
rm -rf "$todir"
|
||||
$RSYNC -vvplrtH --compare-dest="$lddir" "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
./
|
||||
bar/
|
||||
bar/baz/
|
||||
bar/baz/rsync is uptodate
|
||||
foo/
|
||||
foo/config1 is uptodate
|
||||
foo/config2 is uptodate
|
||||
"foo/extra" is a hard link
|
||||
foo/sym is uptodate
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 16 failed"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
longname=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
from1dir="${fromdir}1"
|
||||
|
||||
@@ -32,6 +32,9 @@ else
|
||||
diffopt="-c"
|
||||
fi
|
||||
|
||||
HOME="$scratchdir"
|
||||
export HOME
|
||||
|
||||
runtest() {
|
||||
echo $ECHO_N "Test $1: $ECHO_C"
|
||||
if eval "$2"
|
||||
@@ -44,15 +47,38 @@ runtest() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Call this if you want to filter out verbose messages (-v or -vv) from
|
||||
# the output of an rsync run (whittling the output down to just the file
|
||||
# messages). This isn't needed if you use -i without -v.
|
||||
filter_outfile() {
|
||||
sed -e '/^building file list /d' \
|
||||
-e '/^created directory /d' \
|
||||
-e '/^done$/d' \
|
||||
-e '/ --whole-file$/d' \
|
||||
-e '/^total: /d' \
|
||||
-e '/^$/,$d' \
|
||||
<"$outfile" >"$outfile.new"
|
||||
mv "$outfile.new" "$outfile"
|
||||
}
|
||||
|
||||
printmsg() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
|
||||
rsync_ls_lR() {
|
||||
find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls"
|
||||
}
|
||||
|
||||
check_perms() {
|
||||
perms=`"$TOOLDIR/tls" "$1" | sed 's/^[-d]\(.........\).*/\1/'`
|
||||
if test $perms = $2; then
|
||||
return 0
|
||||
fi
|
||||
echo "permissions: $perms on $1"
|
||||
echo "should be: $2"
|
||||
test_fail "failed test $3"
|
||||
}
|
||||
|
||||
rsync_getgroups() {
|
||||
"$TOOLDIR/getgroups"
|
||||
}
|
||||
@@ -118,7 +144,7 @@ hands_setup() {
|
||||
####################
|
||||
# Many machines do not have "mkdir -p", so we have to build up long paths.
|
||||
# How boring.
|
||||
makepath () {
|
||||
makepath() {
|
||||
echo " makepath $1"
|
||||
p="$1"
|
||||
(
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
build_symlinks || test_fail "failed to build symlinks"
|
||||
|
||||
# Copy recursively, but without -l or -L or -a, and all the symlinks
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
"$TOOLDIR/trimslash" "/usr/local/bin" "/usr/local/bin/" "/usr/local/bin///" \
|
||||
"//a//" "////" \
|
||||
"/Users/Wierd Macintosh Name/// Ooh, translucent plastic/" \
|
||||
|
||||
@@ -32,8 +32,6 @@ ln -s ../files/file1 "from/safe/links/"
|
||||
ln -s ../files/file2 "from/safe/links/"
|
||||
ln -s ../../unsafe/unsafefile "from/safe/links/"
|
||||
|
||||
set -x
|
||||
|
||||
echo "rsync with relative path and just -a";
|
||||
$RSYNC -avv from/safe/ to
|
||||
test_symlink to/links/file1
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
"$TOOLDIR/wildtest" "$srcdir/wildtest.txt" >"$scratchdir/wild.out"
|
||||
diff $diffopt "$scratchdir/wild.out" - <<EOF
|
||||
# This test exercises the wildmatch() function (with no options) and the
|
||||
# wildmatch_join() function (using -x and/or -e).
|
||||
for opts in "" -x1 "-x1 -e1" "-x1 -e1se" -x2 "-x2 -ese" -x3 "-x3 -e1" -x4 "-x4 -e2e" -x5 "-x5 -es"; do
|
||||
echo Running wildtest with "$opts"
|
||||
"$TOOLDIR/wildtest" $opts "$srcdir/wildtest.txt" >"$scratchdir/wild.out"
|
||||
diff $diffopt "$scratchdir/wild.out" - <<EOF
|
||||
No wildmatch errors found.
|
||||
EOF
|
||||
done
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
12
tls.c
12
tls.c
@@ -100,12 +100,12 @@ static void list_file(const char *fname)
|
||||
mt = gmtime(&buf.st_mtime);
|
||||
|
||||
sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
mt->tm_year + 1900,
|
||||
mt->tm_mon + 1,
|
||||
mt->tm_mday,
|
||||
mt->tm_hour,
|
||||
mt->tm_min,
|
||||
mt->tm_sec);
|
||||
(int)mt->tm_year + 1900,
|
||||
(int)mt->tm_mon + 1,
|
||||
(int)mt->tm_mday,
|
||||
(int)mt->tm_hour,
|
||||
(int)mt->tm_min,
|
||||
(int)mt->tm_sec);
|
||||
} else {
|
||||
strcpy(datebuf, " ");
|
||||
}
|
||||
|
||||
58
token.c
58
token.c
@@ -22,46 +22,60 @@
|
||||
|
||||
extern int do_compression;
|
||||
extern int module_id;
|
||||
extern int def_compress_level;
|
||||
|
||||
static int compression_level = Z_DEFAULT_COMPRESSION;
|
||||
static int compression_level, per_file_default_level;
|
||||
|
||||
/* determine the compression level based on a wildcard filename list */
|
||||
void set_compression(char *fname)
|
||||
{
|
||||
char *dont;
|
||||
char *tok;
|
||||
static char *match_list;
|
||||
char *s;
|
||||
|
||||
if (!do_compression)
|
||||
return;
|
||||
|
||||
compression_level = Z_DEFAULT_COMPRESSION;
|
||||
dont = lp_dont_compress(module_id);
|
||||
|
||||
if (!dont || !*dont)
|
||||
return;
|
||||
|
||||
if (dont[0] == '*' && !dont[1]) {
|
||||
/* an optimization to skip the rest of this routine */
|
||||
compression_level = 0;
|
||||
return;
|
||||
if (!match_list) {
|
||||
char *t, *f = lp_dont_compress(module_id);
|
||||
int len = strlen(f);
|
||||
if (!(match_list = t = new_array(char, len + 2)))
|
||||
out_of_memory("set_compression");
|
||||
while (*f) {
|
||||
if (*f == ' ') {
|
||||
f++;
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
if (isupper(*(unsigned char *)f))
|
||||
*t++ = tolower(*(unsigned char *)f);
|
||||
else
|
||||
*t++ = *f;
|
||||
} while (*++f != ' ' && *f);
|
||||
*t++ = '\0';
|
||||
}
|
||||
/* Optimize a match-string of "*". */
|
||||
if (t - match_list == 2 && match_list[0] == '*') {
|
||||
t = match_list;
|
||||
per_file_default_level = 0;
|
||||
} else
|
||||
per_file_default_level = def_compress_level;
|
||||
*t++ = '\0';
|
||||
}
|
||||
|
||||
dont = strdup(dont);
|
||||
fname = strdup(fname);
|
||||
if (!dont || !fname)
|
||||
compression_level = per_file_default_level;
|
||||
|
||||
if (!*match_list)
|
||||
return;
|
||||
|
||||
strlower(dont);
|
||||
strlower(fname);
|
||||
if ((s = strrchr(fname, '/')) != NULL)
|
||||
fname = s + 1;
|
||||
|
||||
for (tok = strtok(dont, " "); tok; tok = strtok(NULL, " ")) {
|
||||
if (wildmatch(tok, fname)) {
|
||||
for (s = match_list; *s; s += strlen(s) + 1) {
|
||||
if (iwildmatch(s, fname)) {
|
||||
compression_level = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(dont);
|
||||
free(fname);
|
||||
}
|
||||
|
||||
/* non-compressing recv token */
|
||||
|
||||
@@ -324,7 +324,6 @@ void recv_uid_list(int f, struct file_list *flist)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (preserve_gid && !numeric_ids) {
|
||||
/* read the gid list */
|
||||
while ((id = read_int(f)) != 0) {
|
||||
@@ -337,8 +336,7 @@ void recv_uid_list(int f, struct file_list *flist)
|
||||
}
|
||||
}
|
||||
|
||||
/* now convert the uid/gid of all files in the list to the mapped
|
||||
* uid/gid */
|
||||
/* Now convert all the uids/gids from sender values to our values. */
|
||||
if (am_root && preserve_uid && !numeric_ids) {
|
||||
for (i = 0; i < flist->count; i++)
|
||||
flist->files[i]->uid = match_uid(flist->files[i]->uid);
|
||||
|
||||
313
util.c
313
util.c
@@ -31,6 +31,9 @@ extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int module_id;
|
||||
extern int modify_window;
|
||||
extern int relative_paths;
|
||||
extern int human_readable;
|
||||
extern mode_t orig_umask;
|
||||
extern char *partial_dir;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
|
||||
@@ -68,7 +71,6 @@ void set_blocking(int fd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a file descriptor pair - like pipe() but use socketpair if
|
||||
* possible (because of blocking issues on pipes).
|
||||
@@ -93,7 +95,6 @@ int fd_pair(int fd[2])
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void print_child_argv(char **cmd)
|
||||
{
|
||||
rprintf(FINFO, "opening connection using ");
|
||||
@@ -105,15 +106,14 @@ void print_child_argv(char **cmd)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789"
|
||||
",.-_=+@/") != strlen(*cmd)) {
|
||||
rprintf(FINFO, "\"%s\" ", safe_fname(*cmd));
|
||||
rprintf(FINFO, "\"%s\" ", *cmd);
|
||||
} else {
|
||||
rprintf(FINFO, "%s ", safe_fname(*cmd));
|
||||
rprintf(FINFO, "%s ", *cmd);
|
||||
}
|
||||
}
|
||||
rprintf(FINFO, "\n");
|
||||
}
|
||||
|
||||
|
||||
void out_of_memory(char *str)
|
||||
{
|
||||
rprintf(FERROR, "ERROR: out of memory in %s\n", str);
|
||||
@@ -126,8 +126,6 @@ void overflow_exit(char *str)
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int set_modtime(char *fname, time_t modtime, mode_t mode)
|
||||
{
|
||||
#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
|
||||
@@ -137,7 +135,7 @@ int set_modtime(char *fname, time_t modtime, mode_t mode)
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "set modtime of %s to (%ld) %s",
|
||||
safe_fname(fname), (long)modtime,
|
||||
fname, (long)modtime,
|
||||
asctime(localtime(&modtime)));
|
||||
}
|
||||
|
||||
@@ -172,31 +170,44 @@ int set_modtime(char *fname, time_t modtime, mode_t mode)
|
||||
}
|
||||
}
|
||||
|
||||
/* This creates a new directory with default permissions. Since there
|
||||
* might be some directory-default permissions affecting this, we can't
|
||||
* force the permissions directly using the original umask and mkdir(). */
|
||||
int mkdir_defmode(char *fname)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/**
|
||||
Create any necessary directories in fname. Unfortunately we don't know
|
||||
what perms to give the directory when this is called so we need to rely
|
||||
on the umask
|
||||
**/
|
||||
int create_directory_path(char *fname, int base_umask)
|
||||
umask(orig_umask);
|
||||
ret = do_mkdir(fname, ACCESSPERMS);
|
||||
umask(0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create any necessary directories in fname. Any missing directories are
|
||||
* created with default permissions. */
|
||||
int create_directory_path(char *fname)
|
||||
{
|
||||
char *p;
|
||||
int ret = 0;
|
||||
|
||||
while (*fname == '/')
|
||||
fname++;
|
||||
while (strncmp(fname, "./", 2) == 0)
|
||||
fname += 2;
|
||||
|
||||
umask(orig_umask);
|
||||
p = fname;
|
||||
while ((p = strchr(p,'/')) != NULL) {
|
||||
*p = 0;
|
||||
do_mkdir(fname, 0777 & ~base_umask);
|
||||
*p = '/';
|
||||
p++;
|
||||
*p = '\0';
|
||||
if (do_mkdir(fname, ACCESSPERMS) < 0 && errno != EEXIST)
|
||||
ret = -1;
|
||||
*p++ = '/';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
umask(0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write @p len bytes at @p ptr to descriptor @p desc, retrying if
|
||||
@@ -227,7 +238,6 @@ int full_write(int desc, char *ptr, size_t len)
|
||||
return total_written;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read @p len bytes at @p ptr from descriptor @p desc, retrying if
|
||||
* interrupted.
|
||||
@@ -253,12 +263,11 @@ static int safe_read(int desc, char *ptr, size_t len)
|
||||
return n_chars;
|
||||
}
|
||||
|
||||
|
||||
/** Copy a file.
|
||||
*
|
||||
* 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 copy_file(const char *source, const char *dest, mode_t mode)
|
||||
{
|
||||
int ifd;
|
||||
int ofd;
|
||||
@@ -327,7 +336,7 @@ int copy_file(char *source, char *dest, mode_t mode)
|
||||
* --delete trying to remove old .rsyncNNN files, hence it renames it
|
||||
* each time.
|
||||
**/
|
||||
int robust_unlink(char *fname)
|
||||
int robust_unlink(const char *fname)
|
||||
{
|
||||
#ifndef ETXTBSY
|
||||
return do_unlink(fname);
|
||||
@@ -362,7 +371,7 @@ int robust_unlink(char *fname)
|
||||
|
||||
if (verbose > 0) {
|
||||
rprintf(FINFO,"renaming %s to %s because of text busy\n",
|
||||
safe_fname(fname), safe_fname(path));
|
||||
fname, path);
|
||||
}
|
||||
|
||||
/* maybe we should return rename()'s exit status? Nah. */
|
||||
@@ -375,8 +384,11 @@ int robust_unlink(char *fname)
|
||||
}
|
||||
|
||||
/* Returns 0 on successful rename, 1 if we successfully copied the file
|
||||
* across filesystems, -2 if copy_file() failed, and -1 on other errors. */
|
||||
int robust_rename(char *from, char *to, int mode)
|
||||
* across filesystems, -2 if copy_file() failed, and -1 on other errors.
|
||||
* If partialptr is not NULL and we need to do a copy, copy the file into
|
||||
* the active partial-dir instead of over the destination file. */
|
||||
int robust_rename(char *from, char *to, char *partialptr,
|
||||
int mode)
|
||||
{
|
||||
int tries = 4;
|
||||
|
||||
@@ -392,6 +404,11 @@ int robust_rename(char *from, char *to, int mode)
|
||||
break;
|
||||
#endif
|
||||
case EXDEV:
|
||||
if (partialptr) {
|
||||
if (!handle_partial_dir(partialptr,PDIR_CREATE))
|
||||
return -1;
|
||||
to = partialptr;
|
||||
}
|
||||
if (copy_file(from, to, mode) != 0)
|
||||
return -2;
|
||||
do_unlink(from);
|
||||
@@ -403,7 +420,6 @@ int robust_rename(char *from, char *to, int mode)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static pid_t all_pids[10];
|
||||
static int num_pids;
|
||||
|
||||
@@ -447,7 +463,6 @@ void kill_all(int sig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Turn a user name into a uid */
|
||||
int name_to_uid(char *name, uid_t *uid)
|
||||
{
|
||||
@@ -476,7 +491,6 @@ int name_to_gid(char *name, gid_t *gid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Lock a byte range in a open file */
|
||||
int lock_range(int fd, int offset, int len)
|
||||
{
|
||||
@@ -528,7 +542,6 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
|
||||
filter_server_path(s);
|
||||
#else
|
||||
glob_t globbuf;
|
||||
int i;
|
||||
|
||||
if (maxargs <= argc)
|
||||
return;
|
||||
@@ -553,9 +566,9 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
|
||||
if (globbuf.gl_pathc == 0)
|
||||
argv[argc++] = s;
|
||||
else {
|
||||
int j = globbuf.gl_pathc;
|
||||
int i;
|
||||
free(s);
|
||||
for (i = 0; i < j; i++) {
|
||||
for (i = 0; i < (int)globbuf.gl_pathc; i++) {
|
||||
if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
|
||||
out_of_memory("glob_expand_one");
|
||||
}
|
||||
@@ -756,7 +769,7 @@ unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
|
||||
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
|
||||
{
|
||||
char *start, *sanp;
|
||||
int rlen = 0;
|
||||
int rlen = 0, leave_one_dotdir = relative_paths;
|
||||
|
||||
if (dest != p) {
|
||||
int plen = strlen(p);
|
||||
@@ -791,9 +804,13 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
|
||||
* always be left pointing after a slash
|
||||
*/
|
||||
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
|
||||
/* skip "." component */
|
||||
p++;
|
||||
continue;
|
||||
if (leave_one_dotdir && p[1])
|
||||
leave_one_dotdir = 0;
|
||||
else {
|
||||
/* skip "." component */
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
|
||||
/* ".." component followed by slash or end */
|
||||
@@ -888,43 +905,6 @@ int pop_dir(char *dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
#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;
|
||||
|
||||
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';
|
||||
|
||||
return fbuf[ndx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a quoted string with the full pathname of the indicated filename.
|
||||
* The string " (in MODNAME)" may also be appended. The returned pointer
|
||||
@@ -939,7 +919,6 @@ char *full_fname(const char *fn)
|
||||
if (result)
|
||||
free(result);
|
||||
|
||||
fn = safe_fname(fn);
|
||||
if (*fn == '/')
|
||||
p1 = p2 = "";
|
||||
else {
|
||||
@@ -1034,22 +1013,6 @@ int handle_partial_dir(const char *fname, int create)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** We need to supply our own strcmp function for file list comparisons
|
||||
to ensure that signed/unsigned usage is consistent between machines. */
|
||||
int u_strcmp(const char *cs1, const char *cs2)
|
||||
{
|
||||
const uchar *s1 = (const uchar *)cs1;
|
||||
const uchar *s2 = (const uchar *)cs2;
|
||||
|
||||
while (*s1 && *s2 && (*s1 == *s2)) {
|
||||
s1++; s2++;
|
||||
}
|
||||
|
||||
return (int)*s1 - (int)*s2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a symlink points outside the current directory tree.
|
||||
* This is considered "unsafe" because e.g. when mirroring somebody
|
||||
@@ -1114,6 +1077,63 @@ int unsafe_symlink(const char *dest, const char *src)
|
||||
return (depth < 0);
|
||||
}
|
||||
|
||||
/* Return the int64 number as a string. If the --human-readable option was
|
||||
* specified, we may output the number in K, M, or G units. We can return
|
||||
* up to 4 buffers at a time. */
|
||||
char *human_num(int64 num)
|
||||
{
|
||||
static char bufs[4][128]; /* more than enough room */
|
||||
static unsigned int n;
|
||||
char *s;
|
||||
|
||||
n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
|
||||
|
||||
if (human_readable) {
|
||||
char units = '\0';
|
||||
int mult = human_readable == 1 ? 1000 : 1024;
|
||||
double dnum = 0;
|
||||
if (num > mult*mult*mult) {
|
||||
dnum = (double)num / (mult*mult*mult);
|
||||
units = 'G';
|
||||
} else if (num > mult*mult) {
|
||||
dnum = (double)num / (mult*mult);
|
||||
units = 'M';
|
||||
} else if (num > mult) {
|
||||
dnum = (double)num / mult;
|
||||
units = 'K';
|
||||
}
|
||||
if (units) {
|
||||
sprintf(bufs[n], "%.2f%c", dnum, units);
|
||||
return bufs[n];
|
||||
}
|
||||
}
|
||||
|
||||
s = bufs[n] + sizeof bufs[0] - 1;
|
||||
*s = '\0';
|
||||
|
||||
if (!num)
|
||||
*--s = '0';
|
||||
while (num) {
|
||||
*--s = (num % 10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return the double number as a string. If the --human-readable option was
|
||||
* specified, we may output the number in K, M, or G units. We use a buffer
|
||||
* from human_num() to return our result. */
|
||||
char *human_dnum(double dnum, int decimal_digits)
|
||||
{
|
||||
char *buf = human_num(dnum);
|
||||
int len = strlen(buf);
|
||||
if (isdigit(*(uchar*)(buf+len-1))) {
|
||||
/* There's extra room in buf prior to the start of the num. */
|
||||
buf -= decimal_digits + 1;
|
||||
snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the date and time as a string
|
||||
@@ -1122,6 +1142,7 @@ char *timestring(time_t t)
|
||||
{
|
||||
static char TimeBuf[200];
|
||||
struct tm *tm = localtime(&t);
|
||||
char *p;
|
||||
|
||||
#ifdef HAVE_STRFTIME
|
||||
strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
@@ -1129,14 +1150,12 @@ char *timestring(time_t t)
|
||||
strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
|
||||
#endif
|
||||
|
||||
if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
|
||||
TimeBuf[strlen(TimeBuf)-1] = 0;
|
||||
}
|
||||
if ((p = strchr(TimeBuf, '\n')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
return(TimeBuf);
|
||||
return TimeBuf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sleep for a specified number of milliseconds.
|
||||
*
|
||||
@@ -1165,11 +1184,8 @@ int msleep(int t)
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two file modification times are equivalent (either
|
||||
* exact or in the modification timestamp window established by
|
||||
* --modify-window).
|
||||
/* Determine if two time_t values are equivalent (either exact, or in
|
||||
* the modification timestamp window established by --modify-window).
|
||||
*
|
||||
* @retval 0 if the times should be treated as the same
|
||||
*
|
||||
@@ -1177,7 +1193,7 @@ int msleep(int t)
|
||||
*
|
||||
* @retval -1 if the 2nd is later
|
||||
**/
|
||||
int cmp_modtime(time_t file1, time_t file2)
|
||||
int cmp_time(time_t file1, time_t file2)
|
||||
{
|
||||
if (file2 > file1) {
|
||||
if (file2 - file1 <= modify_window)
|
||||
@@ -1223,7 +1239,6 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define MALLOC_MAX 0x40000000
|
||||
|
||||
void *_new_array(unsigned int size, unsigned long num)
|
||||
@@ -1349,3 +1364,95 @@ uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2)
|
||||
|
||||
return a[len2-1];
|
||||
}
|
||||
|
||||
#define BB_SLOT_SIZE (16*1024) /* Desired size in bytes */
|
||||
#define BB_PER_SLOT_BITS (BB_SLOT_SIZE * 8) /* Number of bits per slot */
|
||||
#define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */
|
||||
|
||||
struct bitbag {
|
||||
uint32 **bits;
|
||||
int slot_cnt;
|
||||
};
|
||||
|
||||
struct bitbag *bitbag_create(int max_ndx)
|
||||
{
|
||||
struct bitbag *bb = new(struct bitbag);
|
||||
bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS;
|
||||
|
||||
if (!(bb->bits = (uint32**)calloc(bb->slot_cnt, sizeof (uint32*))))
|
||||
out_of_memory("bitbag_create");
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
void bitbag_set_bit(struct bitbag *bb, int ndx)
|
||||
{
|
||||
int slot = ndx / BB_PER_SLOT_BITS;
|
||||
ndx %= BB_PER_SLOT_BITS;
|
||||
|
||||
if (!bb->bits[slot]) {
|
||||
if (!(bb->bits[slot] = (uint32*)calloc(BB_PER_SLOT_INTS, 4)))
|
||||
out_of_memory("bitbag_set_bit");
|
||||
}
|
||||
|
||||
bb->bits[slot][ndx/32] |= 1u << (ndx % 32);
|
||||
}
|
||||
|
||||
#if 0 /* not needed yet */
|
||||
void bitbag_clear_bit(struct bitbag *bb, int ndx)
|
||||
{
|
||||
int slot = ndx / BB_PER_SLOT_BITS;
|
||||
ndx %= BB_PER_SLOT_BITS;
|
||||
|
||||
if (!bb->bits[slot])
|
||||
return;
|
||||
|
||||
bb->bits[slot][ndx/32] &= ~(1u << (ndx % 32));
|
||||
}
|
||||
|
||||
int bitbag_check_bit(struct bitbag *bb, int ndx)
|
||||
{
|
||||
int slot = ndx / BB_PER_SLOT_BITS;
|
||||
ndx %= BB_PER_SLOT_BITS;
|
||||
|
||||
if (!bb->bits[slot])
|
||||
return 0;
|
||||
|
||||
return bb->bits[slot][ndx/32] & (1u << (ndx % 32)) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call this with -1 to start checking from 0. Returns -1 at the end. */
|
||||
int bitbag_next_bit(struct bitbag *bb, int after)
|
||||
{
|
||||
uint32 bits, mask;
|
||||
int i, ndx = after + 1;
|
||||
int slot = ndx / BB_PER_SLOT_BITS;
|
||||
ndx %= BB_PER_SLOT_BITS;
|
||||
|
||||
mask = (1u << (ndx % 32)) - 1;
|
||||
for (i = ndx / 32; slot < bb->slot_cnt; slot++, i = mask = 0) {
|
||||
if (!bb->bits[slot])
|
||||
continue;
|
||||
for ( ; i < BB_PER_SLOT_INTS; i++, mask = 0) {
|
||||
if (!(bits = bb->bits[slot][i] & ~mask))
|
||||
continue;
|
||||
/* 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*BB_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... */
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
47
wildtest.c
47
wildtest.c
@@ -7,7 +7,7 @@
|
||||
#define WILD_TEST_ITERATIONS
|
||||
#include "lib/wildmatch.c"
|
||||
|
||||
#include "popt.h"
|
||||
#include <popt.h>
|
||||
|
||||
#ifdef COMPARE_WITH_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
@@ -20,10 +20,16 @@ int wildmatch_errors = 0;
|
||||
typedef char bool;
|
||||
|
||||
int output_iterations = 0;
|
||||
int explode_mod = 0;
|
||||
int empties_mod = 0;
|
||||
int empty_at_start = 0;
|
||||
int empty_at_end = 0;
|
||||
|
||||
static struct poptOption long_options[] = {
|
||||
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
|
||||
{"iterations", 'i', POPT_ARG_NONE, &output_iterations, 0, 0, 0},
|
||||
{"empties", 'e', POPT_ARG_STRING, 0, 'e', 0, 0},
|
||||
{"explode", 'x', POPT_ARG_INT, &explode_mod, 0, 0, 0},
|
||||
{0,0,0,0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -40,7 +46,28 @@ run_test(int line, bool matches, bool same_as_fnmatch,
|
||||
same_as_fnmatch = 0; /* Get rid of unused-variable compiler warning. */
|
||||
#endif
|
||||
|
||||
matched = wildmatch(pattern, text);
|
||||
if (explode_mod) {
|
||||
char buf[MAXPATHLEN*2], *texts[MAXPATHLEN];
|
||||
int pos = 0, cnt = 0, ndx = 0, len = strlen(text);
|
||||
|
||||
if (empty_at_start)
|
||||
texts[ndx++] = "";
|
||||
/* An empty string must turn into at least one empty array item. */
|
||||
while (1) {
|
||||
texts[ndx] = buf + ndx * (explode_mod + 1);
|
||||
strlcpy(texts[ndx++], text + pos, explode_mod + 1);
|
||||
if (pos + explode_mod >= len)
|
||||
break;
|
||||
pos += explode_mod;
|
||||
if (!(++cnt % empties_mod))
|
||||
texts[ndx++] = "";
|
||||
}
|
||||
if (empty_at_end)
|
||||
texts[ndx++] = "";
|
||||
texts[ndx] = NULL;
|
||||
matched = wildmatch_array(pattern, (const char**)texts, 0);
|
||||
} else
|
||||
matched = wildmatch(pattern, text);
|
||||
#ifdef COMPARE_WITH_FNMATCH
|
||||
fn_matched = !fnmatch(pattern, text, flags);
|
||||
#endif
|
||||
@@ -66,6 +93,7 @@ int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char buf[2048], *s, *string[2], *end[2];
|
||||
const char *arg;
|
||||
FILE *fp;
|
||||
int opt, line, i, flag[2];
|
||||
poptContext pc = poptGetContext("wildtest", argc, (const char**)argv,
|
||||
@@ -73,6 +101,16 @@ main(int argc, char **argv)
|
||||
|
||||
while ((opt = poptGetNextOpt(pc)) != -1) {
|
||||
switch (opt) {
|
||||
case 'e':
|
||||
arg = poptGetOptArg(pc);
|
||||
empties_mod = atoi(arg);
|
||||
if (strchr(arg, 's'))
|
||||
empty_at_start = 1;
|
||||
if (strchr(arg, 'e'))
|
||||
empty_at_end = 1;
|
||||
if (!explode_mod)
|
||||
explode_mod = 1024;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: %s\n",
|
||||
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
|
||||
@@ -81,9 +119,12 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (explode_mod && !empties_mod)
|
||||
empties_mod = 1024;
|
||||
|
||||
argv = (char**)poptGetArgs(pc);
|
||||
if (!argv || argv[1]) {
|
||||
fprintf(stderr, "Usage: wildtest TESTFILE\n");
|
||||
fprintf(stderr, "Usage: wildtest [OPTIONS] TESTFILE\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
0 1 bar/baz/foo */foo
|
||||
0 0 foo/bar/baz **/bar*
|
||||
1 1 deep/foo/bar/baz **/bar/*
|
||||
0 1 deep/foo/bar/baz/ **/bar/*
|
||||
1 1 deep/foo/bar/baz/ **/bar/**
|
||||
0 1 deep/foo/bar **/bar/*
|
||||
1 1 deep/foo/bar/ **/bar/**
|
||||
1 1 foo/bar/baz **/bar**
|
||||
1 1 foo/bar/baz/x */bar/**
|
||||
0 0 deep/foo/bar/baz/x */bar/**
|
||||
|
||||
Reference in New Issue
Block a user