mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
641 Commits
v2.6.9
...
v3.0.0pre2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44ae628c59 | ||
|
|
44a7ba4587 | ||
|
|
44c4492acf | ||
|
|
609e6dda6b | ||
|
|
3f30927214 | ||
|
|
ae11e4ee2d | ||
|
|
b61665d5b6 | ||
|
|
38943d29d3 | ||
|
|
ff0284ddc4 | ||
|
|
3f65576881 | ||
|
|
3caf40356d | ||
|
|
26bbb6aa4b | ||
|
|
bf66c2da14 | ||
|
|
65f6b6b0ef | ||
|
|
983f647c7e | ||
|
|
14dfad3873 | ||
|
|
215465713b | ||
|
|
6be5ac61bd | ||
|
|
90c71caeb3 | ||
|
|
d46b5646c6 | ||
|
|
da564b51a1 | ||
|
|
f89617f7f2 | ||
|
|
0f8984ed78 | ||
|
|
306847ea67 | ||
|
|
d4eba300c9 | ||
|
|
dd589118d0 | ||
|
|
f92e15efd5 | ||
|
|
4f3c1df6c3 | ||
|
|
eb8f5c74e1 | ||
|
|
a960239f39 | ||
|
|
5621e5105a | ||
|
|
a1d2685b08 | ||
|
|
0f6b4909db | ||
|
|
b0ca7d2500 | ||
|
|
7ed6bc53b9 | ||
|
|
f57ab2f718 | ||
|
|
5ebb7935d2 | ||
|
|
c50a9076e1 | ||
|
|
d417c51669 | ||
|
|
5b934f5133 | ||
|
|
49ea69b3ff | ||
|
|
578219bed5 | ||
|
|
2e4a3d17b4 | ||
|
|
b4b24520f6 | ||
|
|
13710874ce | ||
|
|
7341ee2dfd | ||
|
|
e0cfd15bcc | ||
|
|
5a47354882 | ||
|
|
f5b532b144 | ||
|
|
c0dba635ba | ||
|
|
e1ac7791fe | ||
|
|
5b3f6a2730 | ||
|
|
f203266889 | ||
|
|
21914d8135 | ||
|
|
200aec7db4 | ||
|
|
a15c4b38b5 | ||
|
|
40e383765a | ||
|
|
5441088298 | ||
|
|
d0a6cdb62e | ||
|
|
19531e1f74 | ||
|
|
6f0805f564 | ||
|
|
6191429b50 | ||
|
|
89b76bac1f | ||
|
|
0758b2db30 | ||
|
|
74db1f1498 | ||
|
|
4f802c6637 | ||
|
|
33a04593ee | ||
|
|
6303f9a25f | ||
|
|
3932c42373 | ||
|
|
bc5df0f4e6 | ||
|
|
4b163f00c2 | ||
|
|
f07992739a | ||
|
|
c605c2cdbd | ||
|
|
1b42f628f4 | ||
|
|
5dafe360de | ||
|
|
6619d5fcc1 | ||
|
|
b960483e99 | ||
|
|
dd4a039515 | ||
|
|
229554084d | ||
|
|
4a1edb63dd | ||
|
|
3170b20967 | ||
|
|
d34cd639fc | ||
|
|
236df01b15 | ||
|
|
21cafc50cc | ||
|
|
de80679b67 | ||
|
|
27999abab4 | ||
|
|
82f37486a1 | ||
|
|
7820fa949f | ||
|
|
2ac9793064 | ||
|
|
a4453606cc | ||
|
|
71605b0f4d | ||
|
|
ba525f770c | ||
|
|
2509753fd3 | ||
|
|
5688c74d25 | ||
|
|
2ac081ff60 | ||
|
|
5d3e5f641d | ||
|
|
a0f29ed824 | ||
|
|
0b515981fc | ||
|
|
2e8259bb0b | ||
|
|
d274524317 | ||
|
|
71845bd2a0 | ||
|
|
bdd53557a8 | ||
|
|
d6ca255c21 | ||
|
|
2dc7b91dd2 | ||
|
|
288b12eefe | ||
|
|
f7d6dce6c8 | ||
|
|
48a481c4d0 | ||
|
|
8db8eacbdd | ||
|
|
e8e9e12c3a | ||
|
|
6e6daf5ac6 | ||
|
|
e73eed8563 | ||
|
|
da1319128a | ||
|
|
f2179fd370 | ||
|
|
969cdffbea | ||
|
|
3b7bcaaf34 | ||
|
|
4abe379c05 | ||
|
|
c980db5f08 | ||
|
|
c35d6e3522 | ||
|
|
044dc29307 | ||
|
|
7a4addaa74 | ||
|
|
f7e5068d94 | ||
|
|
67b8f3dfe7 | ||
|
|
95a44066da | ||
|
|
7909e65f83 | ||
|
|
f74a3d813b | ||
|
|
ac59386027 | ||
|
|
73a649b7cb | ||
|
|
9b49704959 | ||
|
|
ffbffc647b | ||
|
|
968061bb65 | ||
|
|
c47e3ee1b6 | ||
|
|
549a3efbb7 | ||
|
|
accf8d12bc | ||
|
|
0eeb9f5481 | ||
|
|
7b46e30fd4 | ||
|
|
35c8fd761f | ||
|
|
ba2d43d702 | ||
|
|
29349024c4 | ||
|
|
d108e04f38 | ||
|
|
d4d6646aae | ||
|
|
cf2d26656d | ||
|
|
7918f24405 | ||
|
|
9544261a45 | ||
|
|
354c9da60d | ||
|
|
626065702f | ||
|
|
9863bdbc93 | ||
|
|
83135e8f6a | ||
|
|
369233927c | ||
|
|
7e4b6b7bc4 | ||
|
|
a2dc4d687b | ||
|
|
a4431563e8 | ||
|
|
fbd91cae0c | ||
|
|
eb7a6e09cb | ||
|
|
9889a34bf2 | ||
|
|
8e1e60e98f | ||
|
|
f9998046a3 | ||
|
|
07bbf8703f | ||
|
|
77502cbade | ||
|
|
936fa865e1 | ||
|
|
2f188c8d96 | ||
|
|
83f5394810 | ||
|
|
24d677fc16 | ||
|
|
65a22a5ff7 | ||
|
|
a0f70237f5 | ||
|
|
4eff3051a0 | ||
|
|
e208631a5b | ||
|
|
b553a3dd20 | ||
|
|
e5f1a96ff8 | ||
|
|
eb7e7b2499 | ||
|
|
3caafdfd2f | ||
|
|
26ac181223 | ||
|
|
7fa60281bf | ||
|
|
73f2fa8189 | ||
|
|
75f162e46f | ||
|
|
1d2ca00703 | ||
|
|
4d91a5f8f4 | ||
|
|
61cb031ca4 | ||
|
|
ff0c27c926 | ||
|
|
d1d0a7051f | ||
|
|
444f9f7b04 | ||
|
|
411c04f06f | ||
|
|
5d935dce63 | ||
|
|
b88f6fe7e5 | ||
|
|
e6109f496c | ||
|
|
836ce36a4f | ||
|
|
35da2ec35a | ||
|
|
7b9598b2d5 | ||
|
|
4a4622bbe5 | ||
|
|
c9ec460807 | ||
|
|
79cd0c7fa4 | ||
|
|
de8c8b28c0 | ||
|
|
569e6f432b | ||
|
|
0d585188f9 | ||
|
|
34ca58d440 | ||
|
|
9c528e2935 | ||
|
|
2b967218eb | ||
|
|
6e058b4b60 | ||
|
|
b1e436ec17 | ||
|
|
4319cc56d8 | ||
|
|
952ae75138 | ||
|
|
4d745d3cf5 | ||
|
|
8798be8e63 | ||
|
|
42b06481c3 | ||
|
|
dbe287b701 | ||
|
|
8e3b627d07 | ||
|
|
809724d7e2 | ||
|
|
8e41b68e8f | ||
|
|
dc77edf218 | ||
|
|
65ba6af61b | ||
|
|
83d5e90054 | ||
|
|
e434f0ebfe | ||
|
|
a08979d564 | ||
|
|
252af65bb4 | ||
|
|
d048c2f225 | ||
|
|
9b9d5f89b3 | ||
|
|
e5bf3b5855 | ||
|
|
6755a7d742 | ||
|
|
5459e693a3 | ||
|
|
24108eb854 | ||
|
|
4635fb9995 | ||
|
|
9decb4d2ef | ||
|
|
b3b326016a | ||
|
|
4bde45f60e | ||
|
|
4fd842f98d | ||
|
|
f92f5b166e | ||
|
|
9b25ef35bd | ||
|
|
7c73536c25 | ||
|
|
33cbd577ad | ||
|
|
524eaa8245 | ||
|
|
9742b386b3 | ||
|
|
8b498b9f1a | ||
|
|
c04af69701 | ||
|
|
f87fb190b3 | ||
|
|
a21e72c3e6 | ||
|
|
1c4ffe64db | ||
|
|
abdcb21a7a | ||
|
|
f5ba7bfbb6 | ||
|
|
676e604135 | ||
|
|
3fac8ca8d1 | ||
|
|
33766a8daa | ||
|
|
e3d27df444 | ||
|
|
6aa27a7ce5 | ||
|
|
47cffb77de | ||
|
|
565a340b0a | ||
|
|
f45b64d8dd | ||
|
|
56ce72c447 | ||
|
|
898fab2577 | ||
|
|
0e5dd89866 | ||
|
|
79028af116 | ||
|
|
a572e12675 | ||
|
|
c8e8394615 | ||
|
|
8487f9cf29 | ||
|
|
d750be6ad8 | ||
|
|
0bb8616535 | ||
|
|
1faa1a6da9 | ||
|
|
b5ae4e25c2 | ||
|
|
3d0a159d96 | ||
|
|
8ea07c0030 | ||
|
|
59fd2a5e7d | ||
|
|
ae87c43452 | ||
|
|
f1599b9ef2 | ||
|
|
ee83e1bd4d | ||
|
|
7455467c17 | ||
|
|
19395697b9 | ||
|
|
7787579ad4 | ||
|
|
58a37ed34a | ||
|
|
fe8d61e5d5 | ||
|
|
87b0cc726b | ||
|
|
4504b2259f | ||
|
|
cf1b4969b9 | ||
|
|
434e77193c | ||
|
|
858d45f160 | ||
|
|
63186ec077 | ||
|
|
dfcb386569 | ||
|
|
d15f2ff0cf | ||
|
|
c395acd804 | ||
|
|
030820d5dc | ||
|
|
043ef55b22 | ||
|
|
a30dcbc0a8 | ||
|
|
02f0227e87 | ||
|
|
142a5e7b8b | ||
|
|
fdfc67406c | ||
|
|
fb7b9ddcb1 | ||
|
|
4ade505c7e | ||
|
|
1564cd5a87 | ||
|
|
33233b4900 | ||
|
|
d6b422a61c | ||
|
|
ff2001b91b | ||
|
|
d858b27400 | ||
|
|
1874f7e2e1 | ||
|
|
377d22ab9f | ||
|
|
4f3797c7e2 | ||
|
|
6b5a8f80fc | ||
|
|
bf10faa9dc | ||
|
|
548ca46fec | ||
|
|
e8c64ffdc7 | ||
|
|
0eb05245f1 | ||
|
|
0156c7842d | ||
|
|
1acb8f5119 | ||
|
|
76e754a0fd | ||
|
|
e7f905accb | ||
|
|
a9a8bc962c | ||
|
|
a6e7b97868 | ||
|
|
1befb74b13 | ||
|
|
8f3335a18c | ||
|
|
505c0579f7 | ||
|
|
a430691df1 | ||
|
|
332cf6df7c | ||
|
|
3f7afe7ec1 | ||
|
|
8fc4033ef0 | ||
|
|
ef35abb2b7 | ||
|
|
0b68d6b6f4 | ||
|
|
f1271537a4 | ||
|
|
b13505da1d | ||
|
|
7ea6ea98c8 | ||
|
|
d1798a2fda | ||
|
|
e911ff75d6 | ||
|
|
49f7162e7d | ||
|
|
3bb88b4388 | ||
|
|
b3fbe3ce35 | ||
|
|
9557eabaa7 | ||
|
|
acac1f5c6f | ||
|
|
3427355422 | ||
|
|
cbf626fd62 | ||
|
|
1c702303eb | ||
|
|
9a234269ed | ||
|
|
db9c9e2766 | ||
|
|
9439c0cb5a | ||
|
|
2ed790f354 | ||
|
|
486f8cd1ab | ||
|
|
875a13b42c | ||
|
|
719522b9bd | ||
|
|
753849fdbc | ||
|
|
bb25779de7 | ||
|
|
348d54d6d1 | ||
|
|
4471d9e570 | ||
|
|
19d4cac996 | ||
|
|
e4c877cf70 | ||
|
|
f14b3ef430 | ||
|
|
f3c93b1761 | ||
|
|
a72ba0cfac | ||
|
|
ba59bd68fc | ||
|
|
1c60d21947 | ||
|
|
473feecff3 | ||
|
|
351e23ad8e | ||
|
|
f31514adb7 | ||
|
|
2fcc265c2f | ||
|
|
b58e40332f | ||
|
|
a217c45359 | ||
|
|
764782662d | ||
|
|
4b24f4a2b5 | ||
|
|
c64ff141b8 | ||
|
|
1b896f8d1e | ||
|
|
01894cf01f | ||
|
|
16edf86595 | ||
|
|
1c53e5171c | ||
|
|
63d83e9477 | ||
|
|
5463453489 | ||
|
|
108133689d | ||
|
|
46ad63b7cf | ||
|
|
dbb20f6bc0 | ||
|
|
25c2a6ac0e | ||
|
|
161fba6903 | ||
|
|
55edf18c42 | ||
|
|
a0456b9c46 | ||
|
|
1a515b494b | ||
|
|
33cd9ad54b | ||
|
|
896f046f79 | ||
|
|
b9d5eea5c6 | ||
|
|
5275029d11 | ||
|
|
271aeaa49e | ||
|
|
91763a9c2f | ||
|
|
18438f0bac | ||
|
|
057f649fc9 | ||
|
|
88467ec444 | ||
|
|
1b897d50a9 | ||
|
|
d4a013edb7 | ||
|
|
545584cb9a | ||
|
|
e5abce8e0d | ||
|
|
3060ca8d42 | ||
|
|
ab14d01a0e | ||
|
|
987838fd2c | ||
|
|
6d4e718f5f | ||
|
|
1c3344a105 | ||
|
|
085e2fd588 | ||
|
|
f41152d393 | ||
|
|
d0c59b0e88 | ||
|
|
f49c837651 | ||
|
|
c12895089c | ||
|
|
27122338dc | ||
|
|
d762dfe94b | ||
|
|
c4750c2a07 | ||
|
|
3831f06319 | ||
|
|
be91bd81b8 | ||
|
|
2a40b503c0 | ||
|
|
ba2133d6ad | ||
|
|
4f47fec04d | ||
|
|
ab3d6c6025 | ||
|
|
121bfb2b4d | ||
|
|
100018b7cd | ||
|
|
1ff66d4c68 | ||
|
|
87a34ce56a | ||
|
|
04c722d5e0 | ||
|
|
7730114b30 | ||
|
|
7a2fa0c2d3 | ||
|
|
4eeaa16253 | ||
|
|
8dca155fca | ||
|
|
2a5df86299 | ||
|
|
3ea6e0e7a1 | ||
|
|
051ad69634 | ||
|
|
744e63fb2a | ||
|
|
cc7b86bf9b | ||
|
|
8c18ebe81d | ||
|
|
33689f4803 | ||
|
|
424d369179 | ||
|
|
d0221f1d2b | ||
|
|
3be97bf931 | ||
|
|
4afab31607 | ||
|
|
be21e29c35 | ||
|
|
c5b6e57a13 | ||
|
|
ca947dea3e | ||
|
|
2aea85ab54 | ||
|
|
05a41409b1 | ||
|
|
7a28d18448 | ||
|
|
1e05b590c4 | ||
|
|
ce5fddc3ed | ||
|
|
fd3f5af2aa | ||
|
|
dde5b77226 | ||
|
|
f845ef7dec | ||
|
|
9ae7a2cddb | ||
|
|
8a65e0ce00 | ||
|
|
98b1689dcb | ||
|
|
012d1a01f5 | ||
|
|
d9f46544a3 | ||
|
|
42c6b13901 | ||
|
|
f1482c3391 | ||
|
|
5bb7348509 | ||
|
|
4c9d5fef07 | ||
|
|
5607803376 | ||
|
|
76e0a49efe | ||
|
|
76a1013cc6 | ||
|
|
496c809f8c | ||
|
|
3ac830b9f9 | ||
|
|
f3d6d4800b | ||
|
|
8ef246e0b5 | ||
|
|
c7e6f84f89 | ||
|
|
fe04532ad2 | ||
|
|
e4b619b46d | ||
|
|
9ec3828b03 | ||
|
|
e0e3203156 | ||
|
|
edb977215b | ||
|
|
18233a170e | ||
|
|
283887d777 | ||
|
|
c2f0e4d965 | ||
|
|
8576397c3e | ||
|
|
c09af06d0c | ||
|
|
ded73ed90f | ||
|
|
f335eb1f83 | ||
|
|
7afa34fd27 | ||
|
|
1f56188f8c | ||
|
|
3162ea6f67 | ||
|
|
327c559aff | ||
|
|
99effefc81 | ||
|
|
e8dad39518 | ||
|
|
09a54c399c | ||
|
|
9586e59370 | ||
|
|
ce455b03e7 | ||
|
|
a39da29ac5 | ||
|
|
794a0b6c25 | ||
|
|
1b81f797a2 | ||
|
|
889ae39d7a | ||
|
|
5f4e991c70 | ||
|
|
c96f6eb584 | ||
|
|
e10664c5e8 | ||
|
|
99a957d3f4 | ||
|
|
658a63694b | ||
|
|
30e50494bb | ||
|
|
719985cb9c | ||
|
|
2d2414f39e | ||
|
|
edb4ba5fdb | ||
|
|
007996b40d | ||
|
|
dbd9ea3e5a | ||
|
|
2ef0340517 | ||
|
|
9d737ecb7a | ||
|
|
bd6edd3fa2 | ||
|
|
6eee13cf58 | ||
|
|
9602b5cfbd | ||
|
|
48ffc11e9c | ||
|
|
5a3e9ff608 | ||
|
|
aac5cab80b | ||
|
|
a3e18c763a | ||
|
|
403dbc1377 | ||
|
|
5b30412c68 | ||
|
|
d5833800a8 | ||
|
|
8d3a785fa5 | ||
|
|
3a5a7de6c9 | ||
|
|
c58c1dc446 | ||
|
|
eefe189e1d | ||
|
|
f05c801194 | ||
|
|
c905bf37f6 | ||
|
|
8cae71ebc3 | ||
|
|
14d776ff0c | ||
|
|
c7565dad84 | ||
|
|
b7cfb9e2c0 | ||
|
|
0d152437df | ||
|
|
6aef83c97d | ||
|
|
225aeca346 | ||
|
|
0a62f5f382 | ||
|
|
234844915e | ||
|
|
263d3bfb40 | ||
|
|
bf466c0f82 | ||
|
|
8b58407586 | ||
|
|
64119c792d | ||
|
|
8388e011ae | ||
|
|
0fddbd8a09 | ||
|
|
badb8c24b9 | ||
|
|
bfd3137246 | ||
|
|
6de0d06259 | ||
|
|
89d730a098 | ||
|
|
18979194cf | ||
|
|
aadc84d359 | ||
|
|
9d155ecd12 | ||
|
|
60af946576 | ||
|
|
ca0e8296bc | ||
|
|
c4a28da3ad | ||
|
|
20319fd9ed | ||
|
|
01d29d7b02 | ||
|
|
1183260426 | ||
|
|
07613def0a | ||
|
|
c2a608d9f1 | ||
|
|
49b86442ff | ||
|
|
4785cd43d1 | ||
|
|
e238c9977d | ||
|
|
b37b7c9949 | ||
|
|
f7d7fb381d | ||
|
|
3481bdf493 | ||
|
|
d365e22967 | ||
|
|
d02363609a | ||
|
|
1e1ca25343 | ||
|
|
a2ebbffca7 | ||
|
|
0395130c06 | ||
|
|
b8c167e804 | ||
|
|
17026f2741 | ||
|
|
112d728f48 | ||
|
|
96293cf991 | ||
|
|
f0fbf1d670 | ||
|
|
7a821d518b | ||
|
|
663b2857eb | ||
|
|
155d9206a4 | ||
|
|
6b2a3d5de6 | ||
|
|
82ad07c418 | ||
|
|
d144e43bb3 | ||
|
|
d2aee174e6 | ||
|
|
20f0d0f9b9 | ||
|
|
b675ba6f79 | ||
|
|
d1c178dd53 | ||
|
|
d619ff1376 | ||
|
|
db0f7613e1 | ||
|
|
45d8bfe09e | ||
|
|
d521e1c2a1 | ||
|
|
4ea4acf17b | ||
|
|
3a993aa4bf | ||
|
|
c7871d9892 | ||
|
|
482f48cca9 | ||
|
|
36e6594dce | ||
|
|
e17883827b | ||
|
|
37a4386d2c | ||
|
|
fd0a130c14 | ||
|
|
5e77efaf41 | ||
|
|
b0cacef14b | ||
|
|
b20830b338 | ||
|
|
c63625d41a | ||
|
|
7de7b49f6c | ||
|
|
d0d0e41fd2 | ||
|
|
2a28dd32fd | ||
|
|
65e83e097c | ||
|
|
4f37559232 | ||
|
|
604dbf6d94 | ||
|
|
53593085cf | ||
|
|
eb0144d79b | ||
|
|
54b0dfa0f7 | ||
|
|
264042760b | ||
|
|
1e999f9f1b | ||
|
|
f9b66bc464 | ||
|
|
60d465dbdd | ||
|
|
3ebdd3c7fc | ||
|
|
f0fa8c6df2 | ||
|
|
9d33e6f7cf | ||
|
|
4a19c3b254 | ||
|
|
4743f0f41b | ||
|
|
0abe148fd9 | ||
|
|
39411fa876 | ||
|
|
662fd70b54 | ||
|
|
cd87e2f59a | ||
|
|
2c70847654 | ||
|
|
eaf895e6ef | ||
|
|
149a78e33f | ||
|
|
88897638a9 | ||
|
|
c575f8ce87 | ||
|
|
5303941021 | ||
|
|
c0f1e57b51 | ||
|
|
ccdb23bb90 | ||
|
|
146c2c368c | ||
|
|
60cc01a6c6 | ||
|
|
f5761a342b | ||
|
|
caf8299e2e | ||
|
|
c6fadc0ee1 | ||
|
|
2dc3db2a3e | ||
|
|
771d0add8f | ||
|
|
e5e85283a9 | ||
|
|
21068d8e87 | ||
|
|
4d2ea5a838 | ||
|
|
9ba53f26a3 | ||
|
|
3aeedbfd11 | ||
|
|
989b0b8802 | ||
|
|
b2e4811db2 | ||
|
|
b467495cd0 | ||
|
|
3b8ed84245 | ||
|
|
3a72cc2929 | ||
|
|
c202424a03 | ||
|
|
083f75ee42 | ||
|
|
45760f5f05 | ||
|
|
116a4769c1 | ||
|
|
1e4f5f6342 | ||
|
|
a19d285ae3 | ||
|
|
564782ba95 | ||
|
|
2dc7b8bd0e | ||
|
|
e0930845ce | ||
|
|
cf81788366 | ||
|
|
89a0e3a927 | ||
|
|
a8facdc090 | ||
|
|
c5e29261f3 | ||
|
|
1acb2e15b4 | ||
|
|
06898c80d9 | ||
|
|
684576ff45 | ||
|
|
574a24a2ec | ||
|
|
9775d6ab66 | ||
|
|
2b916250d8 | ||
|
|
2955529bb4 | ||
|
|
d094b5eb3c | ||
|
|
bc93ee842f |
@@ -6,8 +6,7 @@ config.cache
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
conftest.c
|
||||
conftest.log
|
||||
conftest*
|
||||
dox
|
||||
getgroups
|
||||
gmon.out
|
||||
@@ -16,10 +15,11 @@ shconfig
|
||||
testdir
|
||||
tests-dont-exist
|
||||
testtmp
|
||||
testtmp.*
|
||||
tls
|
||||
trimslash
|
||||
t_unsafe
|
||||
wildtest
|
||||
getfsdev
|
||||
.rsync-filter
|
||||
mkrounding
|
||||
rounding.h
|
||||
|
||||
848
COPYING
848
COPYING
@@ -1,285 +1,626 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
0. Definitions.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
1. Source Code.
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
14. Revised Versions of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
NO WARRANTY
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
@@ -304,37 +645,30 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
49
Makefile.in
49
Makefile.in
@@ -26,27 +26,29 @@ VERSION=@VERSION@
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
|
||||
lib/permstring.o lib/pool_alloc.o @LIBOBJS@
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h lib/pool_alloc.h
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
|
||||
lib/permstring.o lib/pool_alloc.o lib/sysacls.o lib/sysxattrs.o @LIBOBJS@
|
||||
ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
|
||||
zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.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 chmod.o
|
||||
OBJS1=flist.o 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 io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
|
||||
fileio.o batch.o clientname.o chmod.o acls.o xattrs.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 \
|
||||
popt/popthelp.o popt/poptparse.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
|
||||
|
||||
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o
|
||||
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
|
||||
|
||||
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test
|
||||
|
||||
# Objects for CHECK_PROGS to clean
|
||||
CHECK_OBJS=getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
|
||||
@@ -74,6 +76,16 @@ rsync$(EXEEXT): $(OBJS)
|
||||
|
||||
$(OBJS): $(HEADERS)
|
||||
|
||||
flist.o: rounding.h
|
||||
|
||||
rounding.h: mkrounding$(EXEEXT)
|
||||
./mkrounding$(EXEEXT) >rounding.h
|
||||
|
||||
mkrounding$(EXEEXT): mkrounding.c rsync.h
|
||||
@sed '1,/^struct file_struct/d; /^}/,$$d' <$(srcdir)/rsync.h >mkrounding.h
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -I. $(srcdir)/mkrounding.c
|
||||
@rm mkrounding.h
|
||||
|
||||
tls$(EXEEXT): $(TLS_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
|
||||
|
||||
@@ -101,7 +113,8 @@ proto:
|
||||
cd $(srcdir) && $(MAKE) -f prepare-source.mak proto.h
|
||||
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
|
||||
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
|
||||
mkrounding mkrounding.h rounding.h
|
||||
|
||||
cleantests:
|
||||
rm -rf ./testtmp*
|
||||
@@ -131,7 +144,6 @@ finddead:
|
||||
|
||||
test: check
|
||||
|
||||
|
||||
# There seems to be no standard way to specify some variables as
|
||||
# exported from a Makefile apart from listing them like this.
|
||||
|
||||
@@ -142,18 +154,27 @@ test: check
|
||||
# catch Bash-isms earlier even if we're running on GNU. Of course, we
|
||||
# might lose in the future where POSIX diverges from old sh.
|
||||
|
||||
check: all $(CHECK_PROGS)
|
||||
check: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
|
||||
|
||||
check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29
|
||||
|
||||
wildtest.o: wildtest.c lib/wildmatch.c rsync.h
|
||||
wildtest$(EXEEXT): wildtest.o lib/compat.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o @BUILD_POPT@ $(LIBS)
|
||||
wildtest$(EXEEXT): wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ $(LIBS)
|
||||
|
||||
testsuite/chown-fake.test:
|
||||
ln -s chown.test $(srcdir)/testsuite/chown-fake.test
|
||||
|
||||
testsuite/devices-fake.test:
|
||||
ln -s devices.test $(srcdir)/testsuite/devices-fake.test
|
||||
|
||||
# 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,
|
||||
# if you want.
|
||||
|
||||
installcheck: $(CHECK_PROGS)
|
||||
installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
|
||||
|
||||
# TODO: Add 'dist' target; need to know which files will be included
|
||||
|
||||
316
NEWS
316
NEWS
@@ -1,158 +1,232 @@
|
||||
NEWS for rsync 2.6.9 (6 Nov 2006)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.8:
|
||||
NEWS for rsync 3.0.0 (UNRELEASED)
|
||||
Protocol: 30 (changed)
|
||||
Changes since 2.6.9:
|
||||
|
||||
NOTABLE CHANGES IN BEHAVIOR:
|
||||
|
||||
- The handling of implied directories when using --relative has changed to
|
||||
send them as directories (e.g. no implied dir is ever sent as a symlink).
|
||||
This avoids unexpected behavior and should not adversely affect most
|
||||
people. If you're one of those rare people who relied upon having an
|
||||
implied dir be duplicated as a symlink, you should specify the transfer
|
||||
of the symlink and the transfer of the referent directory as separate
|
||||
args. (See also --keep-dirlinks and --no-implied-dirs.)
|
||||
|
||||
- Requesting a remote file list without specifying -r (--recursive) now
|
||||
sends the -d (--dirs) option to the remote rsync rather than sending -r
|
||||
along with an extra exclude of /*/*. If the remote rsync does not
|
||||
understand the -d option (i.e. it is 2.6.3 or older), you will need to
|
||||
either turn off -d (--no-d), or specify -r --exclude='/*/*' manually.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- If rsync is interrupted via a handled signal (such as SIGINT), it will
|
||||
once again clean-up its temp file from the destination dir.
|
||||
- Fixed the output of -ii when combined with one of the --*-dest options:
|
||||
it now itemizes all the items, not just the changed ones.
|
||||
|
||||
- Fixed an overzealous sanitizing bug in the handling of the --link-dest,
|
||||
--copy-dest, and --compare-dest options to a daemon without chroot: if
|
||||
the copy's destination dir is deeper than the top of the module's path,
|
||||
these options now accept a safe number of parent-dir (../) references
|
||||
(since these options are relative to the destination dir). The old code
|
||||
incorrectly chopped off all "../" prefixes for these options, no matter
|
||||
how deep the destination directory was in the module's hierarchy.
|
||||
- Made the output of all file types consistent when using a --*-dest
|
||||
option. Prior versions used to output too many creation events for
|
||||
matching items.
|
||||
|
||||
- Fixed a bug where a deferred info/error/log message could get sent
|
||||
directly to the sender instead of being handled by rwrite() in the
|
||||
generator. This fixes an "unexpected tag 3" fatal error, and should
|
||||
also fix a potential problem where a deferred info/error message from
|
||||
the receiver might bypass the log file and get sent only to the client
|
||||
process. (These problems could only affect an rsync daemon that was
|
||||
receiving files.)
|
||||
- The code that waits for a child pid now handles being interrupted by a
|
||||
signal. This fixes a problem with the pre-xfer exec function not being
|
||||
able to get the exit status from the script.
|
||||
|
||||
- Fixed a bug when --inplace was combined with a --*-dest option and we
|
||||
update a file's data using an alternate basis file. The code now
|
||||
notices that it needs to copy the matching data from the basis file
|
||||
instead of (wrongly) assuming that it was already present in the file.
|
||||
- A negated filter rule (with a '!' modifier) no longer loses the negation
|
||||
when sending the filter rules to the remote rsync.
|
||||
|
||||
- Fixed a bug where using --dry-run with a --*-dest option with a path
|
||||
relative to a directory that does not yet exist: the affected option
|
||||
gets its proper path value so that the output of the dry-run is right.
|
||||
- Fixed a problem with the --out-format (aka --log-format) option %f: it
|
||||
would output superfluous directory information for a non-daemon rsync.
|
||||
|
||||
- Fixed a bug in the %f logfile escape when receiving files: the
|
||||
destination path is now included in the output (e.g. you can now tell
|
||||
when a user specifies a subdir inside a module).
|
||||
- Fixed a problem with -vv (double --verbose) and --stats when "pushing"
|
||||
files (which includes local copies). Version 2.6.9 would complete the
|
||||
copy, but exit with an error when the receiver output its memory stats.
|
||||
|
||||
- If the receiving side fails to create a directory, it will now skip
|
||||
trying to update everything that is inside that directory.
|
||||
- If --password-file is used on a non-daemon transfer, rsync now complains
|
||||
and exits. This should help users figure out that they can't use this
|
||||
option to control a remote shell's password prompt.
|
||||
|
||||
- If --link-dest is specified with --checksum but without --times, rsync
|
||||
will now allow a hard-link to be created to a matching link-dest file
|
||||
even when the file's modify-time doesn't match the server's file.
|
||||
- Make sure that directory permissions of a newly-created destination
|
||||
directory are handled right when --perms is left off.
|
||||
|
||||
- The daemon now calls more timezone-using functions prior to doing a
|
||||
chroot. This should help some C libraries to generate proper timestamps
|
||||
from inside a chrooted daemon (and to not try to access /etc/timezone
|
||||
over and over again).
|
||||
- The itemized output of a newly-created destination directory is now
|
||||
output as a creation event, not a change event.
|
||||
|
||||
- Fixed a bug in the handling of an absolute --partial-dir=ABS_PATH option:
|
||||
it now deletes an alternate basis file from the partial-dir that was used
|
||||
to successfully update a destination file.
|
||||
- Improved --hard-link so that more corner cases are handled correctly
|
||||
when combined with options such as --link-dest and/or --ignore-existing.
|
||||
|
||||
- Fixed a bug in the handling of --delete-excluded when using a per-dir
|
||||
merge file: the merge file is now honored on the receiving side, and
|
||||
only its unqualified include/exclude commands are ignored (just as is
|
||||
done for global include/excludes).
|
||||
- The --append option no longer updates a file that has the same size.
|
||||
|
||||
- Fixed a recent bug where --delete was not working when transferring from
|
||||
the root (/) of the filesystem with --relative enabled.
|
||||
- Fixed a bug when combining --backup and --backup-dir with --inplace:
|
||||
any missing backup directories are now created.
|
||||
|
||||
- Fixed a recent bug where an --exclude='*' could affect the root (/) of
|
||||
the filesystem with --relative enabled.
|
||||
- Fixed a bug when using --backup and --inplace with --whole-file or
|
||||
--read-batch: backup files are actually created now.
|
||||
|
||||
- When --inplace creates a file, it is now created with owner read/write
|
||||
permissions (0600) instead of no permissions at all. This avoids a
|
||||
problem continuing a transfer that was interrupted (since --inplace
|
||||
will not update a file that has no write permissions).
|
||||
- Starting up an extra copy of an rsync daemon does not delete the pidfile
|
||||
for the running daemon -- if the pidfile exists, the extra program will
|
||||
exit with an error.
|
||||
|
||||
- If either --remove-source-files or --remove-sent-files is enabled and we
|
||||
are unable to remove the source file, rsync now outputs an error.
|
||||
- The daemon pidfile is checked and created sooner in the startup sequence.
|
||||
|
||||
- Fixed a bug in the daemon's "incoming chmod" rule: newly-created
|
||||
directories no longer get the 'F' (file) rules applied to them.
|
||||
|
||||
- Fixed an infinite loop bug when a filter rule was rejected due to being
|
||||
overly long.
|
||||
|
||||
- When the server receives a --partial-dir option from the client, it no
|
||||
longer runs the client-side code that adds an assumed filter rule (since
|
||||
the client will be sending us the rules in the usual manner, and they
|
||||
may have chosen to override the auto-added rule).
|
||||
- If a daemon module's "path" value is not an absolute pathname, the code
|
||||
now makes it absolute internally (making it work properly).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --log-file=FILE and --log-file-format=FORMAT options. These
|
||||
can be used to tell any rsync to output what it is doing to a log file.
|
||||
They work with a client rsync, a non-daemon server rsync (see the man
|
||||
page for instructions), and also allows the overriding of rsyncd.conf
|
||||
settings when starting a daemon.
|
||||
- A new incremental-recursion algorithm is now used when rsync is talking
|
||||
to another 3.x version. This starts the transfer going more quickly
|
||||
(before all the files have been found), and requires much less memory.
|
||||
See the --recursive option in the manpage for some restrictions.
|
||||
|
||||
- The --log-format option was renamed to be --out-format to avoid confusing
|
||||
it with affecting the log-file output. (The old option remains as an
|
||||
alias for the new to preserve backward compatibility.)
|
||||
- Lowered memory use in the non-incremental-recursion algorithm for typical
|
||||
option values (usually saving from 21-29 bytes per file).
|
||||
|
||||
- Made "log file" and "syslog facility" settable on a per-module basis in
|
||||
the daemon's config file.
|
||||
- The default --delete algorithm is now --delete-during when talking to a
|
||||
3.x rsync. This is a faster scan than using --delete-before (which is
|
||||
the default when talking to older rsync versions), and is compatible with
|
||||
the new incremental recursion mode.
|
||||
|
||||
- Added the --remove-source-files option as a replacement for the (now
|
||||
deprecated) --remove-sent-files option. This new option removes all
|
||||
non-dirs from the source directories, even if the file was already
|
||||
up-to-date. This fixes a problem where interrupting an rsync that
|
||||
was using --remove-sent-files and restarting it could leave behind
|
||||
a file that the earlier rsync synchronized, but didn't get to remove.
|
||||
(The deprecated --remove-sent-files is still understood for now, and
|
||||
still behaves in the same way as before.)
|
||||
- Rsync now allows multiple remote-source args to be specified rather than
|
||||
having to rely on a special space-splitting side-effect of the remote-
|
||||
shell. Additional remote args must specify the same host or have an
|
||||
empty hostname, as seen here: :file1 ::module/file2. This means that
|
||||
local use of brace expansion now works: rsync -av host:path/{f1,f2} .
|
||||
|
||||
- Added the option --no-motd to suppress the message-of-the-day output
|
||||
from a daemon when doing a copy. (See the manpage for a caveat.)
|
||||
- Added the --protect-args (-s) option, that tells rsync to send most of
|
||||
the command-line args at the start of the transfer rather than as args
|
||||
to the remote-shell command. This protects them from space-splitting,
|
||||
and only interprets basic wildcard special shell characters (*?[).
|
||||
|
||||
- Added a new environment variable to the pre-/post-xfer exec commands (in
|
||||
the daemon's config file): RSYNC_PID. This value will be the same in
|
||||
both the pre- and post-xfer commands, so it can be used if the pre-xfer
|
||||
command wants to cache some arg/request info for the post-xfer command.
|
||||
- Added the --delete-delay option, which is a more efficient way to delete
|
||||
files at the end of the transfer without needing a separate delete pass.
|
||||
|
||||
- Added the --acls (-A) option to preserve Access Control Lists. This is
|
||||
an improved version of the prior patch that was available, and it even
|
||||
supports OS X ACLs. (If you need to have backward compatibility with
|
||||
old, patched versions of rsync, apply the acls.diff file from the patches
|
||||
dir.)
|
||||
|
||||
- Added the --xattrs (-X) option to preserver extended attributes. This is
|
||||
an improved version of the prior patch that was available. (If you need
|
||||
to have backward compatibility with old, patched versions of rsync, apply
|
||||
the xattrs.diff file from the patches dir.)
|
||||
|
||||
- Added the --fake-super option that allows a non-super user to preserve
|
||||
all attributes of a file by using a special extended-attribute idiom.
|
||||
There is also an analogous "fake super" option for an rsync daemon.
|
||||
|
||||
- Added the --iconv option, which allows rsync to convert filenames from
|
||||
one character-set to another during the transfer. The default is to make
|
||||
this feature available as long as your system has iconv_open(). If
|
||||
compilation fails, specify --disable-iconv to configure, and then
|
||||
rebuild. If you want rsync to perform character-set conversions by
|
||||
default, you can specify --enable-iconv=CONVERT_STRING with the default
|
||||
value for the --iconv option that you wish to use. For example,
|
||||
"--enable-iconv=." is a good choice. See the rsync manpage for an
|
||||
explanation of the --iconv option's settings.
|
||||
|
||||
- Added the --skip-compress=LIST option to override the default list of
|
||||
file suffixes that will not be compressed when using --compress.
|
||||
|
||||
- The daemon's default for "dont compress" was extended to include:
|
||||
*.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg
|
||||
The matching routine was also optimized to run more quickly.
|
||||
|
||||
- The --max-delete option now outputs a warning if it skipped any file
|
||||
deletions, including a count of how many deletions were skipped. (Older
|
||||
versions just silently stopped deleting things.)
|
||||
|
||||
- You may specify --max-delete=0 to a 3.0.0 client to request that it warn
|
||||
about extraneous files without deleting anything. If you're not sure
|
||||
what version the client is, you can use the less-obvious --max-delete=-1,
|
||||
as both old and new versions will treat that as the same request (though
|
||||
older versions don't warn).
|
||||
|
||||
- The --hard-link option now uses less memory on both the sending and
|
||||
receiving side for all protocol versions. For protocol 30, the use of a
|
||||
hashtable on the sending side allows us to more efficiently convey to the
|
||||
receiver what files are linked together. This reduces the amount of data
|
||||
sent over the socket by a considerable margin (rather than adding more
|
||||
data), and limits the in-memory storage of the device+inode information
|
||||
to just the sending side for the new protocol 30, or to the receiving
|
||||
side when speaking an older protocol (note that older rsync versions kept
|
||||
the device+inode information on both sides).
|
||||
|
||||
- The filter rules now support a perishable ("p") modifier that marks rules
|
||||
that should not have an effect in a directory that is being deleted. e.g.
|
||||
-f '-p .svn/' would only affect "live" .svn directories.
|
||||
|
||||
- If we get an error setting the time on a symlink, we don't complain about
|
||||
it anymore (since some operating systems don't support that, and it's not
|
||||
that important).
|
||||
|
||||
- Protocol 30 now uses MD5 checksums instead of MD4.
|
||||
|
||||
- Changed the --append option to not checksum the existing data in the
|
||||
destination file, which speeds up file appending.
|
||||
|
||||
- Added the --append-verify option, which works like the older --append
|
||||
option (verifying the existing data in the destination file). For
|
||||
compatibility with older rsync versions, any use of --append that is
|
||||
talking protocol 29 or older will revert to the --append-verify method.
|
||||
|
||||
- Documented and extended the support for the RSYNC_CONNECT_PROG variable
|
||||
that can be used to enhance the client side of a daemon connection.
|
||||
|
||||
- Improved the dashes and double-quotes in the nroff manpage output.
|
||||
|
||||
- We now support a lot more --no-OPTION override options.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Did a code audit using IBM's code-checker program and made several
|
||||
changes, including: replacing most of the strcpy() and sprintf()
|
||||
calls with strlcpy(), snprintf(), and memcpy(), adding a 0-value to
|
||||
an enum that had been intermingling a literal 0 with the defined enum
|
||||
values, silencing some uninitialized memory checks, marking some
|
||||
functions with a "noreturn" attribute, and changing an "if" that
|
||||
could never succeed on some platforms into a pre-processor directive
|
||||
that conditionally compiles the code.
|
||||
- The file-list sorting algorithm now uses a sort that keeps any same-
|
||||
named items in the same order as they were specified. This allows
|
||||
rsync to always ensure that the first of the duplicates is the one
|
||||
that will be included in the copy. The new sort was also faster
|
||||
than the glibc version of qsort() and mergesort() in my testing.
|
||||
|
||||
- Fixed a potential bug in f_name_cmp() when both the args are a
|
||||
top-level "." dir (which doesn't happen in normal operations).
|
||||
- Rsync now supports the transfer of 64-bit timestamps (time_t values).
|
||||
|
||||
- Changed exit_cleanup() so that it can never return instead of exit.
|
||||
The old code might return if it found the exit_cleanup() function
|
||||
was being called recursively. The new code is segmented so that
|
||||
any recursive calls move on to the next step of the exit-processing.
|
||||
- Fixed a build problem with older (2.x) versions of gcc.
|
||||
|
||||
- The macro WIFEXITED(stat) will now be defined if the OS didn't already
|
||||
define it.
|
||||
- Added some isType() functions that make dealing with signed characters
|
||||
easier without forcing variables via casts.
|
||||
|
||||
- Changed strcat/strcpy/sprintf function calls to use safer versions.
|
||||
|
||||
- Upgraded the included popt version to 1.10.2 and improved its use of
|
||||
string-handling functions.
|
||||
|
||||
- Added missing prototypes for compatibility functions from the lib dir.
|
||||
|
||||
- Configure determines if iconv() has a const arg, allowing us to avoid a
|
||||
compiler warning.
|
||||
|
||||
- Made the sending of some numbers more efficient for protocol 30.
|
||||
|
||||
- Make sure that a daemon process doesn't mind if the client was weird and
|
||||
omitted the --server option.
|
||||
|
||||
- Improved the use of "const" on pointers.
|
||||
|
||||
- Improved J.W.'s pool_alloc routines to add a way of freeing older
|
||||
sections of a pool's memory.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The acls.diff and xattrs.diff patches have received a bunch of work to
|
||||
make them much closer to being acceptable in the main distribution.
|
||||
The xattrs patch also has some preliminary Mac OS X compatibility code
|
||||
that allows Macs and non-macs to exchange extended attributes.
|
||||
- Rsync is now licensed under the GPLv3 or later.
|
||||
|
||||
- A new diff in the patches dir, fake-root.diff, allows rsync to
|
||||
maintain a backup hierarchy with full owner, group, and device info
|
||||
without actually running as root. It does this using a special
|
||||
extended attribute, so it depends on xattrs.diff (which depends on
|
||||
acls.diff).
|
||||
- When running the tests, we now put our per-test temp dirs into a sub-
|
||||
directory named testtmp (which is created, if missing). This allows
|
||||
someone to symlink the testtmp directory to another filesystem (which is
|
||||
useful if the build dir's filesystem does not support ACLs and xattrs,
|
||||
and another file system does).
|
||||
|
||||
- The rsync.yo and rsyncd.conf.yo files have been updated to work
|
||||
better with the latest yodl 2.x releases.
|
||||
|
||||
- Updated config.guess and config.sub to their 2006-02-23 version.
|
||||
|
||||
- Updated various files to include the latest FSF address and to have
|
||||
consistent opening comments.
|
||||
- Rsync now has a way of handling protocol-version changes during the
|
||||
development of a new protocol version. This causes any out-of-sync
|
||||
versions to speak an older protocol rather than fail in a cryptic manner.
|
||||
This addition makes it safe to deploy a pre-release version that may
|
||||
interact with the public. This new exchange of sub-version info does not
|
||||
interfere with the {MIN,MAX}_PROTOCOL_VERSION checking algorithm (which
|
||||
does not have enough range to allow the main protocol number to be
|
||||
incremented for every minor tweak in that happens during development).
|
||||
|
||||
167
OLDNEWS
167
OLDNEWS
@@ -1,3 +1,165 @@
|
||||
NEWS for rsync 2.6.9 (6 Nov 2006)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.8:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- If rsync is interrupted via a handled signal (such as SIGINT), it will
|
||||
once again clean-up its temp file from the destination dir.
|
||||
|
||||
- Fixed an overzealous sanitizing bug in the handling of the --link-dest,
|
||||
--copy-dest, and --compare-dest options to a daemon without chroot: if
|
||||
the copy's destination dir is deeper than the top of the module's path,
|
||||
these options now accept a safe number of parent-dir (../) references
|
||||
(since these options are relative to the destination dir). The old code
|
||||
incorrectly chopped off all "../" prefixes for these options, no matter
|
||||
how deep the destination directory was in the module's hierarchy.
|
||||
|
||||
- Fixed a bug where a deferred info/error/log message could get sent
|
||||
directly to the sender instead of being handled by rwrite() in the
|
||||
generator. This fixes an "unexpected tag 3" fatal error, and should
|
||||
also fix a potential problem where a deferred info/error message from
|
||||
the receiver might bypass the log file and get sent only to the client
|
||||
process. (These problems could only affect an rsync daemon that was
|
||||
receiving files.)
|
||||
|
||||
- Fixed a bug when --inplace was combined with a --*-dest option and we
|
||||
update a file's data using an alternate basis file. The code now
|
||||
notices that it needs to copy the matching data from the basis file
|
||||
instead of (wrongly) assuming that it was already present in the file.
|
||||
|
||||
- Fixed a bug where using --dry-run with a --*-dest option with a path
|
||||
relative to a directory that does not yet exist: the affected option
|
||||
gets its proper path value so that the output of the dry-run is right.
|
||||
|
||||
- Fixed a bug in the %f logfile escape when receiving files: the
|
||||
destination path is now included in the output (e.g. you can now tell
|
||||
when a user specifies a subdir inside a module).
|
||||
|
||||
- If the receiving side fails to create a directory, it will now skip
|
||||
trying to update everything that is inside that directory.
|
||||
|
||||
- If --link-dest is specified with --checksum but without --times, rsync
|
||||
will now allow a hard-link to be created to a matching link-dest file
|
||||
even when the file's modify-time doesn't match the server's file.
|
||||
|
||||
- The daemon now calls more timezone-using functions prior to doing a
|
||||
chroot. This should help some C libraries to generate proper timestamps
|
||||
from inside a chrooted daemon (and to not try to access /etc/timezone
|
||||
over and over again).
|
||||
|
||||
- Fixed a bug in the handling of an absolute --partial-dir=ABS_PATH option:
|
||||
it now deletes an alternate basis file from the partial-dir that was used
|
||||
to successfully update a destination file.
|
||||
|
||||
- Fixed a bug in the handling of --delete-excluded when using a per-dir
|
||||
merge file: the merge file is now honored on the receiving side, and
|
||||
only its unqualified include/exclude commands are ignored (just as is
|
||||
done for global include/excludes).
|
||||
|
||||
- Fixed a recent bug where --delete was not working when transferring from
|
||||
the root (/) of the filesystem with --relative enabled.
|
||||
|
||||
- Fixed a recent bug where an --exclude='*' could affect the root (/) of
|
||||
the filesystem with --relative enabled.
|
||||
|
||||
- When --inplace creates a file, it is now created with owner read/write
|
||||
permissions (0600) instead of no permissions at all. This avoids a
|
||||
problem continuing a transfer that was interrupted (since --inplace
|
||||
will not update a file that has no write permissions).
|
||||
|
||||
- If either --remove-source-files or --remove-sent-files is enabled and we
|
||||
are unable to remove the source file, rsync now outputs an error.
|
||||
|
||||
- Fixed a bug in the daemon's "incoming chmod" rule: newly-created
|
||||
directories no longer get the 'F' (file) rules applied to them.
|
||||
|
||||
- Fixed an infinite loop bug when a filter rule was rejected due to being
|
||||
overly long.
|
||||
|
||||
- When the server receives a --partial-dir option from the client, it no
|
||||
longer runs the client-side code that adds an assumed filter rule (since
|
||||
the client will be sending us the rules in the usual manner, and they
|
||||
may have chosen to override the auto-added rule).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --log-file=FILE and --log-file-format=FORMAT options. These
|
||||
can be used to tell any rsync to output what it is doing to a log file.
|
||||
They work with a client rsync, a non-daemon server rsync (see the man
|
||||
page for instructions), and also allows the overriding of rsyncd.conf
|
||||
settings when starting a daemon.
|
||||
|
||||
- The --log-format option was renamed to be --out-format to avoid confusing
|
||||
it with affecting the log-file output. (The old option remains as an
|
||||
alias for the new to preserve backward compatibility.)
|
||||
|
||||
- Made "log file" and "syslog facility" settable on a per-module basis in
|
||||
the daemon's config file.
|
||||
|
||||
- Added the --remove-source-files option as a replacement for the (now
|
||||
deprecated) --remove-sent-files option. This new option removes all
|
||||
non-dirs from the source directories, even if the file was already
|
||||
up-to-date. This fixes a problem where interrupting an rsync that
|
||||
was using --remove-sent-files and restarting it could leave behind
|
||||
a file that the earlier rsync synchronized, but didn't get to remove.
|
||||
(The deprecated --remove-sent-files is still understood for now, and
|
||||
still behaves in the same way as before.)
|
||||
|
||||
- Added the option --no-motd to suppress the message-of-the-day output
|
||||
from a daemon when doing a copy. (See the manpage for a caveat.)
|
||||
|
||||
- Added a new environment variable to the pre-/post-xfer exec commands (in
|
||||
the daemon's config file): RSYNC_PID. This value will be the same in
|
||||
both the pre- and post-xfer commands, so it can be used as a unique ID
|
||||
if the pre-xfer command wants to cache some arg/request info for the
|
||||
post-xfer command.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Did a code audit using IBM's code-checker program and made several
|
||||
changes, including: replacing most of the strcpy() and sprintf()
|
||||
calls with strlcpy(), snprintf(), and memcpy(), adding a 0-value to
|
||||
an enum that had been intermingling a literal 0 with the defined enum
|
||||
values, silencing some uninitialized memory checks, marking some
|
||||
functions with a "noreturn" attribute, and changing an "if" that
|
||||
could never succeed on some platforms into a pre-processor directive
|
||||
that conditionally compiles the code.
|
||||
|
||||
- Fixed a potential bug in f_name_cmp() when both the args are a
|
||||
top-level "." dir (which doesn't happen in normal operations).
|
||||
|
||||
- Changed exit_cleanup() so that it can never return instead of exit.
|
||||
The old code might return if it found the exit_cleanup() function
|
||||
was being called recursively. The new code is segmented so that
|
||||
any recursive calls move on to the next step of the exit-processing.
|
||||
|
||||
- The macro WIFEXITED(stat) will now be defined if the OS didn't already
|
||||
define it.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The acls.diff and xattrs.diff patches have received a bunch of work to
|
||||
make them much closer to being acceptable in the main distribution.
|
||||
The xattrs patch also has some preliminary Mac OS X and FreeBSD
|
||||
compatibility code that various system types to exchange extended
|
||||
file-attributes.
|
||||
|
||||
- A new diff in the patches dir, fake-root.diff, allows rsync to
|
||||
maintain a backup hierarchy with full owner, group, and device info
|
||||
without actually running as root. It does this using a special
|
||||
extended attribute, so it depends on xattrs.diff (which depends on
|
||||
acls.diff).
|
||||
|
||||
- The rsync.yo and rsyncd.conf.yo files have been updated to work
|
||||
better with the latest yodl 2.x releases.
|
||||
|
||||
- Updated config.guess and config.sub to their 2006-07-02 versions.
|
||||
|
||||
- Updated various files to include the latest FSF address and to have
|
||||
consistent opening comments.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.8 (22 Apr 2006)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.7:
|
||||
@@ -144,8 +306,8 @@ Changes since 2.6.6:
|
||||
- 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 the code reading a filter/exclude file gets 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
|
||||
@@ -2082,6 +2244,7 @@ Changes since 2.4.6:
|
||||
|
||||
Partial Protocol History
|
||||
RELEASE DATE VER. DATE OF COMMIT* PROTOCOL
|
||||
?? ??? 2007 3.0.0 11 Nov 2006 30
|
||||
06 Nov 2006 2.6.9 29
|
||||
22 Apr 2006 2.6.8 29
|
||||
11 Mar 2006 2.6.7 29
|
||||
|
||||
10
README
10
README
@@ -51,13 +51,13 @@ case.
|
||||
Once built put a copy of rsync in your search path on the local and
|
||||
remote systems (or use "make install"). That's it!
|
||||
|
||||
RSYNC SERVERS
|
||||
RSYNC DAEMONS
|
||||
-------------
|
||||
|
||||
rsync can also talk to "rsync servers" which can provide anonymous or
|
||||
rsync can also talk to "rsync daemons" which can provide anonymous or
|
||||
authenticated rsync. See the rsyncd.conf(5) man page for details on how
|
||||
to setup a rsync server. See the rsync(1) man page for info on how to
|
||||
connect to a rsync server.
|
||||
to setup an rsync daemon. See the rsync(1) man page for info on how to
|
||||
connect to an rsync daemon.
|
||||
|
||||
|
||||
MAILING LIST
|
||||
@@ -69,7 +69,7 @@ versions on this list.
|
||||
|
||||
To join the mailing list see the web page at http://lists.samba.org/
|
||||
|
||||
To send mail to everyone on the list send it to rsync@samba.org
|
||||
To send mail to everyone on the list send it to rsync@lists.samba.org
|
||||
|
||||
|
||||
BUG REPORTS
|
||||
|
||||
26
TODO
26
TODO
@@ -365,21 +365,6 @@ Use generic zlib 2002/02/25
|
||||
-- --
|
||||
|
||||
|
||||
TDB 2002/03/12
|
||||
|
||||
Rather than storing the file list in memory, store it in a TDB.
|
||||
|
||||
This *might* make memory usage lower while building the file list.
|
||||
|
||||
Hashtable lookup will mean files are not transmitted in order,
|
||||
though... hm.
|
||||
|
||||
This would neatly eliminate one of the major post-fork shared data
|
||||
structures.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Splint 2002/03/12
|
||||
|
||||
Build rsync with SPLINT to try to find security holes. Add
|
||||
@@ -392,17 +377,6 @@ Splint 2002/03/12
|
||||
|
||||
PERFORMANCE ----------------------------------------------------------
|
||||
|
||||
Traverse just one directory at a time
|
||||
|
||||
Traverse just one directory at a time. Tridge says it's possible.
|
||||
|
||||
At the moment rsync reads the whole file list into memory at the
|
||||
start, which makes us use a lot of memory and also not pipeline
|
||||
network access as much as we could.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Allow skipping MD4 file_sum 2002/04/08
|
||||
|
||||
If we're doing a local transfer, or using -W, then perhaps don't
|
||||
|
||||
7
access.c
7
access.c
@@ -2,11 +2,11 @@
|
||||
* Routines to authenticate access to a daemon (hosts allow/deny).
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2004, 2005 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -27,11 +26,11 @@ extern char *password_file;
|
||||
encode a buffer using base64 - simple and slow algorithm. null terminates
|
||||
the result.
|
||||
***************************************************************************/
|
||||
void base64_encode(char *buf, int len, char *out, int pad)
|
||||
void base64_encode(const char *buf, int len, char *out, int pad)
|
||||
{
|
||||
char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i;
|
||||
unsigned char *d = (unsigned char *)buf;
|
||||
const uchar *d = (const uchar *)buf;
|
||||
int bytes = (len*8 + 5)/6;
|
||||
|
||||
for (i = 0; i < bytes; i++) {
|
||||
@@ -55,15 +54,16 @@ void base64_encode(char *buf, int len, char *out, int pad)
|
||||
}
|
||||
|
||||
/* Generate a challenge buffer and return it base64-encoded. */
|
||||
static void gen_challenge(char *addr, char *challenge)
|
||||
static void gen_challenge(const char *addr, char *challenge)
|
||||
{
|
||||
char input[32];
|
||||
char md4_out[MD4_SUM_LENGTH];
|
||||
char digest[MAX_DIGEST_LEN];
|
||||
struct timeval tv;
|
||||
int len;
|
||||
|
||||
memset(input, 0, sizeof input);
|
||||
|
||||
strlcpy((char *)input, addr, 17);
|
||||
strlcpy(input, addr, 17);
|
||||
sys_gettimeofday(&tv);
|
||||
SIVAL(input, 16, tv.tv_sec);
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
@@ -71,20 +71,21 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
|
||||
sum_init(0);
|
||||
sum_update(input, sizeof input);
|
||||
sum_end(md4_out);
|
||||
len = sum_end(digest);
|
||||
|
||||
base64_encode(md4_out, MD4_SUM_LENGTH, challenge, 0);
|
||||
base64_encode(digest, len, challenge, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Return the secret for a user from the secret file, null terminated.
|
||||
* Maximum length is len (not counting the null). */
|
||||
static int get_secret(int module, char *user, char *secret, int len)
|
||||
static int get_secret(int module, const char *user, char *secret, int len)
|
||||
{
|
||||
char *fname = lp_secrets_file(module);
|
||||
const char *fname = lp_secrets_file(module);
|
||||
STRUCT_STAT st;
|
||||
int fd, ok = 1;
|
||||
char ch, *p;
|
||||
const char *p;
|
||||
char ch, *s;
|
||||
|
||||
if (!fname || !*fname)
|
||||
return 0;
|
||||
@@ -136,27 +137,27 @@ static int get_secret(int module, char *user, char *secret, int len)
|
||||
}
|
||||
|
||||
/* Slurp the secret into the "secret" buffer. */
|
||||
p = secret;
|
||||
s = secret;
|
||||
while (len > 0) {
|
||||
if (read(fd, p, 1) != 1 || *p == '\n')
|
||||
if (read(fd, s, 1) != 1 || *s == '\n')
|
||||
break;
|
||||
if (*p == '\r')
|
||||
if (*s == '\r')
|
||||
continue;
|
||||
p++;
|
||||
s++;
|
||||
len--;
|
||||
}
|
||||
*p = '\0';
|
||||
*s = '\0';
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *getpassf(char *filename)
|
||||
static const char *getpassf(const char *filename)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
char buffer[512], *p;
|
||||
int fd, n, ok = 1;
|
||||
char *envpw = getenv("RSYNC_PASSWORD");
|
||||
const char *envpw = getenv("RSYNC_PASSWORD");
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
@@ -203,16 +204,17 @@ static char *getpassf(char *filename)
|
||||
|
||||
/* Generate an MD4 hash created from the combination of the password
|
||||
* and the challenge string and return it base64-encoded. */
|
||||
static void generate_hash(char *in, char *challenge, char *out)
|
||||
static void generate_hash(const char *in, const char *challenge, char *out)
|
||||
{
|
||||
char buf[MD4_SUM_LENGTH];
|
||||
char buf[MAX_DIGEST_LEN];
|
||||
int len;
|
||||
|
||||
sum_init(0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
sum_end(buf);
|
||||
len = sum_end(buf);
|
||||
|
||||
base64_encode(buf, MD4_SUM_LENGTH, out, 0);
|
||||
base64_encode(buf, len, out, 0);
|
||||
}
|
||||
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
@@ -221,14 +223,14 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
* Return NULL if authentication failed. Return "" if anonymous access.
|
||||
* Otherwise return username.
|
||||
*/
|
||||
char *auth_server(int f_in, int f_out, int module, char *host, char *addr,
|
||||
char *leader)
|
||||
char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
const char *addr, const char *leader)
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
char challenge[MD4_SUM_LENGTH*2];
|
||||
char challenge[MAX_DIGEST_LEN*2];
|
||||
char line[BIGPATHBUFLEN];
|
||||
char secret[512];
|
||||
char pass2[MD4_SUM_LENGTH*2];
|
||||
char pass2[MAX_DIGEST_LEN*2];
|
||||
char *tok, *pass;
|
||||
|
||||
/* if no auth list then allow anyone in! */
|
||||
@@ -239,7 +241,7 @@ char *auth_server(int f_in, int f_out, int module, char *host, char *addr,
|
||||
|
||||
io_printf(f_out, "%s%s\n", leader, challenge);
|
||||
|
||||
if (!read_line(f_in, line, sizeof line - 1)
|
||||
if (!read_line_old(f_in, line, sizeof line)
|
||||
|| (pass = strchr(line, ' ')) == NULL) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"invalid challenge response\n",
|
||||
@@ -286,11 +288,10 @@ char *auth_server(int f_in, int f_out, int module, char *host, char *addr,
|
||||
return strdup(line);
|
||||
}
|
||||
|
||||
|
||||
void auth_client(int fd, char *user, char *challenge)
|
||||
void auth_client(int fd, const char *user, const char *challenge)
|
||||
{
|
||||
char *pass;
|
||||
char pass2[MD4_SUM_LENGTH*2];
|
||||
const char *pass;
|
||||
char pass2[MAX_DIGEST_LEN*2];
|
||||
|
||||
if (!user || !*user)
|
||||
user = "nobody";
|
||||
|
||||
160
backup.c
160
backup.c
@@ -2,11 +2,11 @@
|
||||
* Backup handling code.
|
||||
*
|
||||
* Copyright (C) 1999 Andrew Tridgell
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,27 +15,27 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int am_root;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
extern int preserve_links;
|
||||
extern int safe_symlinks;
|
||||
extern int backup_dir_len;
|
||||
extern unsigned int backup_dir_remainder;
|
||||
extern char backup_dir_buf[MAXPATHLEN];
|
||||
extern char *backup_suffix;
|
||||
extern char *backup_dir;
|
||||
|
||||
extern int am_root;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
extern int preserve_links;
|
||||
extern int safe_symlinks;
|
||||
|
||||
/* make a complete pathname for backup file */
|
||||
char *get_backup_name(char *fname)
|
||||
char *get_backup_name(const char *fname)
|
||||
{
|
||||
if (backup_dir) {
|
||||
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
|
||||
@@ -52,10 +52,10 @@ char *get_backup_name(char *fname)
|
||||
}
|
||||
|
||||
/* simple backup creates a backup with a suffix in the same directory */
|
||||
static int make_simple_backup(char *fname)
|
||||
static int make_simple_backup(const char *fname)
|
||||
{
|
||||
int rename_errno;
|
||||
char *fnamebak = get_backup_name(fname);
|
||||
const char *fnamebak = get_backup_name(fname);
|
||||
|
||||
if (!fnamebak)
|
||||
return 0;
|
||||
@@ -92,31 +92,37 @@ static int make_simple_backup(char *fname)
|
||||
Create a directory given an absolute path, perms based upon another directory
|
||||
path
|
||||
****************************************************************************/
|
||||
static int make_bak_dir(char *fullpath)
|
||||
int make_bak_dir(const char *fullpath)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
char *rel = fullpath + backup_dir_len;
|
||||
char *end = rel + strlen(rel);
|
||||
char *p = end;
|
||||
char fbuf[MAXPATHLEN], *rel, *end, *p;
|
||||
struct file_struct *file;
|
||||
int len = backup_dir_len;
|
||||
stat_x sx;
|
||||
|
||||
while (strncmp(fullpath, "./", 2) == 0)
|
||||
while (*fullpath == '.' && fullpath[1] == '/') {
|
||||
fullpath += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (strlcpy(fbuf, fullpath, sizeof fbuf) >= sizeof fbuf)
|
||||
return -1;
|
||||
|
||||
rel = fbuf + len;
|
||||
end = p = rel + strlen(rel);
|
||||
|
||||
/* Try to find an existing dir, starting from the deepest dir. */
|
||||
while (1) {
|
||||
if (--p == fullpath) {
|
||||
p += strlen(p);
|
||||
goto failure;
|
||||
}
|
||||
if (--p == fbuf)
|
||||
return -1;
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (mkdir_defmode(fullpath) == 0)
|
||||
if (mkdir_defmode(fbuf) == 0)
|
||||
break;
|
||||
if (errno != ENOENT) {
|
||||
rsyserr(FERROR, errno,
|
||||
"make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
full_fname(fbuf));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,37 +132,53 @@ static int make_bak_dir(char *fullpath)
|
||||
if (p >= rel) {
|
||||
/* Try to transfer the directory settings of the
|
||||
* actual dir that the files are coming from. */
|
||||
if (do_stat(rel, &st) < 0) {
|
||||
if (x_stat(rel, &sx.st, NULL) < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"make_bak_dir stat %s failed",
|
||||
full_fname(rel));
|
||||
} else {
|
||||
do_lchown(fullpath, st.st_uid, st.st_gid);
|
||||
do_chmod(fullpath, st.st_mode);
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx.acc_acl = sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx.xattr = NULL;
|
||||
#endif
|
||||
if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
|
||||
continue;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
get_acl(rel, &sx);
|
||||
cache_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(rel, &sx);
|
||||
cache_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
set_file_attrs(fbuf, file, NULL, NULL, 0);
|
||||
unmake_file(file);
|
||||
}
|
||||
}
|
||||
*p = '/';
|
||||
p += strlen(p);
|
||||
if (p == end)
|
||||
break;
|
||||
if (mkdir_defmode(fullpath) < 0) {
|
||||
if (mkdir_defmode(fbuf) < 0) {
|
||||
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
full_fname(fbuf));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
while (p != end) {
|
||||
*p = '/';
|
||||
p += strlen(p);
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* robustly move a file, creating new directory structures if necessary */
|
||||
static int robust_move(char *src, char *dst)
|
||||
static int robust_move(const char *src, char *dst)
|
||||
{
|
||||
if (robust_rename(src, dst, NULL, 0755) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(dst) < 0
|
||||
@@ -168,31 +190,56 @@ static int robust_move(char *src, char *dst)
|
||||
|
||||
/* If we have a --backup-dir, then we get here from make_backup().
|
||||
* We will move the file to be deleted into a parallel directory tree. */
|
||||
static int keep_backup(char *fname)
|
||||
static int keep_backup(const char *fname)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
stat_x sx;
|
||||
struct file_struct *file;
|
||||
char *buf;
|
||||
int kept = 0;
|
||||
int ret_code;
|
||||
|
||||
/* return if no file to keep */
|
||||
if (do_lstat(fname, &st) < 0)
|
||||
if (x_lstat(fname, &sx.st, NULL) < 0)
|
||||
return 1;
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx.acc_acl = sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx.xattr = NULL;
|
||||
#endif
|
||||
|
||||
if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
|
||||
return 1; /* the file could have disappeared */
|
||||
|
||||
if (!(buf = get_backup_name(fname)))
|
||||
if (!(buf = get_backup_name(fname))) {
|
||||
unmake_file(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
get_acl(fname, &sx);
|
||||
cache_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(fname, &sx);
|
||||
cache_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check to see if this is a device file, or link */
|
||||
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|
||||
|| (preserve_specials && IS_SPECIAL(file->mode))) {
|
||||
uint32 *devp = F_RDEV_P(file);
|
||||
dev_t rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
|
||||
do_unlink(buf);
|
||||
if (do_mknod(buf, file->mode, file->u.rdev) < 0
|
||||
if (do_mknod(buf, file->mode, rdev) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_mknod(buf, file->mode, file->u.rdev) < 0)) {
|
||||
|| do_mknod(buf, file->mode, rdev) < 0)) {
|
||||
rsyserr(FERROR, errno, "mknod %s failed",
|
||||
full_fname(buf));
|
||||
} else if (verbose > 2) {
|
||||
@@ -222,20 +269,20 @@ static int keep_backup(char *fname)
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (!kept && preserve_links && S_ISLNK(file->mode)) {
|
||||
if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
|
||||
const char *sl = F_SYMLINK(file);
|
||||
if (safe_symlinks && unsafe_symlink(sl, buf)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
|
||||
full_fname(buf), file->u.link);
|
||||
full_fname(buf), sl);
|
||||
}
|
||||
kept = 1;
|
||||
} else {
|
||||
do_unlink(buf);
|
||||
if (do_symlink(file->u.link, buf) < 0
|
||||
if (do_symlink(sl, buf) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_symlink(file->u.link, buf) < 0)) {
|
||||
|| do_symlink(sl, buf) < 0)) {
|
||||
rsyserr(FERROR, errno, "link %s -> \"%s\"",
|
||||
full_fname(buf),
|
||||
file->u.link);
|
||||
full_fname(buf), sl);
|
||||
}
|
||||
do_unlink(fname);
|
||||
kept = 1;
|
||||
@@ -246,6 +293,7 @@ static int keep_backup(char *fname)
|
||||
if (!kept && !S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
|
||||
fname);
|
||||
unmake_file(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -254,14 +302,14 @@ static int keep_backup(char *fname)
|
||||
if (robust_move(fname, buf) != 0) {
|
||||
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
|
||||
full_fname(fname), buf);
|
||||
} else if (st.st_nlink > 1) {
|
||||
} else if (sx.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_file_attrs(buf, file, NULL, 0);
|
||||
free(file);
|
||||
set_file_attrs(buf, file, NULL, fname, 0);
|
||||
unmake_file(file);
|
||||
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
@@ -272,7 +320,7 @@ static int keep_backup(char *fname)
|
||||
|
||||
|
||||
/* main backup switch routine */
|
||||
int make_backup(char *fname)
|
||||
int make_backup(const char *fname)
|
||||
{
|
||||
if (backup_dir)
|
||||
return keep_backup(fname);
|
||||
|
||||
7
batch.c
7
batch.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
19
byteorder.h
19
byteorder.h
@@ -2,10 +2,11 @@
|
||||
* Simple byteorder handling.
|
||||
*
|
||||
* Copyright (C) 1992-1995 Andrew Tridgell
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -14,14 +15,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#undef CAREFUL_ALIGNMENT
|
||||
|
||||
/* we know that the x86 can handle misalignment and has the "right"
|
||||
byteorder */
|
||||
/* We know that the x86 can handle misalignment and has the same
|
||||
* byte order (LSB-first) as the 32-bit numbers we transmit. */
|
||||
#ifdef __i386__
|
||||
#define CAREFUL_ALIGNMENT 0
|
||||
#endif
|
||||
@@ -31,13 +31,12 @@
|
||||
#endif
|
||||
|
||||
#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
|
||||
#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
|
||||
#define UVAL(buf,pos) ((uint32)CVAL(buf,pos))
|
||||
#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
|
||||
|
||||
|
||||
#if CAREFUL_ALIGNMENT
|
||||
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
|
||||
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
|
||||
#define PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8)
|
||||
#define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16)
|
||||
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
|
||||
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
|
||||
#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
|
||||
@@ -51,5 +50,3 @@
|
||||
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
|
||||
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
7
case_N.h
7
case_N.h
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* End-of-run cleanup helper code used by cleanup.c.
|
||||
*
|
||||
* Copyright (C) 2006 Wayne Davison
|
||||
* Copyright (C) 2006-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -14,8 +14,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This is included by cleanup.c multiple times, once for every segement in
|
||||
|
||||
188
checksum.c
188
checksum.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004, 2005 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,19 +16,16 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int csum_length=2; /* initial value */
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
|
||||
int csum_length = SHORT_SUM_LENGTH; /* initial value */
|
||||
|
||||
/*
|
||||
a simple 32 bit checksum that can be upadted from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
@@ -54,54 +51,64 @@ uint32 get_checksum1(char *buf1, int32 len)
|
||||
|
||||
void get_checksum2(char *buf, int32 len, char *sum)
|
||||
{
|
||||
int32 i;
|
||||
static char *buf1;
|
||||
static int32 len1;
|
||||
struct mdfour m;
|
||||
md_context m;
|
||||
|
||||
if (len > len1) {
|
||||
if (buf1)
|
||||
free(buf1);
|
||||
buf1 = new_array(char, len+4);
|
||||
len1 = len;
|
||||
if (!buf1)
|
||||
out_of_memory("get_checksum2");
|
||||
if (protocol_version >= 30) {
|
||||
uchar seedbuf[4];
|
||||
md5_begin(&m);
|
||||
md5_update(&m, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m, seedbuf, 4);
|
||||
}
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
int32 i;
|
||||
static char *buf1;
|
||||
static int32 len1;
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
if (len > len1) {
|
||||
if (buf1)
|
||||
free(buf1);
|
||||
buf1 = new_array(char, len+4);
|
||||
len1 = len;
|
||||
if (!buf1)
|
||||
out_of_memory("get_checksum2");
|
||||
}
|
||||
|
||||
memcpy(buf1, buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(buf1,len,checksum_seed);
|
||||
len += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
|
||||
|
||||
/*
|
||||
* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
memcpy(buf1,buf,len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(buf1,len,checksum_seed);
|
||||
len += 4;
|
||||
}
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
|
||||
}
|
||||
/*
|
||||
* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0 || protocol_version >= 27) {
|
||||
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
|
||||
}
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
|
||||
|
||||
void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
void file_checksum(char *fname, char *sum, OFF_T size)
|
||||
{
|
||||
OFF_T i;
|
||||
struct map_struct *buf;
|
||||
OFF_T i, len = size;
|
||||
md_context m;
|
||||
int32 remainder;
|
||||
int fd;
|
||||
OFF_T len = size;
|
||||
struct mdfour m;
|
||||
|
||||
memset(sum,0,MD4_SUM_LENGTH);
|
||||
memset(sum, 0, MAX_DIGEST_LEN);
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1)
|
||||
@@ -109,38 +116,57 @@ void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
|
||||
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
|
||||
|
||||
mdfour_begin(&m);
|
||||
if (protocol_version >= 30) {
|
||||
md5_begin(&m);
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
mdfour_begin(&m);
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes. */
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes. */
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, len-i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
|
||||
close(fd);
|
||||
unmap_file(buf);
|
||||
}
|
||||
|
||||
|
||||
static int32 sumresidue;
|
||||
static char sumrbuf[CSUM_CHUNK];
|
||||
static struct mdfour md;
|
||||
static md_context md;
|
||||
|
||||
void sum_init(int seed)
|
||||
{
|
||||
char s[4];
|
||||
mdfour_begin(&md);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
|
||||
if (protocol_version >= 30)
|
||||
md5_begin(&md);
|
||||
else {
|
||||
mdfour_begin(&md);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,18 +177,23 @@ void sum_init(int seed)
|
||||
* @todo Perhaps get rid of md and just pass in the address each time.
|
||||
* Very slightly clearer and slower.
|
||||
**/
|
||||
void sum_update(char *p, int32 len)
|
||||
void sum_update(const char *p, int32 len)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_update(&md, (uchar *)p, len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(sumrbuf + sumresidue, p, len);
|
||||
memcpy(md.buffer + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sumresidue) {
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(sumrbuf + sumresidue, p, i);
|
||||
mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK);
|
||||
memcpy(md.buffer + sumresidue, p, i);
|
||||
mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
@@ -175,13 +206,20 @@ void sum_update(char *p, int32 len)
|
||||
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(sumrbuf, p, sumresidue);
|
||||
memcpy(md.buffer, p, sumresidue);
|
||||
}
|
||||
|
||||
void sum_end(char *sum)
|
||||
int sum_end(char *sum)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_result(&md, (uchar *)sum);
|
||||
return MD5_DIGEST_LEN;
|
||||
}
|
||||
|
||||
if (sumresidue || protocol_version >= 27)
|
||||
mdfour_update(&md, (uchar *)sumrbuf, sumresidue);
|
||||
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
|
||||
|
||||
mdfour_result(&md, (uchar *)sum);
|
||||
|
||||
return MD4_DIGEST_LEN;
|
||||
}
|
||||
|
||||
13
chmod.c
13
chmod.c
@@ -2,11 +2,11 @@
|
||||
* Implement the core of the --chmod option.
|
||||
*
|
||||
* Copyright (C) 2002 Scott Howard
|
||||
* Copyright (C) 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2005-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -105,12 +104,12 @@ struct chmod_mode_struct *parse_chmod(const char *modestr,
|
||||
case 'D':
|
||||
if (flags & FLAG_FILES_ONLY)
|
||||
state = STATE_ERROR;
|
||||
flags |= FLAG_DIRS_ONLY;
|
||||
flags |= FLAG_DIRS_ONLY;
|
||||
break;
|
||||
case 'F':
|
||||
if (flags & FLAG_DIRS_ONLY)
|
||||
state = STATE_ERROR;
|
||||
flags |= FLAG_FILES_ONLY;
|
||||
flags |= FLAG_FILES_ONLY;
|
||||
break;
|
||||
case 'u':
|
||||
where |= 0100;
|
||||
@@ -151,7 +150,7 @@ struct chmod_mode_struct *parse_chmod(const char *modestr,
|
||||
what |= 2;
|
||||
break;
|
||||
case 'X':
|
||||
flags |= FLAG_X_KEEP;
|
||||
flags |= FLAG_X_KEEP;
|
||||
/* FALL THROUGH */
|
||||
case 'x':
|
||||
what |= 1;
|
||||
|
||||
16
cleanup.c
16
cleanup.c
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -104,6 +103,11 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
if (exit_code) /* Preserve first error code when recursing. */
|
||||
code = exit_code;
|
||||
|
||||
/* If this is the exit at the end of the run, the server side
|
||||
* should not attempt to output a message (see log.c). */
|
||||
if (am_server && code == 0)
|
||||
am_server = 2;
|
||||
|
||||
/* Some of our actions might cause a recursive call back here, so we
|
||||
* keep track of where we are in the cleanup and never repeat a step. */
|
||||
switch (cleanup_step) {
|
||||
@@ -143,7 +147,7 @@ NORETURN 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, NULL,
|
||||
finish_transfer(cleanup_new_fname, fname, NULL, NULL,
|
||||
cleanup_file, 0, !partial_dir);
|
||||
}
|
||||
|
||||
@@ -190,6 +194,8 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
|
||||
if (am_server && code)
|
||||
msleep(100);
|
||||
close_all();
|
||||
|
||||
/* FALLTHROUGH */
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002, 2003, 2004 Wayne Davison
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
398
clientserver.c
398
clientserver.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001-2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002, 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,14 +16,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int quiet;
|
||||
extern int output_motd;
|
||||
extern int list_only;
|
||||
extern int am_sender;
|
||||
@@ -31,6 +30,7 @@ extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
extern int rsync_port;
|
||||
extern int ignore_errors;
|
||||
extern int kluge_around_eof;
|
||||
extern int daemon_over_rsh;
|
||||
extern int sanitize_paths;
|
||||
@@ -51,15 +51,20 @@ extern char *files_from;
|
||||
extern char *tmpdir;
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern char curr_dir[];
|
||||
|
||||
char *auth_user;
|
||||
int read_only = 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. */
|
||||
/* module_dirlen is the length of the module_dir string when in daemon
|
||||
* mode, not chrooted, and the path is not "/"; otherwise 0. */
|
||||
char *module_dir = NULL;
|
||||
unsigned int module_dirlen = 0;
|
||||
|
||||
static int rl_nulls = 0;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
@@ -78,7 +83,8 @@ static struct sigaction sigact;
|
||||
* @return -1 for error in startup, or the result of client_run().
|
||||
* Either way, it eventually gets passed to exit_cleanup().
|
||||
**/
|
||||
int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
int start_socket_client(char *host, int remote_argc, char *remote_argv[],
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int fd, ret;
|
||||
char *p, *user = NULL;
|
||||
@@ -86,7 +92,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
/* This is redundant with code in start_inband_exchange(), but this
|
||||
* short-circuits a problem in the client before we open a socket,
|
||||
* and the extra check won't hurt. */
|
||||
if (*path == '/') {
|
||||
if (**remote_argv == '/') {
|
||||
rprintf(FERROR,
|
||||
"ERROR: The remote path must start with a module name not a /\n");
|
||||
return -1;
|
||||
@@ -105,19 +111,92 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
|
||||
set_socket_options(fd, sockopts);
|
||||
|
||||
ret = start_inband_exchange(user, path, fd, fd, argc);
|
||||
ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv);
|
||||
|
||||
return ret ? ret : client_run(fd, fd, -1, argc, argv);
|
||||
}
|
||||
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
int argc)
|
||||
static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client)
|
||||
{
|
||||
int remote_sub = -1;
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
int our_sub = 0;
|
||||
#endif
|
||||
char *motd;
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub);
|
||||
|
||||
if (!am_client) {
|
||||
motd = lp_motd_file();
|
||||
if (motd && *motd) {
|
||||
FILE *f = fopen(motd,"r");
|
||||
while (f && !feof(f)) {
|
||||
int len = fread(buf, 1, bufsiz - 1, f);
|
||||
if (len > 0)
|
||||
write_buf(f_out, buf, len);
|
||||
}
|
||||
if (f)
|
||||
fclose(f);
|
||||
write_sbuf(f_out, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* This strips the \n. */
|
||||
if (!read_line_old(f_in, buf, bufsiz)) {
|
||||
if (am_client)
|
||||
rprintf(FERROR, "rsync: did not see server greeting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "@RSYNCD: %d.%d", &remote_protocol, &remote_sub) < 1) {
|
||||
if (am_client)
|
||||
rprintf(FERROR, "rsync: server sent \"%s\" rather than greeting\n", buf);
|
||||
else
|
||||
io_printf(f_out, "@ERROR: protocol startup error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (remote_sub < 0) {
|
||||
if (remote_protocol == 30) {
|
||||
if (am_client)
|
||||
rprintf(FERROR, "rsync: server is speaking an incompatible beta of protocol 30\n");
|
||||
else
|
||||
io_printf(f_out, "@ERROR: your client is speaking an incompatible beta of protocol 30\n");
|
||||
return -1;
|
||||
}
|
||||
remote_sub = 0;
|
||||
}
|
||||
|
||||
if (protocol_version > remote_protocol) {
|
||||
protocol_version = remote_protocol;
|
||||
if (remote_sub)
|
||||
protocol_version--;
|
||||
} else if (protocol_version == remote_protocol) {
|
||||
if (remote_sub != our_sub)
|
||||
protocol_version--;
|
||||
}
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
else if (protocol_version < remote_protocol) {
|
||||
if (our_sub)
|
||||
protocol_version--;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (protocol_version >= 30)
|
||||
rl_nulls = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char line[BIGPATHBUFLEN];
|
||||
char *sargs[MAX_ARGS];
|
||||
int sargc = 0;
|
||||
char line[BIGPATHBUFLEN];
|
||||
char *p;
|
||||
char *p, *path = *argv;
|
||||
|
||||
if (argc == 0 && !am_sender)
|
||||
list_only |= 1;
|
||||
@@ -133,24 +212,8 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
if (!user)
|
||||
user = getenv("LOGNAME");
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
|
||||
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
rprintf(FERROR, "rsync: did not see server greeting\n");
|
||||
if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(line,"@RSYNCD: %d", &remote_protocol) != 1) {
|
||||
/* note that read_line strips of \n or \r */
|
||||
rprintf(FERROR, "rsync: server sent \"%s\" rather than greeting\n",
|
||||
line);
|
||||
return -1;
|
||||
}
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
|
||||
if (list_only && protocol_version >= 29)
|
||||
list_only |= 2;
|
||||
|
||||
/* set daemon_over_rsh to false since we need to build the
|
||||
* true set of args passed through the rsh/ssh connection;
|
||||
@@ -158,18 +221,28 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
daemon_over_rsh = 0;
|
||||
server_options(sargs, &sargc);
|
||||
|
||||
if (sargc >= MAX_ARGS - 2)
|
||||
goto arg_overflow;
|
||||
|
||||
sargs[sargc++] = ".";
|
||||
|
||||
if (path && *path)
|
||||
sargs[sargc++] = path;
|
||||
while (argc > 0) {
|
||||
if (sargc >= MAX_ARGS - 1) {
|
||||
arg_overflow:
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
sargs[sargc++] = *argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
sargs[sargc] = NULL;
|
||||
|
||||
if (verbose > 1)
|
||||
print_child_argv(sargs);
|
||||
print_child_argv("sending daemon args:", sargs);
|
||||
|
||||
p = strchr(path,'/');
|
||||
if (p) *p = 0;
|
||||
p = strchr(path, '/');
|
||||
if (p) *p = '\0';
|
||||
io_printf(f_out, "%s\n", path);
|
||||
if (p) *p = '/';
|
||||
|
||||
@@ -178,7 +251,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
kluge_around_eof = list_only && protocol_version < 25 ? 1 : 0;
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
if (!read_line_old(f_in, line, sizeof line)) {
|
||||
rprintf(FERROR, "rsync: didn't get server startup line\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -213,10 +286,17 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
}
|
||||
kluge_around_eof = 0;
|
||||
|
||||
for (i = 0; i < sargc; i++) {
|
||||
io_printf(f_out, "%s\n", sargs[i]);
|
||||
if (rl_nulls) {
|
||||
for (i = 0; i < sargc; i++) {
|
||||
write_sbuf(f_out, sargs[i]);
|
||||
write_byte(f_out, 0);
|
||||
}
|
||||
write_byte(f_out, 0);
|
||||
} else {
|
||||
for (i = 0; i < sargc; i++)
|
||||
io_printf(f_out, "%s\n", sargs[i]);
|
||||
write_sbuf(f_out, "\n");
|
||||
}
|
||||
io_printf(f_out, "\n");
|
||||
|
||||
if (protocol_version < 23) {
|
||||
if (protocol_version == 22 || !am_sender)
|
||||
@@ -231,12 +311,12 @@ static char *finish_pre_exec(pid_t pid, int fd, char *request,
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (!request)
|
||||
request = "(NONE)";
|
||||
|
||||
write_buf(fd, request, strlen(request)+1);
|
||||
for (j = 0; j < argc; j++)
|
||||
write_buf(fd, argv[j], strlen(argv[j])+1);
|
||||
write_byte(fd, 0);
|
||||
|
||||
close(fd);
|
||||
@@ -244,7 +324,9 @@ static char *finish_pre_exec(pid_t pid, int fd, char *request,
|
||||
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)
|
||||
if (asprintf(&e, "pre-xfer exec returned failure (%d)%s%s\n",
|
||||
status, status < 0 ? ": " : "",
|
||||
status < 0 ? strerror(errno) : "") < 0)
|
||||
out_of_memory("finish_pre_exec");
|
||||
return e;
|
||||
}
|
||||
@@ -270,8 +352,7 @@ static int read_arg_from_pipe(int fd, char *buf, int limit)
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
{
|
||||
int argc = 0;
|
||||
int maxargs;
|
||||
int argc, opt_cnt;
|
||||
char **argv;
|
||||
char line[BIGPATHBUFLEN];
|
||||
uid_t uid = (uid_t)-2; /* canonically "nobody" */
|
||||
@@ -279,7 +360,6 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
char *p, *err_msg = NULL;
|
||||
char *name = lp_name(i);
|
||||
int use_chroot = lp_use_chroot(i);
|
||||
int start_glob = 0;
|
||||
int ret, pre_exec_fd = -1;
|
||||
pid_t pre_exec_pid = 0;
|
||||
char *request = NULL;
|
||||
@@ -340,7 +420,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
if (am_root) {
|
||||
p = lp_uid(i);
|
||||
if (!name_to_uid(p, &uid)) {
|
||||
if (!isdigit(*(unsigned char *)p)) {
|
||||
if (!isDigit(p)) {
|
||||
rprintf(FLOG, "Invalid uid %s\n", p);
|
||||
io_printf(f_out, "@ERROR: invalid uid %s\n", p);
|
||||
return -1;
|
||||
@@ -350,7 +430,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
|
||||
p = lp_gid(i);
|
||||
if (!name_to_gid(p, &gid)) {
|
||||
if (!isdigit(*(unsigned char *)p)) {
|
||||
if (!isDigit(p)) {
|
||||
rprintf(FLOG, "Invalid gid %s\n", p);
|
||||
io_printf(f_out, "@ERROR: invalid gid %s\n", p);
|
||||
return -1;
|
||||
@@ -366,11 +446,22 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
/* TODO: Perhaps take a list of gids, and make them into the
|
||||
* supplementary groups. */
|
||||
|
||||
if (use_chroot || (module_dirlen = strlen(lp_path(i))) == 1) {
|
||||
/* We do a push_dir() without actually calling chdir() in order
|
||||
* to make sure that the module's path is absolute. After this
|
||||
* check, module_dir will be set to an absolute path. */
|
||||
module_dir = lp_path(i);
|
||||
strlcpy(line, curr_dir, sizeof line);
|
||||
if (!push_dir(module_dir, 1))
|
||||
goto chdir_failed;
|
||||
if (strcmp(curr_dir, module_dir) != 0)
|
||||
module_dir = strdup(curr_dir);
|
||||
push_dir(line, 1); /* Restore curr_dir. */
|
||||
|
||||
if (use_chroot || (module_dirlen = strlen(module_dir)) == 1) {
|
||||
module_dirlen = 0;
|
||||
set_filter_dir("/", 1);
|
||||
} else
|
||||
set_filter_dir(lp_path(i), module_dirlen);
|
||||
set_filter_dir(module_dir, module_dirlen);
|
||||
|
||||
p = lp_filter(i);
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
@@ -400,7 +491,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
char *modname, *modpath, *hostaddr, *hostname, *username;
|
||||
int status;
|
||||
if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
|
||||
|| asprintf(&modpath, "RSYNC_MODULE_PATH=%s", lp_path(i)) < 0
|
||||
|| asprintf(&modpath, "RSYNC_MODULE_PATH=%s", module_dir) < 0
|
||||
|| asprintf(&hostaddr, "RSYNC_HOST_ADDR=%s", addr) < 0
|
||||
|| asprintf(&hostname, "RSYNC_HOST_NAME=%s", host) < 0
|
||||
|| asprintf(&username, "RSYNC_USER_NAME=%s", auth_user) < 0)
|
||||
@@ -500,24 +591,17 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
* a warning, unless a "require chroot" flag is set,
|
||||
* in which case we fail.
|
||||
*/
|
||||
if (chroot(lp_path(i))) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed",
|
||||
lp_path(i));
|
||||
if (chroot(module_dir)) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed", module_dir);
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/", 0)) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n",
|
||||
lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/", 0))
|
||||
goto chdir_failed;
|
||||
} else {
|
||||
if (!push_dir(lp_path(i), 0)) {
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n",
|
||||
lp_path(i));
|
||||
if (!push_dir(module_dir, 0)) {
|
||||
chdir_failed:
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", module_dir);
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -571,59 +655,23 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
|
||||
io_printf(f_out, "@RSYNCD: OK\n");
|
||||
|
||||
maxargs = MAX_ARGS;
|
||||
if (!(argv = new_array(char *, maxargs)))
|
||||
out_of_memory("rsync_module");
|
||||
argv[argc++] = "rsyncd";
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
|
||||
if (!*line)
|
||||
break;
|
||||
|
||||
p = line;
|
||||
|
||||
if (argc == maxargs) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("rsync_module");
|
||||
}
|
||||
if (!(argv[argc] = strdup(p)))
|
||||
out_of_memory("rsync_module");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
opt_cnt = read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
|
||||
|
||||
if (pre_exec_pid) {
|
||||
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
|
||||
argc, argv);
|
||||
opt_cnt, argv);
|
||||
}
|
||||
|
||||
verbose = 0; /* future verbosity is controlled by client options */
|
||||
ret = parse_arguments(&argc, (const char ***) &argv, 0);
|
||||
quiet = 0; /* Don't let someone try to be tricky. */
|
||||
am_server = 1; /* Don't let someone try to be tricky. */
|
||||
if (lp_ignore_errors(module_id))
|
||||
ignore_errors = 1;
|
||||
|
||||
if (lp_fake_super(i))
|
||||
am_root = -1;
|
||||
else if (am_root < 0) /* Treat --fake-super from client as --super. */
|
||||
am_root = 2;
|
||||
|
||||
if (filesfrom_fd == 0)
|
||||
filesfrom_fd = f_in;
|
||||
@@ -678,7 +726,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
|
||||
if (!ret || err_msg) {
|
||||
if (err_msg)
|
||||
rprintf(FERROR, err_msg);
|
||||
rwrite(FERROR, err_msg, strlen(err_msg), 0);
|
||||
else
|
||||
option_error();
|
||||
msleep(400);
|
||||
@@ -728,7 +776,7 @@ static void send_listing(int fd)
|
||||
int start_daemon(int f_in, int f_out)
|
||||
{
|
||||
char line[1024];
|
||||
char *motd, *addr, *host;
|
||||
char *addr, *host;
|
||||
int i;
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
@@ -753,35 +801,11 @@ int start_daemon(int f_in, int f_out)
|
||||
set_nonblocking(f_in);
|
||||
}
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
|
||||
|
||||
motd = lp_motd_file();
|
||||
if (motd && *motd) {
|
||||
FILE *f = fopen(motd,"r");
|
||||
while (f && !feof(f)) {
|
||||
int len = fread(line, 1, sizeof line - 1, f);
|
||||
if (len > 0) {
|
||||
line[len] = 0;
|
||||
io_printf(f_out, "%s", line);
|
||||
}
|
||||
}
|
||||
if (f)
|
||||
fclose(f);
|
||||
io_printf(f_out, "\n");
|
||||
}
|
||||
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
if (exchange_protocols(f_in, f_out, line, sizeof line, 0) < 0)
|
||||
return -1;
|
||||
|
||||
if (sscanf(line,"@RSYNCD: %d", &remote_protocol) != 1) {
|
||||
io_printf(f_out, "@ERROR: protocol startup error\n");
|
||||
return -1;
|
||||
}
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
|
||||
line[0] = 0;
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
if (!read_line_old(f_in, line, sizeof line))
|
||||
return -1;
|
||||
|
||||
if (!*line || strcmp(line, "#list") == 0) {
|
||||
@@ -812,9 +836,70 @@ int start_daemon(int f_in, int f_out)
|
||||
return rsync_module(f_in, f_out, i, addr, host);
|
||||
}
|
||||
|
||||
static void create_pid_file(void)
|
||||
{
|
||||
char *pid_file = lp_pid_file();
|
||||
char pidbuf[16];
|
||||
pid_t pid = getpid();
|
||||
int fd;
|
||||
|
||||
if (!pid_file || !*pid_file)
|
||||
return;
|
||||
|
||||
cleanup_set_pid(pid);
|
||||
if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666 & ~orig_umask)) == -1) {
|
||||
cleanup_set_pid(0);
|
||||
fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
|
||||
write(fd, pidbuf, strlen(pidbuf));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Become a daemon, discarding the controlling terminal. */
|
||||
static void become_daemon(void)
|
||||
{
|
||||
int i;
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid) {
|
||||
if (pid < 0) {
|
||||
fprintf(stderr, "failed to fork: %s\n", strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
create_pid_file();
|
||||
|
||||
/* detach from the terminal */
|
||||
#ifdef HAVE_SETSID
|
||||
setsid();
|
||||
#elif defined TIOCNOTTY
|
||||
i = open("/dev/tty", O_RDWR);
|
||||
if (i >= 0) {
|
||||
ioctl(i, (int)TIOCNOTTY, (char *)0);
|
||||
close(i);
|
||||
}
|
||||
#endif
|
||||
/* make sure that stdin, stdout an stderr don't stuff things
|
||||
* up (library functions, for example) */
|
||||
for (i = 0; i < 3; i++) {
|
||||
close(i);
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
}
|
||||
|
||||
int daemon_main(void)
|
||||
{
|
||||
char *pid_file;
|
||||
if (!config_file) {
|
||||
if (am_server && am_root <= 0)
|
||||
config_file = RSYNCD_USERCONF;
|
||||
else
|
||||
config_file = RSYNCD_SYSCONF;
|
||||
}
|
||||
|
||||
if (is_a_socket(STDIN_FILENO)) {
|
||||
int i;
|
||||
@@ -830,11 +915,15 @@ int daemon_main(void)
|
||||
return start_daemon(STDIN_FILENO, STDIN_FILENO);
|
||||
}
|
||||
|
||||
if (!no_detach)
|
||||
become_daemon();
|
||||
|
||||
if (!lp_load(config_file, 1))
|
||||
if (!lp_load(config_file, 1)) {
|
||||
fprintf(stderr, "Failed to parse config file: %s\n", config_file);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (no_detach)
|
||||
create_pid_file();
|
||||
else
|
||||
become_daemon();
|
||||
|
||||
if (rsync_port == 0 && (rsync_port = lp_rsync_port()) == 0)
|
||||
rsync_port = RSYNC_PORT;
|
||||
@@ -849,23 +938,6 @@ int daemon_main(void)
|
||||
* address too. In fact, why not just do inet_ntop on the
|
||||
* local address??? */
|
||||
|
||||
if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
|
||||
char pidbuf[16];
|
||||
int fd;
|
||||
pid_t pid = getpid();
|
||||
cleanup_set_pid(pid);
|
||||
if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC,
|
||||
0666 & ~orig_umask)) == -1) {
|
||||
cleanup_set_pid(0);
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s",
|
||||
pid_file);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
|
||||
write(fd, pidbuf, strlen(pidbuf));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
start_accept_loop(rsync_port, start_daemon);
|
||||
return -1;
|
||||
}
|
||||
|
||||
146
compat.c
146
compat.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) Andrew Tridgell 1996
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,28 +16,110 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int local_server;
|
||||
extern int inplace;
|
||||
extern int recurse;
|
||||
extern int use_qsort;
|
||||
extern int allow_inc_recurse;
|
||||
extern int append_mode;
|
||||
extern int fuzzy_basis;
|
||||
extern int read_batch;
|
||||
extern int delay_updates;
|
||||
extern int checksum_seed;
|
||||
extern int basis_dir_cnt;
|
||||
extern int prune_empty_dirs;
|
||||
extern int protocol_version;
|
||||
extern int protect_args;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int need_messages_from_generator;
|
||||
extern int delete_mode, delete_before, delete_during, delete_after;
|
||||
extern char *shell_cmd; /* contains VER.SUB string if client is a pre-release */
|
||||
extern char *partial_dir;
|
||||
extern char *dest_option;
|
||||
extern char *files_from;
|
||||
extern char *filesfrom_host;
|
||||
extern struct filter_list_struct filter_list;
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
#endif
|
||||
|
||||
/* These index values are for the file-list's extra-attribute array. */
|
||||
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx;
|
||||
#ifdef ICONV_OPTION
|
||||
int ic_ndx;
|
||||
|
||||
int filesfrom_convert = 0;
|
||||
#endif
|
||||
|
||||
/* The server makes sure that if either side only supports a pre-release
|
||||
* version of a protocol, that both sides must speak a compatible version
|
||||
* of that protocol for it to be advertised as available. */
|
||||
static void check_sub_protocol(void)
|
||||
{
|
||||
char *dot;
|
||||
int their_protocol, their_sub;
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
int our_sub = 0;
|
||||
#endif
|
||||
|
||||
if (!shell_cmd || !(dot = strchr(shell_cmd, '.'))
|
||||
|| !(their_protocol = atoi(shell_cmd))
|
||||
|| !(their_sub = atoi(dot+1))) {
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
if (our_sub)
|
||||
protocol_version--;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (their_protocol < protocol_version) {
|
||||
if (their_sub)
|
||||
protocol_version = their_protocol - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (their_protocol > protocol_version)
|
||||
their_sub = 0; /* 0 == final version of older protocol */
|
||||
if (their_sub != our_sub)
|
||||
protocol_version--;
|
||||
}
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
if (am_sender)
|
||||
file_extra_cnt += PTR_EXTRA_CNT;
|
||||
else
|
||||
file_extra_cnt++;
|
||||
if (preserve_uid)
|
||||
uid_ndx = ++file_extra_cnt;
|
||||
if (preserve_gid)
|
||||
gid_ndx = ++file_extra_cnt;
|
||||
if (preserve_acls && !am_sender)
|
||||
acls_ndx = ++file_extra_cnt;
|
||||
if (preserve_xattrs)
|
||||
xattrs_ndx = ++file_extra_cnt;
|
||||
|
||||
if (remote_protocol == 0) {
|
||||
if (am_server && !local_server)
|
||||
check_sub_protocol();
|
||||
if (!read_batch)
|
||||
write_int(f_out, protocol_version);
|
||||
remote_protocol = read_int(f_in);
|
||||
@@ -45,7 +127,7 @@ void setup_protocol(int f_out,int f_in)
|
||||
protocol_version = remote_protocol;
|
||||
}
|
||||
if (read_batch && remote_protocol > protocol_version) {
|
||||
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
|
||||
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
|
||||
remote_protocol, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
@@ -75,6 +157,32 @@ void setup_protocol(int f_out,int f_in)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (protocol_version < 30) {
|
||||
if (append_mode == 1)
|
||||
append_mode = 2;
|
||||
if (preserve_acls && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--acls requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (preserve_xattrs && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--xattrs requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_mode && !(delete_before+delete_during+delete_after)) {
|
||||
if (protocol_version < 30)
|
||||
delete_before = 1;
|
||||
else
|
||||
delete_during = 1;
|
||||
}
|
||||
|
||||
if (protocol_version < 29) {
|
||||
if (fuzzy_basis) {
|
||||
rprintf(FERROR,
|
||||
@@ -107,8 +215,36 @@ void setup_protocol(int f_out,int f_in)
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
} else if (protocol_version >= 30) {
|
||||
if (recurse && allow_inc_recurse
|
||||
&& !delete_before && !delete_after && !delay_updates
|
||||
&& !use_qsort && !prune_empty_dirs)
|
||||
inc_recurse = 1;
|
||||
need_messages_from_generator = 1;
|
||||
}
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (iconv_opt && (!am_sender || inc_recurse))
|
||||
ic_ndx = ++file_extra_cnt;
|
||||
#endif
|
||||
|
||||
if (partial_dir && *partial_dir != '/' && (!am_server || local_server)) {
|
||||
int flags = MATCHFLG_NO_PREFIXES | MATCHFLG_DIRECTORY;
|
||||
if (!am_sender || protocol_version >= 30)
|
||||
flags |= MATCHFLG_PERISHABLE;
|
||||
parse_rule(&filter_list, partial_dir, flags, 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (protect_args && files_from) {
|
||||
if (am_sender)
|
||||
filesfrom_convert = filesfrom_host && ic_send != (iconv_t)-1;
|
||||
else
|
||||
filesfrom_convert = !filesfrom_host && ic_recv != (iconv_t)-1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (am_server) {
|
||||
if (!checksum_seed)
|
||||
checksum_seed = time(NULL);
|
||||
|
||||
186
configure.in
186
configure.in
@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
RSYNC_VERSION=2.6.9
|
||||
RSYNC_VERSION=3.0.0pre2
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -38,7 +38,7 @@ fi
|
||||
AC_MSG_CHECKING([whether to include debugging symbols])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--disable-debug],
|
||||
[turn off debugging symbols and features]))
|
||||
[disable debugging symbols and features]))
|
||||
|
||||
if test x"$enable_debug" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -283,7 +283,7 @@ fi
|
||||
dnl Do you want to disable use of locale functions
|
||||
AC_ARG_ENABLE([locale],
|
||||
AC_HELP_STRING([--disable-locale],
|
||||
[turn off locale features]))
|
||||
[disable 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
|
||||
@@ -339,8 +339,14 @@ AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(int16_t)
|
||||
AC_CHECK_SIZEOF(uint16_t)
|
||||
AC_CHECK_SIZEOF(int32_t)
|
||||
AC_CHECK_SIZEOF(uint32_t)
|
||||
AC_CHECK_SIZEOF(int64_t)
|
||||
AC_CHECK_SIZEOF(off_t)
|
||||
AC_CHECK_SIZEOF(off64_t)
|
||||
AC_CHECK_SIZEOF(time_t)
|
||||
|
||||
AC_C_INLINE
|
||||
AC_C_LONG_DOUBLE
|
||||
@@ -405,6 +411,28 @@ AC_SEARCH_LIBS(inet_ntop, resolv)
|
||||
# Search for libiconv_open (not iconv_open) to discover if -liconv is needed!
|
||||
AC_SEARCH_LIBS(libiconv_open, iconv)
|
||||
|
||||
AC_MSG_CHECKING([for iconv declaration])
|
||||
AC_CACHE_VAL(am_cv_proto_iconv, [
|
||||
AC_TRY_COMPILE([
|
||||
#include <stdlib.h>
|
||||
#include <iconv.h>
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
|
||||
#else
|
||||
size_t iconv();
|
||||
#endif
|
||||
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
|
||||
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
|
||||
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
|
||||
AC_MSG_RESULT([$]{ac_t:-
|
||||
}[$]am_cv_proto_iconv)
|
||||
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
|
||||
[Define as const if the declaration of iconv() needs const.])
|
||||
|
||||
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
|
||||
|
||||
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
|
||||
@@ -515,6 +543,11 @@ if test x"$ac_cv_func_strcasecmp" = x"no"; then
|
||||
AC_CHECK_LIB(resolv, strcasecmp)
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(aclsort)
|
||||
if test x"$ac_cv_func_aclsort" = x"no"; then
|
||||
AC_CHECK_LIB(sec, aclsort)
|
||||
fi
|
||||
|
||||
dnl At the moment we don't test for a broken memcmp(), because all we
|
||||
dnl need to do is test for equality, not comparison, and it seems that
|
||||
dnl every platform has a memcmp that can do at least that.
|
||||
@@ -527,14 +560,30 @@ 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 iconv_open locale_charset nl_langinfo \
|
||||
sigaction sigprocmask)
|
||||
strerror putenv iconv_open locale_charset nl_langinfo getxattr \
|
||||
extattr_get_link sigaction sigprocmask)
|
||||
|
||||
AC_CHECK_FUNCS(getpgrp tcgetpgrp)
|
||||
if test $ac_cv_func_getpgrp = yes; then
|
||||
AC_FUNC_GETPGRP
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
AC_HELP_STRING([--disable-iconv],
|
||||
[disable rsync's --iconv option]),
|
||||
[], [enable_iconv=$ac_cv_func_iconv_open])
|
||||
AH_TEMPLATE([ICONV_OPTION],
|
||||
[Define if you want the --iconv option. Specifing a value will set the
|
||||
default iconv setting (a NULL means no --iconv processing by default).])
|
||||
if test x"$enable_iconv" != x"no"; then
|
||||
if test x"$enable_iconv" = x"yes"; then
|
||||
AC_DEFINE(ICONV_OPTION, NULL)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(ICONV_OPTION, "$enable_iconv")
|
||||
fi
|
||||
AC_DEFINE(UTF8_CHARSET, "UTF-8", [String to pass to iconv() for the UTF-8 charset.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether chown() modifies symlinks],rsync_cv_chown_modifies_symlink,[
|
||||
AC_TRY_RUN([
|
||||
#if HAVE_UNISTD_H
|
||||
@@ -779,6 +828,133 @@ AC_SUBST(OBJ_RESTORE)
|
||||
AC_SUBST(CC_SHOBJ_FLAG)
|
||||
AC_SUBST(BUILD_POPT)
|
||||
|
||||
AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
|
||||
AC_CHECK_FUNCS(_acl __acl _facl __facl)
|
||||
#################################################
|
||||
# check for ACL support
|
||||
|
||||
AC_MSG_CHECKING([whether to support ACLs])
|
||||
AC_ARG_ENABLE(acl-support,
|
||||
AC_HELP_STRING([--disable-acl-support],
|
||||
[disable ACL support]))
|
||||
|
||||
if test x"$enable_acl_support" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
case "$host_os" in
|
||||
*sysv5*)
|
||||
AC_MSG_RESULT(Using UnixWare ACLs)
|
||||
AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1, [Define to 1 to add support for ACLs])
|
||||
;;
|
||||
*solaris*|*cygwin*)
|
||||
AC_MSG_RESULT(Using solaris ACLs)
|
||||
AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*hpux*)
|
||||
AC_MSG_RESULT(Using HPUX ACLs)
|
||||
AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*irix*)
|
||||
AC_MSG_RESULT(Using IRIX ACLs)
|
||||
AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*aix*)
|
||||
AC_MSG_RESULT(Using AIX ACLs)
|
||||
AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*osf*)
|
||||
AC_MSG_RESULT(Using Tru64 ACLs)
|
||||
AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
LIBS="$LIBS -lpacl"
|
||||
;;
|
||||
darwin*)
|
||||
AC_MSG_RESULT(Using OS X ACLs)
|
||||
AC_DEFINE(HAVE_OSX_ACLS, 1, [true if you have Mac OS X ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(running tests:)
|
||||
AC_CHECK_LIB(acl,acl_get_file)
|
||||
AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/acl.h>],
|
||||
[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
|
||||
samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
|
||||
AC_MSG_CHECKING(ACL test results)
|
||||
if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
|
||||
AC_MSG_RESULT(Using posix ACLs)
|
||||
AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/acl.h>],
|
||||
[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
|
||||
samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
|
||||
if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
|
||||
fi
|
||||
else
|
||||
if test x"$enable_acl_support" = x"yes"; then
|
||||
AC_MSG_ERROR(Failed to find ACL support)
|
||||
else
|
||||
AC_MSG_RESULT(No ACL support found)
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS(attr/xattr.h)
|
||||
AC_CHECK_HEADERS(sys/xattr.h)
|
||||
AC_CHECK_HEADERS(sys/extattr.h)
|
||||
|
||||
#################################################
|
||||
# check for extended attribute support
|
||||
AC_MSG_CHECKING(whether to support extended attributes)
|
||||
AC_ARG_ENABLE(xattr-support,
|
||||
AC_HELP_STRING([--disable-xattr-support],
|
||||
[disable extended attributes]),
|
||||
[], [case "$ac_cv_func_getxattr$ac_cv_func_extattr_get_link" in
|
||||
*yes*) enable_xattr_support=maybe ;;
|
||||
*) enable_xattr_support=no ;;
|
||||
esac])
|
||||
AH_TEMPLATE([SUPPORT_XATTRS],
|
||||
[Define to 1 to add support for extended attributes])
|
||||
if test x"$enable_xattr_support" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
case "$host_os" in
|
||||
*linux*)
|
||||
AC_MSG_RESULT(Using Linux xattrs)
|
||||
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
darwin*)
|
||||
AC_MSG_RESULT(Using OS X xattrs)
|
||||
AC_DEFINE(HAVE_OSX_XATTRS, 1, [True if you have Mac OS X xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
freebsd*)
|
||||
AC_MSG_RESULT(Using FreeBSD extattrs)
|
||||
AC_DEFINE(HAVE_FREEBSD_XATTRS, 1, [True if you have FreeBSD xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
*)
|
||||
if test x"$enable_xattr_support" = x"yes"; then
|
||||
AC_MSG_ERROR(Failed to find extended attribute support)
|
||||
else
|
||||
AC_MSG_RESULT(No extended attribute support found)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
33
connection.c
33
connection.c
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -14,36 +14,33 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
/****************************************************************************
|
||||
simple routine to do connection counting
|
||||
****************************************************************************/
|
||||
int claim_connection(char *fname,int max_connections)
|
||||
/* A simple routine to do connection counting. This returns 1 on success
|
||||
* and 0 on failure, with errno also being set if the open() failed (errno
|
||||
* will be 0 if the lock request failed). */
|
||||
int claim_connection(char *fname, int max_connections)
|
||||
{
|
||||
int fd, i;
|
||||
|
||||
if (max_connections <= 0)
|
||||
if (max_connections == 0)
|
||||
return 1;
|
||||
|
||||
fd = open(fname,O_RDWR|O_CREAT, 0600);
|
||||
|
||||
if (fd == -1) {
|
||||
if ((fd = open(fname, O_RDWR|O_CREAT, 0600)) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find a free spot */
|
||||
for (i=0;i<max_connections;i++) {
|
||||
if (lock_range(fd, i*4, 4)) return 1;
|
||||
/* Find a free spot. */
|
||||
for (i = 0; i < max_connections; i++) {
|
||||
if (lock_range(fd, i*4, 4))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* only interested in open failures */
|
||||
errno = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
/* A lock failure needs to return an errno of 0. */
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* Error codes returned by rsync.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2003, 2005 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* If you change these, please also update the string mappings in log.c and
|
||||
|
||||
70
exclude.c
70
exclude.c
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -27,11 +26,11 @@ extern int verbose;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int eol_nulls;
|
||||
extern int list_only;
|
||||
extern int recurse;
|
||||
extern int io_error;
|
||||
extern int local_server;
|
||||
extern int prune_empty_dirs;
|
||||
extern int ignore_perishable;
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
extern int cvs_exclude;
|
||||
@@ -51,8 +50,8 @@ struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
|
||||
#define MAX_RULE_PREFIX (16)
|
||||
|
||||
#define MODIFIERS_MERGE_FILE "-+Cenw"
|
||||
#define MODIFIERS_INCL_EXCL "/!Crs"
|
||||
#define MODIFIERS_HIDE_PROTECT "/!"
|
||||
#define MODIFIERS_INCL_EXCL "/!Crsp"
|
||||
#define MODIFIERS_HIDE_PROTECT "/!p"
|
||||
|
||||
/* The dirbuf is set by push_local_filters() to the current subdirectory
|
||||
* relative to curr_dir that is being processed. The path always has a
|
||||
@@ -144,9 +143,8 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ret = new(struct filter_struct)))
|
||||
if (!(ret = new0(struct filter_struct)))
|
||||
out_of_memory("add_rule");
|
||||
memset(ret, 0, sizeof ret[0]);
|
||||
|
||||
if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))
|
||||
&& ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/')
|
||||
@@ -492,6 +490,34 @@ void pop_local_filters(void *mem)
|
||||
free(pop);
|
||||
}
|
||||
|
||||
void change_local_filter_dir(const char *dname, int dlen, int dir_depth)
|
||||
{
|
||||
static int cur_depth = -1;
|
||||
static void *filt_array[MAXPATHLEN/2+1];
|
||||
|
||||
if (!dname) {
|
||||
for ( ; cur_depth >= 0; cur_depth--) {
|
||||
if (filt_array[cur_depth]) {
|
||||
pop_local_filters(filt_array[cur_depth]);
|
||||
filt_array[cur_depth] = NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(dir_depth < MAXPATHLEN/2+1);
|
||||
|
||||
for ( ; cur_depth >= dir_depth; cur_depth--) {
|
||||
if (filt_array[cur_depth]) {
|
||||
pop_local_filters(filt_array[cur_depth]);
|
||||
filt_array[cur_depth] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cur_depth = dir_depth;
|
||||
filt_array[cur_depth] = push_local_filters(dname, dlen);
|
||||
}
|
||||
|
||||
static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir)
|
||||
{
|
||||
int slash_handling, str_cnt = 0, anchored_match = 0;
|
||||
@@ -601,6 +627,8 @@ int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
|
||||
struct filter_struct *ent;
|
||||
|
||||
for (ent = listp->head; ent; ent = ent->next) {
|
||||
if (ignore_perishable && ent->match_flags & MATCHFLG_PERISHABLE)
|
||||
continue;
|
||||
if (ent->match_flags & MATCHFLG_PERDIR_MERGE) {
|
||||
int rc = check_filter(ent->u.mergelist, name,
|
||||
name_is_dir);
|
||||
@@ -808,6 +836,9 @@ static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags,
|
||||
case 'n':
|
||||
new_mflags |= MATCHFLG_NO_INHERIT;
|
||||
break;
|
||||
case 'p':
|
||||
new_mflags |= MATCHFLG_PERISHABLE;
|
||||
break;
|
||||
case 'r':
|
||||
new_mflags |= MATCHFLG_RECEIVER_SIDE;
|
||||
break;
|
||||
@@ -873,14 +904,16 @@ static char default_cvsignore[] =
|
||||
|
||||
static void get_cvs_excludes(uint32 mflags)
|
||||
{
|
||||
char *p, fname[MAXPATHLEN];
|
||||
static int initialized = 0;
|
||||
char *p, fname[MAXPATHLEN];
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = 1;
|
||||
|
||||
parse_rule(&cvs_filter_list, default_cvsignore, mflags, 0);
|
||||
parse_rule(&cvs_filter_list, default_cvsignore,
|
||||
mflags | (protocol_version >= 30 ? MATCHFLG_PERISHABLE : 0),
|
||||
0);
|
||||
|
||||
p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME");
|
||||
if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN)
|
||||
@@ -1064,6 +1097,8 @@ char *get_rule_prefix(int match_flags, const char *pat, int for_xfer,
|
||||
else
|
||||
legal_len = 0;
|
||||
|
||||
if (match_flags & MATCHFLG_NEGATE)
|
||||
*op++ = '!';
|
||||
if (match_flags & MATCHFLG_CVS_IGNORE)
|
||||
*op++ = 'C';
|
||||
else {
|
||||
@@ -1087,6 +1122,12 @@ char *get_rule_prefix(int match_flags, const char *pat, int for_xfer,
|
||||
&& (!for_xfer || protocol_version >= 29
|
||||
|| (delete_excluded && am_sender)))
|
||||
*op++ = 'r';
|
||||
if (match_flags & MATCHFLG_PERISHABLE) {
|
||||
if (!for_xfer || protocol_version >= 30)
|
||||
*op++ = 'p';
|
||||
else if (am_sender)
|
||||
return NULL;
|
||||
}
|
||||
if (op - buf > legal_len)
|
||||
return NULL;
|
||||
if (legal_len)
|
||||
@@ -1141,7 +1182,7 @@ static void send_rules(int f_out, struct filter_list_struct *flp)
|
||||
if (!p) {
|
||||
rprintf(FERROR,
|
||||
"filter rules are too modern for remote rsync.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (f_out < 0)
|
||||
continue;
|
||||
@@ -1173,11 +1214,6 @@ void send_filter_list(int f_out)
|
||||
parse_rule(&filter_list, "-C", 0, 0);
|
||||
}
|
||||
|
||||
/* This is a complete hack - blame Rusty. FIXME!
|
||||
* Remove this hack when older rsyncs (below 2.6.4) are gone. */
|
||||
if (list_only == 1 && !recurse)
|
||||
parse_rule(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0);
|
||||
|
||||
send_rules(f_out, &filter_list);
|
||||
|
||||
if (f_out >= 0)
|
||||
|
||||
68
fileio.c
68
fileio.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -29,47 +28,55 @@
|
||||
extern int sparse_files;
|
||||
|
||||
static char last_byte;
|
||||
static int last_sparse;
|
||||
static size_t sparse_seek = 0;
|
||||
|
||||
int sparse_end(int f)
|
||||
{
|
||||
if (last_sparse) {
|
||||
do_lseek(f,-1,SEEK_CUR);
|
||||
return (write(f,&last_byte,1) == 1 ? 0 : -1);
|
||||
}
|
||||
last_sparse = 0;
|
||||
return 0;
|
||||
int ret;
|
||||
|
||||
if (!sparse_seek)
|
||||
return 0;
|
||||
|
||||
do_lseek(f, sparse_seek-1, SEEK_CUR);
|
||||
sparse_seek = 0;
|
||||
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
return ret <= 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_sparse(int f,char *buf,size_t len)
|
||||
static int write_sparse(int f, char *buf, size_t len)
|
||||
{
|
||||
size_t l1=0, l2=0;
|
||||
size_t l1 = 0, l2 = 0;
|
||||
int ret;
|
||||
|
||||
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
|
||||
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
|
||||
|
||||
/* XXX Riddle me this: why does this function SLOW DOWN when I
|
||||
* remove the following (unneeded) line?? Core Duo weirdness? */
|
||||
last_byte = buf[len-1];
|
||||
|
||||
if (l1 == len || l2 > 0)
|
||||
last_sparse=1;
|
||||
|
||||
if (l1 > 0) {
|
||||
do_lseek(f,l1,SEEK_CUR);
|
||||
}
|
||||
sparse_seek += l1;
|
||||
|
||||
if (l1 == len)
|
||||
return len;
|
||||
|
||||
ret = write(f, buf + l1, len - (l1+l2));
|
||||
if (ret == -1 || ret == 0)
|
||||
return ret;
|
||||
else if (ret != (int) (len - (l1+l2)))
|
||||
return (l1+ret);
|
||||
if (sparse_seek)
|
||||
do_lseek(f, sparse_seek, SEEK_CUR);
|
||||
sparse_seek = l2;
|
||||
|
||||
if (l2 > 0)
|
||||
do_lseek(f,l2,SEEK_CUR);
|
||||
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
|
||||
if (ret < 0 && errno == EINTR)
|
||||
continue;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != (int)(len - (l1+l2)))
|
||||
return l1+ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -107,7 +114,7 @@ int write_file(int f,char *buf,size_t len)
|
||||
|
||||
while (len > 0) {
|
||||
int r1;
|
||||
if (sparse_files) {
|
||||
if (sparse_files > 0) {
|
||||
int len1 = MIN(len, SPARSE_WRITE_SIZE);
|
||||
r1 = write_sparse(f, buf, len1);
|
||||
} else {
|
||||
@@ -152,13 +159,12 @@ struct map_struct *map_file(int fd, OFF_T len, int32 read_size,
|
||||
{
|
||||
struct map_struct *map;
|
||||
|
||||
if (!(map = new(struct map_struct)))
|
||||
if (!(map = new0(struct map_struct)))
|
||||
out_of_memory("map_file");
|
||||
|
||||
if (blk_size && (read_size % blk_size))
|
||||
read_size += blk_size - (read_size % blk_size);
|
||||
|
||||
memset(map, 0, sizeof map[0]);
|
||||
map->fd = fd;
|
||||
map->file_size = len;
|
||||
map->def_window_size = read_size;
|
||||
@@ -190,7 +196,7 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
||||
window_start = offset;
|
||||
window_size = map->def_window_size;
|
||||
if (window_start + window_size > map->file_size)
|
||||
window_size = map->file_size - window_start;
|
||||
window_size = (int32)(map->file_size - window_start);
|
||||
if (len > window_size)
|
||||
window_size = len;
|
||||
|
||||
@@ -208,7 +214,7 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
||||
window_start < map->p_offset + map->p_len &&
|
||||
window_start + window_size >= map->p_offset + map->p_len) {
|
||||
read_start = map->p_offset + map->p_len;
|
||||
read_offset = read_start - window_start;
|
||||
read_offset = (int32)(read_start - window_start);
|
||||
read_size = window_size - read_offset;
|
||||
memmove(map->p, map->p + (map->p_len - read_offset), read_offset);
|
||||
} else {
|
||||
|
||||
1737
generator.c
1737
generator.c
File diff suppressed because it is too large
Load Diff
10
getgroups.c
10
getgroups.c
@@ -3,12 +3,11 @@
|
||||
* `id -G` on Linux, but it's too hard to find a portable equivalent.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003, 2004 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -16,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
145
hashtable.c
Normal file
145
hashtable.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#define HASH_LOAD_LIMIT(size) ((size)*3/4)
|
||||
|
||||
struct hashtable *hashtable_create(int size, int key64)
|
||||
{
|
||||
struct hashtable *tbl;
|
||||
int node_size = key64 ? sizeof (struct ht_int64_node )
|
||||
: sizeof (struct ht_int32_node);
|
||||
|
||||
/* Pick a power of 2 that can hold the requested size. */
|
||||
if (size & (size-1) || size < 16) {
|
||||
int req = size;
|
||||
size = 16;
|
||||
while (size < req)
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
if (!(tbl = new(struct hashtable))
|
||||
|| !(tbl->nodes = new_array0(char, size * node_size)))
|
||||
out_of_memory("hashtable_create");
|
||||
tbl->size = size;
|
||||
tbl->entries = 0;
|
||||
tbl->node_size = node_size;
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
void hashtable_destroy(struct hashtable *tbl)
|
||||
{
|
||||
free(tbl->nodes);
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
/* This returns the node for the indicated key, either newly created or
|
||||
* already existing. Returns NULL if not allocating and not found. */
|
||||
void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
{
|
||||
int key64 = (tbl->node_size > sizeof (struct ht_int32_node));
|
||||
struct ht_int32_node *node;
|
||||
uint32 ndx;
|
||||
|
||||
if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
|
||||
void *old_nodes = tbl->nodes;
|
||||
int size = tbl->size * 2;
|
||||
int i;
|
||||
|
||||
if (!(tbl->nodes = new_array0(char, size * tbl->node_size)))
|
||||
out_of_memory("hashtable_node");
|
||||
tbl->size = size;
|
||||
tbl->entries = 0;
|
||||
|
||||
for (i = size / 2; i-- > 0; ) {
|
||||
struct ht_int32_node *move_node = HT_NODE(tbl, old_nodes, i);
|
||||
int64 move_key = HT_KEY(move_node, key64);
|
||||
if (move_key == 0)
|
||||
continue;
|
||||
node = hashtable_find(tbl, move_key, 1);
|
||||
node->data = move_node->data;
|
||||
}
|
||||
|
||||
free(old_nodes);
|
||||
}
|
||||
|
||||
if (!key64) {
|
||||
/* Based on Jenkins One-at-a-time hash. */
|
||||
uchar buf[4], *keyp = buf;
|
||||
int i;
|
||||
|
||||
SIVAL(buf, 0, key);
|
||||
for (ndx = 0, i = 0; i < 4; i++) {
|
||||
ndx += keyp[i];
|
||||
ndx += (ndx << 10);
|
||||
ndx ^= (ndx >> 6);
|
||||
}
|
||||
ndx += (ndx << 3);
|
||||
ndx ^= (ndx >> 11);
|
||||
ndx += (ndx << 15);
|
||||
} else {
|
||||
/* Based on Jenkins hashword() from lookup3.c. */
|
||||
uint32 a, b, c;
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + (8 << 2);
|
||||
|
||||
#define rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k))))
|
||||
b += (uint32)(key >> 32);
|
||||
a += (uint32)key;
|
||||
c ^= b; c -= rot(b, 14);
|
||||
a ^= c; a -= rot(c, 11);
|
||||
b ^= a; b -= rot(a, 25);
|
||||
c ^= b; c -= rot(b, 16);
|
||||
a ^= c; a -= rot(c, 4);
|
||||
b ^= a; b -= rot(a, 14);
|
||||
c ^= b; c -= rot(b, 24);
|
||||
#undef rot
|
||||
ndx = c;
|
||||
}
|
||||
|
||||
/* If it already exists, return the node. If we're not
|
||||
* allocating, return NULL if the key is not found. */
|
||||
while (1) {
|
||||
int64 nkey;
|
||||
|
||||
ndx &= tbl->size - 1;
|
||||
node = HT_NODE(tbl, tbl->nodes, ndx);
|
||||
nkey = HT_KEY(node, key64);
|
||||
|
||||
if (nkey == key)
|
||||
return node;
|
||||
if (nkey == 0) {
|
||||
if (!allocate_if_missing)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
ndx++;
|
||||
}
|
||||
|
||||
/* Take over this empty spot and then return the node. */
|
||||
if (key64)
|
||||
((struct ht_int64_node*)node)->key = key;
|
||||
else
|
||||
node->key = key;
|
||||
tbl->entries++;
|
||||
return node;
|
||||
}
|
||||
636
hlink.c
636
hlink.c
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,151 +17,209 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int am_sender;
|
||||
extern int inc_recurse;
|
||||
extern int do_xfers;
|
||||
extern int link_dest;
|
||||
extern int preserve_acls;
|
||||
extern int make_backups;
|
||||
extern int protocol_version;
|
||||
extern int remove_source_files;
|
||||
extern int stdout_format_has_i;
|
||||
extern int maybe_ATTRS_REPORT;
|
||||
extern char *basis_dir[];
|
||||
extern struct file_list *the_file_list;
|
||||
extern struct file_list *cur_flist;
|
||||
#ifdef ICONV_OPTION
|
||||
extern int ic_ndx;
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
|
||||
#define SKIPPED_LINK (-1)
|
||||
#define FINISHED_LINK (-2)
|
||||
/* Starting with protocol 30, we use a simple hashtable on the sending side
|
||||
* for hashing the st_dev and st_ino info. The receiving side gets told
|
||||
* (via flags and a "group index") which items are hard-linked together, so
|
||||
* we can avoid the pool of dev+inode data. For incremental recursion mode,
|
||||
* the receiver will use a ndx hash to remember old pathnames. */
|
||||
|
||||
#define FPTR(i) (the_file_list->files[i])
|
||||
#define LINKED(p1,p2) (FPTR(p1)->F_DEV == FPTR(p2)->F_DEV \
|
||||
&& FPTR(p1)->F_INODE == FPTR(p2)->F_INODE)
|
||||
static struct hashtable *dev_tbl;
|
||||
|
||||
static int hlink_compare(int *int1, int *int2)
|
||||
{
|
||||
struct file_struct *f1 = FPTR(*int1);
|
||||
struct file_struct *f2 = FPTR(*int2);
|
||||
static struct hashtable *prior_hlinks;
|
||||
|
||||
if (f1->F_DEV != f2->F_DEV)
|
||||
return (int) (f1->F_DEV > f2->F_DEV ? 1 : -1);
|
||||
|
||||
if (f1->F_INODE != f2->F_INODE)
|
||||
return (int) (f1->F_INODE > f2->F_INODE ? 1 : -1);
|
||||
|
||||
return f_name_cmp(f1, f2);
|
||||
}
|
||||
|
||||
static int32 *hlink_list;
|
||||
static int32 hlink_count;
|
||||
|
||||
/* Analyze the data in the hlink_list[], remove items that aren't multiply
|
||||
* linked, and replace the dev+inode data with the hlindex+next linked list. */
|
||||
static void link_idev_data(void)
|
||||
{
|
||||
int32 cur, from, to, start;
|
||||
|
||||
alloc_pool_t hlink_pool;
|
||||
alloc_pool_t idev_pool = the_file_list->hlink_pool;
|
||||
|
||||
hlink_pool = pool_create(128 * 1024, sizeof (struct hlink),
|
||||
out_of_memory, POOL_INTERN);
|
||||
|
||||
for (from = to = 0; from < hlink_count; from++) {
|
||||
start = from;
|
||||
while (1) {
|
||||
cur = hlink_list[from];
|
||||
if (from == hlink_count-1
|
||||
|| !LINKED(cur, hlink_list[from+1]))
|
||||
break;
|
||||
pool_free(idev_pool, 0, FPTR(cur)->link_u.idev);
|
||||
FPTR(cur)->link_u.links = pool_talloc(hlink_pool,
|
||||
struct hlink, 1, "hlink_list");
|
||||
|
||||
FPTR(cur)->F_HLINDEX = to;
|
||||
FPTR(cur)->F_NEXT = hlink_list[++from];
|
||||
FPTR(cur)->link_u.links->link_dest_used = 0;
|
||||
}
|
||||
pool_free(idev_pool, 0, FPTR(cur)->link_u.idev);
|
||||
if (from > start) {
|
||||
int head = hlink_list[start];
|
||||
FPTR(cur)->link_u.links = pool_talloc(hlink_pool,
|
||||
struct hlink, 1, "hlink_list");
|
||||
|
||||
FPTR(head)->flags |= FLAG_HLINK_TOL;
|
||||
FPTR(cur)->F_HLINDEX = to;
|
||||
FPTR(cur)->F_NEXT = head;
|
||||
FPTR(cur)->flags |= FLAG_HLINK_EOL;
|
||||
FPTR(cur)->link_u.links->link_dest_used = 0;
|
||||
hlink_list[to++] = head;
|
||||
} else
|
||||
FPTR(cur)->link_u.links = NULL;
|
||||
}
|
||||
|
||||
if (!to) {
|
||||
free(hlink_list);
|
||||
hlink_list = NULL;
|
||||
pool_destroy(hlink_pool);
|
||||
hlink_pool = NULL;
|
||||
} else {
|
||||
hlink_count = to;
|
||||
hlink_list = realloc_array(hlink_list, int32, hlink_count);
|
||||
if (!hlink_list)
|
||||
out_of_memory("init_hard_links");
|
||||
}
|
||||
the_file_list->hlink_pool = hlink_pool;
|
||||
pool_destroy(idev_pool);
|
||||
}
|
||||
#endif
|
||||
static struct file_list *hlink_flist;
|
||||
|
||||
void init_hard_links(void)
|
||||
{
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
int i;
|
||||
|
||||
if (hlink_list)
|
||||
free(hlink_list);
|
||||
|
||||
if (!(hlink_list = new_array(int32, the_file_list->count)))
|
||||
out_of_memory("init_hard_links");
|
||||
|
||||
hlink_count = 0;
|
||||
for (i = 0; i < the_file_list->count; i++) {
|
||||
if (FPTR(i)->link_u.idev)
|
||||
hlink_list[hlink_count++] = i;
|
||||
}
|
||||
|
||||
qsort(hlink_list, hlink_count,
|
||||
sizeof hlink_list[0], (int (*)()) hlink_compare);
|
||||
|
||||
if (!hlink_count) {
|
||||
free(hlink_list);
|
||||
hlink_list = NULL;
|
||||
} else
|
||||
link_idev_data();
|
||||
#endif
|
||||
if (am_sender || protocol_version < 30)
|
||||
dev_tbl = hashtable_create(16, SIZEOF_INT64 == 8);
|
||||
else if (inc_recurse)
|
||||
prior_hlinks = hashtable_create(1024, 0);
|
||||
}
|
||||
|
||||
struct ht_int64_node *idev_find(int64 dev, int64 ino)
|
||||
{
|
||||
static struct ht_int64_node *dev_node = NULL;
|
||||
struct hashtable *tbl;
|
||||
|
||||
if (!dev_node || dev_node->key != dev) {
|
||||
/* We keep a separate hash table of inodes for every device. */
|
||||
dev_node = hashtable_find(dev_tbl, dev, 1);
|
||||
if (!(tbl = dev_node->data))
|
||||
tbl = dev_node->data = hashtable_create(512, SIZEOF_INT64 == 8);
|
||||
} else
|
||||
tbl = dev_node->data;
|
||||
|
||||
return hashtable_find(tbl, ino, 1);
|
||||
}
|
||||
|
||||
void idev_destroy(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev_tbl->size; i++) {
|
||||
struct ht_int32_node *node = HT_NODE(dev_tbl, dev_tbl->nodes, i);
|
||||
if (node->data)
|
||||
hashtable_destroy(node->data);
|
||||
}
|
||||
|
||||
hashtable_destroy(dev_tbl);
|
||||
}
|
||||
|
||||
static int hlink_compare_gnum(int *int1, int *int2)
|
||||
{
|
||||
struct file_struct *f1 = hlink_flist->sorted[*int1];
|
||||
struct file_struct *f2 = hlink_flist->sorted[*int2];
|
||||
int32 gnum1 = F_HL_GNUM(f1);
|
||||
int32 gnum2 = F_HL_GNUM(f2);
|
||||
|
||||
if (gnum1 != gnum2)
|
||||
return gnum1 > gnum2 ? 1 : -1;
|
||||
|
||||
return *int1 > *int2 ? 1 : -1;
|
||||
}
|
||||
|
||||
static void match_gnums(int32 *ndx_list, int ndx_count)
|
||||
{
|
||||
int32 from, prev;
|
||||
struct file_struct *file, *file_next;
|
||||
struct ht_int32_node *node = NULL;
|
||||
int32 gnum, gnum_next;
|
||||
|
||||
qsort(ndx_list, ndx_count, sizeof ndx_list[0],
|
||||
(int (*)()) hlink_compare_gnum);
|
||||
|
||||
for (from = 0; from < ndx_count; from++) {
|
||||
file = hlink_flist->sorted[ndx_list[from]];
|
||||
gnum = F_HL_GNUM(file);
|
||||
if (inc_recurse) {
|
||||
node = hashtable_find(prior_hlinks, gnum, 1);
|
||||
if (!node->data) {
|
||||
node->data = new_array0(char, 5);
|
||||
assert(gnum >= hlink_flist->ndx_start);
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
} else if (CVAL(node->data, 0) == 0) {
|
||||
struct file_list *flist;
|
||||
struct file_struct *fp;
|
||||
prev = IVAL(node->data, 1);
|
||||
flist = flist_for_ndx(prev);
|
||||
assert(flist != NULL);
|
||||
fp = flist->files[prev - flist->ndx_start];
|
||||
fp->flags &= ~FLAG_HLINK_LAST;
|
||||
} else
|
||||
prev = -1;
|
||||
} else {
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
}
|
||||
for ( ; from < ndx_count-1; file = file_next, gnum = gnum_next, from++) { /*SHARED ITERATOR*/
|
||||
file_next = hlink_flist->sorted[ndx_list[from+1]];
|
||||
gnum_next = F_HL_GNUM(file_next);
|
||||
if (gnum != gnum_next)
|
||||
break;
|
||||
F_HL_PREV(file) = prev;
|
||||
/* The linked list must use raw ndx values. */
|
||||
#ifdef ICONV_OPTION
|
||||
if (ic_ndx)
|
||||
prev = F_NDX(file);
|
||||
else
|
||||
#endif
|
||||
prev = ndx_list[from] + hlink_flist->ndx_start;
|
||||
}
|
||||
if (prev < 0 && !inc_recurse) {
|
||||
/* Disable hard-link bit and set DONE so that
|
||||
* HLINK_BUMP()-dependent values are unaffected. */
|
||||
file->flags &= ~(FLAG_HLINKED | FLAG_HLINK_FIRST);
|
||||
file->flags |= FLAG_HLINK_DONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
file->flags |= FLAG_HLINK_LAST;
|
||||
F_HL_PREV(file) = prev;
|
||||
if (inc_recurse && CVAL(node->data, 0) == 0) {
|
||||
#ifdef ICONV_OPTION
|
||||
if (ic_ndx)
|
||||
prev = F_NDX(file);
|
||||
else
|
||||
#endif
|
||||
prev = ndx_list[from] + hlink_flist->ndx_start;
|
||||
SIVAL(node->data, 1, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Analyze the hard-links in the file-list by creating a list of all the
|
||||
* items that have hlink data, sorting them, and matching up identical
|
||||
* values into clusters. These will be a single linked list from last
|
||||
* to first when we're done. */
|
||||
void match_hard_links(struct file_list *flist)
|
||||
{
|
||||
int i, ndx_count = 0;
|
||||
int32 *ndx_list;
|
||||
|
||||
if (!(ndx_list = new_array(int32, flist->used)))
|
||||
out_of_memory("match_hard_links");
|
||||
|
||||
for (i = 0; i < flist->used; i++) {
|
||||
if (F_IS_HLINKED(flist->sorted[i]))
|
||||
ndx_list[ndx_count++] = i;
|
||||
}
|
||||
|
||||
hlink_flist = flist;
|
||||
|
||||
if (ndx_count)
|
||||
match_gnums(ndx_list, ndx_count);
|
||||
|
||||
free(ndx_list);
|
||||
if (protocol_version < 30)
|
||||
idev_destroy();
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static int maybe_hard_link(struct file_struct *file, int ndx,
|
||||
char *fname, int statret, STRUCT_STAT *st,
|
||||
char *toname, STRUCT_STAT *to_st,
|
||||
int itemizing, enum logcode code)
|
||||
const char *fname, int statret, stat_x *sxp,
|
||||
const char *oldname, STRUCT_STAT *old_stp,
|
||||
const char *realname, int itemizing, enum logcode code)
|
||||
{
|
||||
if (statret == 0) {
|
||||
if (st->st_dev == to_st->st_dev
|
||||
&& st->st_ino == to_st->st_ino) {
|
||||
if (sxp->st.st_dev == old_stp->st_dev
|
||||
&& sxp->st.st_ino == old_stp->st_ino) {
|
||||
if (itemizing) {
|
||||
itemize(file, ndx, statret, st,
|
||||
itemize(fname, file, ndx, statret, sxp,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
|
||||
0, "");
|
||||
}
|
||||
if (verbose > 1 && maybe_ATTRS_REPORT)
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
file->flags |= FLAG_HLINK_DONE;
|
||||
return 0;
|
||||
}
|
||||
if (make_backups) {
|
||||
if (make_backups > 0) {
|
||||
if (!make_backup(fname))
|
||||
return -1;
|
||||
} else if (robust_unlink(fname)) {
|
||||
@@ -170,90 +228,171 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return hard_link_one(file, ndx, fname, statret, st, toname,
|
||||
0, itemizing, code);
|
||||
}
|
||||
#endif
|
||||
|
||||
int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
int statret, STRUCT_STAT *st, int itemizing,
|
||||
enum logcode code, int skip)
|
||||
{
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
int head;
|
||||
if (skip && !(file->flags & FLAG_HLINK_EOL))
|
||||
head = hlink_list[file->F_HLINDEX] = file->F_NEXT;
|
||||
else
|
||||
head = hlink_list[file->F_HLINDEX];
|
||||
if (ndx != head) {
|
||||
struct file_struct *head_file = FPTR(head);
|
||||
if (!stdout_format_has_i && verbose > 1) {
|
||||
rprintf(FINFO, "\"%s\" is a hard link\n",
|
||||
f_name(file, NULL));
|
||||
if (hard_link_one(file, fname, oldname, 0)) {
|
||||
if (itemizing) {
|
||||
itemize(fname, file, ndx, statret, sxp,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
|
||||
realname);
|
||||
}
|
||||
if (head_file->F_HLINDEX == FINISHED_LINK) {
|
||||
STRUCT_STAT st2, st3;
|
||||
char toname[MAXPATHLEN];
|
||||
int ldu = head_file->link_u.links->link_dest_used;
|
||||
if (ldu) {
|
||||
pathjoin(toname, MAXPATHLEN, basis_dir[ldu-1],
|
||||
f_name(head_file, NULL));
|
||||
} else
|
||||
f_name(head_file, toname);
|
||||
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 || !stdout_format_has_i) {
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
}
|
||||
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);
|
||||
if (remove_source_files == 1 && do_xfers) {
|
||||
char numbuf[4];
|
||||
SIVAL(numbuf, 0, ndx);
|
||||
send_msg(MSG_SUCCESS, numbuf, 4);
|
||||
}
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
} else
|
||||
file->F_HLINDEX = SKIPPED_LINK;
|
||||
return 1;
|
||||
if (code != FNONE && verbose)
|
||||
rprintf(code, "%s => %s\n", fname, realname);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
int hard_link_one(struct file_struct *file, int ndx, char *fname,
|
||||
int statret, STRUCT_STAT *st, char *toname, int terse,
|
||||
int itemizing, enum logcode code)
|
||||
/* Figure out if a prior entry is still there or if we just have a
|
||||
* cached name for it. Never called with a FLAG_HLINK_FIRST entry. */
|
||||
static char *check_prior(int prev_ndx, int gnum, struct file_list **flist_p)
|
||||
{
|
||||
if (do_link(toname, fname)) {
|
||||
struct file_list *flist = flist_for_ndx(prev_ndx);
|
||||
struct ht_int32_node *node;
|
||||
|
||||
if (flist) {
|
||||
*flist_p = flist;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = hashtable_find(prior_hlinks, gnum, 0);
|
||||
assert(node != NULL && node->data);
|
||||
assert(CVAL(node->data, 0) != 0);
|
||||
return node->data;
|
||||
}
|
||||
|
||||
/* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
|
||||
* 0 = process the file, 1 = skip the file, -1 = error occurred. */
|
||||
int hard_link_check(struct file_struct *file, int ndx, const char *fname,
|
||||
int statret, stat_x *sxp, int itemizing,
|
||||
enum logcode code)
|
||||
{
|
||||
STRUCT_STAT prev_st;
|
||||
char namebuf[MAXPATHLEN], altbuf[MAXPATHLEN];
|
||||
char *realname, *prev_name;
|
||||
struct file_list *flist;
|
||||
int gnum = inc_recurse ? F_HL_GNUM(file) : -1;
|
||||
int prev_ndx = F_HL_PREV(file);
|
||||
|
||||
prev_name = realname = check_prior(prev_ndx, gnum, &flist);
|
||||
|
||||
if (!prev_name) {
|
||||
struct file_struct *prev_file = flist->files[prev_ndx - flist->ndx_start];
|
||||
|
||||
/* Is the previous link is not complete yet? */
|
||||
if (!(prev_file->flags & FLAG_HLINK_DONE)) {
|
||||
/* Is the previous link being transferred? */
|
||||
if (prev_file->flags & FLAG_FILE_SENT) {
|
||||
/* Add ourselves to the list of files that will be
|
||||
* updated when the transfer completes, and mark
|
||||
* ourself as waiting for the transfer. */
|
||||
F_HL_PREV(file) = F_HL_PREV(prev_file);
|
||||
F_HL_PREV(prev_file) = ndx;
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
cur_flist->in_progress++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There is a finished file to link with! */
|
||||
if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
|
||||
/* The previous previous is FIRST when prev is not. */
|
||||
prev_ndx = F_HL_PREV(prev_file);
|
||||
prev_name = realname = check_prior(prev_ndx, gnum, &flist);
|
||||
/* Update our previous pointer to point to the FIRST. */
|
||||
F_HL_PREV(file) = prev_ndx;
|
||||
}
|
||||
|
||||
if (!prev_name) {
|
||||
int alt_dest;
|
||||
|
||||
prev_file = flist->files[prev_ndx - flist->ndx_start];
|
||||
/* F_HL_PREV() is alt_dest value when DONE && FIRST. */
|
||||
alt_dest = F_HL_PREV(prev_file);
|
||||
|
||||
if (alt_dest >= 0 && dry_run) {
|
||||
pathjoin(namebuf, MAXPATHLEN, basis_dir[alt_dest],
|
||||
f_name(prev_file, NULL));
|
||||
prev_name = namebuf;
|
||||
realname = f_name(prev_file, altbuf);
|
||||
} else {
|
||||
prev_name = f_name(prev_file, namebuf);
|
||||
realname = prev_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (link_stat(prev_name, &prev_st, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(prev_name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (statret < 0 && basis_dir[0] != NULL) {
|
||||
/* If we match an alt-dest item, we don't output this as a change. */
|
||||
char cmpbuf[MAXPATHLEN];
|
||||
stat_x alt_sx;
|
||||
int j = 0;
|
||||
#ifdef SUPPORT_ACLS
|
||||
alt_sx.acc_acl = alt_sx.def_acl = NULL;
|
||||
#endif
|
||||
do {
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
|
||||
continue;
|
||||
if (link_dest) {
|
||||
if (prev_st.st_dev != alt_sx.st.st_dev
|
||||
|| prev_st.st_ino != alt_sx.st.st_ino)
|
||||
continue;
|
||||
statret = 1;
|
||||
if (verbose < 2 || !stdout_format_has_i) {
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
if (verbose > 1 && maybe_ATTRS_REPORT)
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!unchanged_file(cmpbuf, file, &alt_sx.st))
|
||||
continue;
|
||||
statret = 1;
|
||||
if (unchanged_attrs(cmpbuf, file, &alt_sx))
|
||||
break;
|
||||
} while (basis_dir[++j] != NULL);
|
||||
if (statret == 1) {
|
||||
sxp->st = alt_sx.st;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
if (!ACL_READY(*sxp))
|
||||
get_acl(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->acc_acl = alt_sx.acc_acl;
|
||||
sxp->def_acl = alt_sx.def_acl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef SUPPORT_ACLS
|
||||
else if (preserve_acls)
|
||||
free_acl(&alt_sx);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
|
||||
realname, itemizing, code) < 0)
|
||||
return -1;
|
||||
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hard_link_one(struct file_struct *file, const char *fname,
|
||||
const char *oldname, int terse)
|
||||
{
|
||||
if (do_link(oldname, fname) < 0) {
|
||||
enum logcode code;
|
||||
if (terse) {
|
||||
if (!verbose)
|
||||
return -1;
|
||||
@@ -261,55 +400,80 @@ 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), toname);
|
||||
return -1;
|
||||
full_fname(fname), oldname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (itemizing) {
|
||||
itemize(file, ndx, statret, st,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
|
||||
terse ? "" : toname);
|
||||
}
|
||||
if (code != FNONE && verbose && !terse)
|
||||
rprintf(code, "%s => %s\n", fname, toname);
|
||||
return 0;
|
||||
file->flags |= FLAG_HLINK_DONE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void hard_link_cluster(struct file_struct *file, int master, int itemizing,
|
||||
enum logcode code)
|
||||
void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
STRUCT_STAT *stp, int itemizing, enum logcode code,
|
||||
int alt_dest)
|
||||
{
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
char hlink1[MAXPATHLEN];
|
||||
char *hlink2;
|
||||
STRUCT_STAT st1, st2;
|
||||
int statret, ndx = master;
|
||||
stat_x prev_sx;
|
||||
STRUCT_STAT st;
|
||||
char alt_name[MAXPATHLEN], *prev_name;
|
||||
const char *our_name;
|
||||
struct file_list *flist;
|
||||
int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
|
||||
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
if (link_stat(f_name(file, hlink1), &st1, 0) < 0)
|
||||
return;
|
||||
if (!(file->flags & FLAG_HLINK_TOL)) {
|
||||
while (!(file->flags & FLAG_HLINK_EOL)) {
|
||||
ndx = file->F_NEXT;
|
||||
file = FPTR(ndx);
|
||||
if (stp == NULL && prev_ndx >= 0) {
|
||||
if (link_stat(fname, &st, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
return;
|
||||
}
|
||||
stp = &st;
|
||||
}
|
||||
do {
|
||||
ndx = file->F_NEXT;
|
||||
file = FPTR(ndx);
|
||||
if (file->F_HLINDEX != SKIPPED_LINK)
|
||||
continue;
|
||||
hlink2 = f_name(file, NULL);
|
||||
statret = link_stat(hlink2, &st2, 0);
|
||||
maybe_hard_link(file, ndx, hlink2, statret, &st2,
|
||||
hlink1, &st1, itemizing, code);
|
||||
if (remove_source_files == 1 && do_xfers) {
|
||||
char numbuf[4];
|
||||
SIVAL(numbuf, 0, ndx);
|
||||
send_msg(MSG_SUCCESS, numbuf, 4);
|
||||
}
|
||||
file->F_HLINDEX = FINISHED_LINK;
|
||||
} while (!(file->flags & FLAG_HLINK_EOL));
|
||||
|
||||
/* FIRST combined with DONE means we were the first to get done. */
|
||||
file->flags |= FLAG_HLINK_FIRST | FLAG_HLINK_DONE;
|
||||
F_HL_PREV(file) = alt_dest;
|
||||
if (alt_dest >= 0 && dry_run) {
|
||||
pathjoin(alt_name, MAXPATHLEN, basis_dir[alt_dest],
|
||||
f_name(file, NULL));
|
||||
our_name = alt_name;
|
||||
} else
|
||||
our_name = fname;
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
prev_sx.acc_acl = prev_sx.def_acl = NULL;
|
||||
#endif
|
||||
|
||||
while ((ndx = prev_ndx) >= 0) {
|
||||
int val;
|
||||
flist = flist_for_ndx(ndx);
|
||||
assert(flist != NULL);
|
||||
file = flist->files[ndx - flist->ndx_start];
|
||||
file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
|
||||
prev_ndx = F_HL_PREV(file);
|
||||
F_HL_PREV(file) = fin_ndx;
|
||||
prev_name = f_name(file, NULL);
|
||||
prev_statret = link_stat(prev_name, &prev_sx.st, 0);
|
||||
val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
|
||||
our_name, stp, fname, itemizing, code);
|
||||
flist->in_progress--;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls)
|
||||
free_acl(&prev_sx);
|
||||
#endif
|
||||
if (val < 0)
|
||||
continue;
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
}
|
||||
|
||||
if (inc_recurse) {
|
||||
int gnum = F_HL_GNUM(file);
|
||||
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
|
||||
assert(node != NULL && node->data != NULL);
|
||||
assert(CVAL(node->data, 0) == 0);
|
||||
free(node->data);
|
||||
if (!(node->data = strdup(our_name)))
|
||||
out_of_memory("finish_hard_link");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
100
ifuncs.h
Normal file
100
ifuncs.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
alloc_xbuf(xbuf *xb, size_t sz)
|
||||
{
|
||||
if (!(xb->buf = new_array(char, sz)))
|
||||
out_of_memory("alloc_xbuf");
|
||||
xb->size = sz;
|
||||
xb->len = xb->pos = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
realloc_xbuf(xbuf *xb, size_t sz)
|
||||
{
|
||||
char *bf = realloc_array(xb->buf, char, sz);
|
||||
if (!bf)
|
||||
out_of_memory("realloc_xbuf");
|
||||
xb->buf = bf;
|
||||
xb->size = sz;
|
||||
}
|
||||
|
||||
static inline int
|
||||
to_wire_mode(mode_t mode)
|
||||
{
|
||||
#ifdef SUPPORT_LINKS
|
||||
#if _S_IFLNK != 0120000
|
||||
if (S_ISLNK(mode))
|
||||
return (mode & ~(_S_IFMT)) | 0120000;
|
||||
#endif
|
||||
#endif
|
||||
return mode;
|
||||
}
|
||||
|
||||
static inline mode_t
|
||||
from_wire_mode(int mode)
|
||||
{
|
||||
#if _S_IFLNK != 0120000
|
||||
if ((mode & (_S_IFMT)) == 0120000)
|
||||
return (mode & ~(_S_IFMT)) | _S_IFLNK;
|
||||
#endif
|
||||
return mode;
|
||||
}
|
||||
|
||||
static inline int
|
||||
isDigit(const char *ptr)
|
||||
{
|
||||
return isdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isPrint(const char *ptr)
|
||||
{
|
||||
return isprint(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isSpace(const char *ptr)
|
||||
{
|
||||
return isspace(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isLower(const char *ptr)
|
||||
{
|
||||
return islower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isUpper(const char *ptr)
|
||||
{
|
||||
return isupper(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toLower(const char *ptr)
|
||||
{
|
||||
return tolower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toUpper(const char *ptr)
|
||||
{
|
||||
return toupper(*(unsigned char *)ptr);
|
||||
}
|
||||
52
io.h
Normal file
52
io.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
extern int protocol_version;
|
||||
|
||||
static inline int32
|
||||
read_varint30(int f)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
return read_int(f);
|
||||
return read_varint(f);
|
||||
}
|
||||
|
||||
static inline int64
|
||||
read_varlong30(int f, uchar min_bytes)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
return read_longint(f);
|
||||
return read_varlong(f, min_bytes);
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_varint30(int f, int32 x)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
write_int(f, x);
|
||||
else
|
||||
write_varint(f, x);
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_varlong30(int f, int64 x, uchar min_bytes)
|
||||
{
|
||||
if (protocol_version < 30)
|
||||
write_longint(f, x);
|
||||
else
|
||||
write_varlong(f, x, min_bytes);
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
304
lib/md5.c
Normal file
304
lib/md5.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
void md5_begin(md_context *ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xEFCDAB89;
|
||||
ctx->C = 0x98BADCFE;
|
||||
ctx->D = 0x10325476;
|
||||
|
||||
ctx->totalN = ctx->totalN2 = 0;
|
||||
}
|
||||
|
||||
static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
|
||||
{
|
||||
uint32 X[16], A, B, C, D;
|
||||
|
||||
A = ctx->A;
|
||||
B = ctx->B;
|
||||
C = ctx->C;
|
||||
D = ctx->D;
|
||||
|
||||
X[0] = IVAL(data, 0);
|
||||
X[1] = IVAL(data, 4);
|
||||
X[2] = IVAL(data, 8);
|
||||
X[3] = IVAL(data, 12);
|
||||
X[4] = IVAL(data, 16);
|
||||
X[5] = IVAL(data, 20);
|
||||
X[6] = IVAL(data, 24);
|
||||
X[7] = IVAL(data, 28);
|
||||
X[8] = IVAL(data, 32);
|
||||
X[9] = IVAL(data, 36);
|
||||
X[10] = IVAL(data, 40);
|
||||
X[11] = IVAL(data, 44);
|
||||
X[12] = IVAL(data, 48);
|
||||
X[13] = IVAL(data, 52);
|
||||
X[14] = IVAL(data, 56);
|
||||
X[15] = IVAL(data, 60);
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) a += F(b,c,d) + X[k] + t, a = S(a,s) + b
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P(A, B, C, D, 0, 7, 0xD76AA478);
|
||||
P(D, A, B, C, 1, 12, 0xE8C7B756);
|
||||
P(C, D, A, B, 2, 17, 0x242070DB);
|
||||
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
|
||||
P(A, B, C, D, 4, 7, 0xF57C0FAF);
|
||||
P(D, A, B, C, 5, 12, 0x4787C62A);
|
||||
P(C, D, A, B, 6, 17, 0xA8304613);
|
||||
P(B, C, D, A, 7, 22, 0xFD469501);
|
||||
P(A, B, C, D, 8, 7, 0x698098D8);
|
||||
P(D, A, B, C, 9, 12, 0x8B44F7AF);
|
||||
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
|
||||
P(B, C, D, A, 11, 22, 0x895CD7BE);
|
||||
P(A, B, C, D, 12, 7, 0x6B901122);
|
||||
P(D, A, B, C, 13, 12, 0xFD987193);
|
||||
P(C, D, A, B, 14, 17, 0xA679438E);
|
||||
P(B, C, D, A, 15, 22, 0x49B40821);
|
||||
|
||||
#undef F
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P(A, B, C, D, 1, 5, 0xF61E2562);
|
||||
P(D, A, B, C, 6, 9, 0xC040B340);
|
||||
P(C, D, A, B, 11, 14, 0x265E5A51);
|
||||
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
|
||||
P(A, B, C, D, 5, 5, 0xD62F105D);
|
||||
P(D, A, B, C, 10, 9, 0x02441453);
|
||||
P(C, D, A, B, 15, 14, 0xD8A1E681);
|
||||
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
|
||||
P(A, B, C, D, 9, 5, 0x21E1CDE6);
|
||||
P(D, A, B, C, 14, 9, 0xC33707D6);
|
||||
P(C, D, A, B, 3, 14, 0xF4D50D87);
|
||||
P(B, C, D, A, 8, 20, 0x455A14ED);
|
||||
P(A, B, C, D, 13, 5, 0xA9E3E905);
|
||||
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
|
||||
P(C, D, A, B, 7, 14, 0x676F02D9);
|
||||
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
|
||||
|
||||
#undef F
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P(A, B, C, D, 5, 4, 0xFFFA3942);
|
||||
P(D, A, B, C, 8, 11, 0x8771F681);
|
||||
P(C, D, A, B, 11, 16, 0x6D9D6122);
|
||||
P(B, C, D, A, 14, 23, 0xFDE5380C);
|
||||
P(A, B, C, D, 1, 4, 0xA4BEEA44);
|
||||
P(D, A, B, C, 4, 11, 0x4BDECFA9);
|
||||
P(C, D, A, B, 7, 16, 0xF6BB4B60);
|
||||
P(B, C, D, A, 10, 23, 0xBEBFBC70);
|
||||
P(A, B, C, D, 13, 4, 0x289B7EC6);
|
||||
P(D, A, B, C, 0, 11, 0xEAA127FA);
|
||||
P(C, D, A, B, 3, 16, 0xD4EF3085);
|
||||
P(B, C, D, A, 6, 23, 0x04881D05);
|
||||
P(A, B, C, D, 9, 4, 0xD9D4D039);
|
||||
P(D, A, B, C, 12, 11, 0xE6DB99E5);
|
||||
P(C, D, A, B, 15, 16, 0x1FA27CF8);
|
||||
P(B, C, D, A, 2, 23, 0xC4AC5665);
|
||||
|
||||
#undef F
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P(A, B, C, D, 0, 6, 0xF4292244);
|
||||
P(D, A, B, C, 7, 10, 0x432AFF97);
|
||||
P(C, D, A, B, 14, 15, 0xAB9423A7);
|
||||
P(B, C, D, A, 5, 21, 0xFC93A039);
|
||||
P(A, B, C, D, 12, 6, 0x655B59C3);
|
||||
P(D, A, B, C, 3, 10, 0x8F0CCC92);
|
||||
P(C, D, A, B, 10, 15, 0xFFEFF47D);
|
||||
P(B, C, D, A, 1, 21, 0x85845DD1);
|
||||
P(A, B, C, D, 8, 6, 0x6FA87E4F);
|
||||
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
|
||||
P(C, D, A, B, 6, 15, 0xA3014314);
|
||||
P(B, C, D, A, 13, 21, 0x4E0811A1);
|
||||
P(A, B, C, D, 4, 6, 0xF7537E82);
|
||||
P(D, A, B, C, 11, 10, 0xBD3AF235);
|
||||
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
|
||||
P(B, C, D, A, 9, 21, 0xEB86D391);
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->A += A;
|
||||
ctx->B += B;
|
||||
ctx->C += C;
|
||||
ctx->D += D;
|
||||
}
|
||||
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
{
|
||||
uint32 left, fill;
|
||||
|
||||
if (!length)
|
||||
return;
|
||||
|
||||
left = ctx->totalN & 0x3F;
|
||||
fill = CSUM_CHUNK - left;
|
||||
|
||||
ctx->totalN += length;
|
||||
ctx->totalN &= 0xFFFFFFFF;
|
||||
|
||||
if (ctx->totalN < length)
|
||||
ctx->totalN2++;
|
||||
|
||||
if (left && length >= fill) {
|
||||
memcpy(ctx->buffer + left, input, fill);
|
||||
md5_process(ctx, ctx->buffer);
|
||||
length -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (length >= CSUM_CHUNK) {
|
||||
md5_process(ctx, input);
|
||||
length -= CSUM_CHUNK;
|
||||
input += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
if (length)
|
||||
memcpy(ctx->buffer + left, input, length);
|
||||
}
|
||||
|
||||
static uchar md5_padding[CSUM_CHUNK] = { 0x80 };
|
||||
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
|
||||
{
|
||||
uint32 last, padn;
|
||||
uint32 high, low;
|
||||
uchar msglen[8];
|
||||
|
||||
high = (ctx->totalN >> 29)
|
||||
| (ctx->totalN2 << 3);
|
||||
low = (ctx->totalN << 3);
|
||||
|
||||
SIVAL(msglen, 0, low);
|
||||
SIVAL(msglen, 4, high);
|
||||
|
||||
last = ctx->totalN & 0x3F;
|
||||
padn = last < 56 ? 56 - last : 120 - last;
|
||||
|
||||
md5_update(ctx, md5_padding, padn);
|
||||
md5_update(ctx, msglen, 8);
|
||||
|
||||
SIVAL(digest, 0, ctx->A);
|
||||
SIVAL(digest, 4, ctx->B);
|
||||
SIVAL(digest, 8, ctx->C);
|
||||
SIVAL(digest, 12, ctx->D);
|
||||
}
|
||||
|
||||
void get_md5(uchar *out, const uchar *input, int n)
|
||||
{
|
||||
md_context ctx;
|
||||
md5_begin(&ctx);
|
||||
md5_update(&ctx, input, n);
|
||||
md5_result(&ctx, out);
|
||||
}
|
||||
|
||||
#ifdef TEST_MD5
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* those are the standard RFC 1321 test vectors
|
||||
*/
|
||||
|
||||
static struct {
|
||||
char *str, *md5;
|
||||
} tests[] = {
|
||||
{ "",
|
||||
"d41d8cd98f00b204e9800998ecf8427e" },
|
||||
{ "a",
|
||||
"0cc175b9c0f1b6a831c399e269772661" },
|
||||
{ "abc",
|
||||
"900150983cd24fb0d6963f7d28e17f72" },
|
||||
{ "message digest",
|
||||
"f96b697d7cb7938d525a2f31aaf161d0" },
|
||||
{ "abcdefghijklmnopqrstuvwxyz",
|
||||
"c3fcd3d76192e4007dfb496cca67e13b" },
|
||||
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
"d174ab98d277d9f5a5611c2c9f419d9f" },
|
||||
{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
||||
"57edf4a22be3c955ac49da2e2107b67a" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *f;
|
||||
int i, j;
|
||||
char output[33];
|
||||
md_context ctx;
|
||||
uchar buf[1000];
|
||||
uchar md5sum[MD5_DIGEST_LEN];
|
||||
|
||||
if (argc < 2) {
|
||||
printf("\nMD5 Validation Tests:\n\n");
|
||||
|
||||
for (i = 0; tests[i].str; i++) {
|
||||
char *str = tests[i].str;
|
||||
char *chk = tests[i].md5;
|
||||
|
||||
printf(" Test %d ", i + 1);
|
||||
|
||||
get_md5(md5sum, str, strlen(str));
|
||||
|
||||
for (j = 0; j < MD5_DIGEST_LEN; j++)
|
||||
sprintf(output + j * 2, "%02x", md5sum[j]);
|
||||
|
||||
if (memcmp(output, chk, 32)) {
|
||||
printf("failed!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("passed.\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (--argc) {
|
||||
if (!(f = fopen(*++argv, "rb"))) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
md5_begin(&ctx);
|
||||
|
||||
while ((i = fread(buf, 1, sizeof buf, f)) > 0)
|
||||
md5_update(&ctx, buf, i);
|
||||
|
||||
md5_result(&ctx, md5sum);
|
||||
|
||||
for (j = 0; j < MD5_DIGEST_LEN; j++)
|
||||
printf("%02x", md5sum[j]);
|
||||
|
||||
printf(" %s\n", *argv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
156
lib/mdfour.c
156
lib/mdfour.c
@@ -4,11 +4,11 @@
|
||||
* An implementation of MD4 designed for use in the SMB authentication protocol.
|
||||
*
|
||||
* Copyright (C) 1997-1998 Andrew Tridgell
|
||||
* Copyright (C) 2005 Wayne Davison
|
||||
* Copyright (C) 2005-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -27,7 +26,7 @@
|
||||
*
|
||||
* It assumes that a int is at least 32 bits long. */
|
||||
|
||||
static struct mdfour *m;
|
||||
static md_context *m;
|
||||
|
||||
#define MASK32 (0xffffffff)
|
||||
|
||||
@@ -49,32 +48,31 @@ static void mdfour64(uint32 *M)
|
||||
A = m->A; B = m->B; C = m->C; D = m->D;
|
||||
AA = A; BB = B; CC = C; DD = D;
|
||||
|
||||
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
|
||||
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
|
||||
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
|
||||
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
|
||||
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
|
||||
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
|
||||
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
|
||||
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
|
||||
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
|
||||
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
|
||||
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
|
||||
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
|
||||
|
||||
|
||||
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
|
||||
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
|
||||
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
|
||||
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
|
||||
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
|
||||
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
|
||||
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
|
||||
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
|
||||
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
|
||||
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
|
||||
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
|
||||
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
|
||||
|
||||
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
|
||||
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
|
||||
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
|
||||
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
|
||||
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
|
||||
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
|
||||
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
|
||||
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
|
||||
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
|
||||
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
|
||||
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
|
||||
|
||||
A += AA; B += BB;
|
||||
@@ -86,16 +84,17 @@ static void mdfour64(uint32 *M)
|
||||
m->A = A; m->B = B; m->C = C; m->D = D;
|
||||
}
|
||||
|
||||
static void copy64(uint32 *M, unsigned char *in)
|
||||
static void copy64(uint32 *M, const uchar *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
|
||||
(in[i*4+1]<<8) | (in[i*4+0]<<0);
|
||||
for (i = 0; i < MD4_DIGEST_LEN; i++) {
|
||||
M[i] = (in[i*4+3] << 24) | (in[i*4+2] << 16)
|
||||
| (in[i*4+1] << 8) | (in[i*4+0] << 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void copy4(unsigned char *out,uint32 x)
|
||||
static void copy4(uchar *out,uint32 x)
|
||||
{
|
||||
out[0] = x&0xFF;
|
||||
out[1] = (x>>8)&0xFF;
|
||||
@@ -103,7 +102,7 @@ static void copy4(unsigned char *out,uint32 x)
|
||||
out[3] = (x>>24)&0xFF;
|
||||
}
|
||||
|
||||
void mdfour_begin(struct mdfour *md)
|
||||
void mdfour_begin(md_context *md)
|
||||
{
|
||||
md->A = 0x67452301;
|
||||
md->B = 0xefcdab89;
|
||||
@@ -113,27 +112,26 @@ void mdfour_begin(struct mdfour *md)
|
||||
md->totalN2 = 0;
|
||||
}
|
||||
|
||||
|
||||
static void mdfour_tail(unsigned char *in, uint32 n)
|
||||
static void mdfour_tail(const uchar *in, uint32 length)
|
||||
{
|
||||
unsigned char buf[128];
|
||||
uchar buf[128];
|
||||
uint32 M[16];
|
||||
extern int protocol_version;
|
||||
|
||||
/*
|
||||
* Count total number of bits, modulo 2^64
|
||||
*/
|
||||
m->totalN += n << 3;
|
||||
if (m->totalN < (n << 3)) {
|
||||
m->totalN += length << 3;
|
||||
if (m->totalN < (length << 3))
|
||||
m->totalN2++;
|
||||
}
|
||||
m->totalN2 += n >> 29;
|
||||
m->totalN2 += length >> 29;
|
||||
|
||||
memset(buf, 0, 128);
|
||||
if (n) memcpy(buf, in, n);
|
||||
buf[n] = 0x80;
|
||||
if (length)
|
||||
memcpy(buf, in, length);
|
||||
buf[length] = 0x80;
|
||||
|
||||
if (n <= 55) {
|
||||
if (length <= 55) {
|
||||
copy4(buf+56, m->totalN);
|
||||
/*
|
||||
* Prior to protocol version 27 only the number of bits
|
||||
@@ -141,9 +139,8 @@ static void mdfour_tail(unsigned char *in, uint32 n)
|
||||
* of bits modulo 2^64, which was fixed starting with
|
||||
* protocol version 27.
|
||||
*/
|
||||
if (protocol_version >= 27) {
|
||||
if (protocol_version >= 27)
|
||||
copy4(buf+60, m->totalN2);
|
||||
}
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
} else {
|
||||
@@ -154,9 +151,8 @@ static void mdfour_tail(unsigned char *in, uint32 n)
|
||||
* of bits modulo 2^64, which was fixed starting with
|
||||
* protocol version 27.
|
||||
*/
|
||||
if (protocol_version >= 27) {
|
||||
if (protocol_version >= 27)
|
||||
copy4(buf+124, m->totalN2);
|
||||
}
|
||||
copy64(M, buf);
|
||||
mdfour64(M);
|
||||
copy64(M, buf+64);
|
||||
@@ -164,46 +160,45 @@ static void mdfour_tail(unsigned char *in, uint32 n)
|
||||
}
|
||||
}
|
||||
|
||||
void mdfour_update(struct mdfour *md, unsigned char *in, uint32 n)
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length)
|
||||
{
|
||||
uint32 M[16];
|
||||
|
||||
m = md;
|
||||
|
||||
if (n == 0) mdfour_tail(in, n);
|
||||
if (length == 0)
|
||||
mdfour_tail(in, length);
|
||||
|
||||
while (n >= 64) {
|
||||
while (length >= 64) {
|
||||
copy64(M, in);
|
||||
mdfour64(M);
|
||||
in += 64;
|
||||
n -= 64;
|
||||
length -= 64;
|
||||
m->totalN += 64 << 3;
|
||||
if (m->totalN < 64 << 3) {
|
||||
if (m->totalN < 64 << 3)
|
||||
m->totalN2++;
|
||||
}
|
||||
}
|
||||
|
||||
if (n) mdfour_tail(in, n);
|
||||
if (length)
|
||||
mdfour_tail(in, length);
|
||||
}
|
||||
|
||||
|
||||
void mdfour_result(struct mdfour *md, unsigned char *out)
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN])
|
||||
{
|
||||
m = md;
|
||||
|
||||
copy4(out, m->A);
|
||||
copy4(out+4, m->B);
|
||||
copy4(out+8, m->C);
|
||||
copy4(out+12, m->D);
|
||||
copy4(digest, m->A);
|
||||
copy4(digest+4, m->B);
|
||||
copy4(digest+8, m->C);
|
||||
copy4(digest+12, m->D);
|
||||
}
|
||||
|
||||
|
||||
void mdfour(unsigned char *out, unsigned char *in, int n)
|
||||
void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length)
|
||||
{
|
||||
struct mdfour md;
|
||||
md_context md;
|
||||
mdfour_begin(&md);
|
||||
mdfour_update(&md, in, n);
|
||||
mdfour_result(&md, out);
|
||||
mdfour_update(&md, in, length);
|
||||
mdfour_result(&md, digest);
|
||||
}
|
||||
|
||||
#ifdef TEST_MDFOUR
|
||||
@@ -212,8 +207,8 @@ int protocol_version = 28;
|
||||
static void file_checksum1(char *fname)
|
||||
{
|
||||
int fd, i, was_multiple_of_64 = 1;
|
||||
struct mdfour md;
|
||||
unsigned char buf[64*1024], sum[16];
|
||||
md_context md;
|
||||
uchar buf[64*1024], sum[MD4_DIGEST_LEN];
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) {
|
||||
@@ -224,7 +219,7 @@ static void file_checksum1(char *fname)
|
||||
mdfour_begin(&md);
|
||||
|
||||
while (1) {
|
||||
int n = read(fd, buf, sizeof(buf));
|
||||
int n = read(fd, buf, sizeof buf);
|
||||
if (n <= 0)
|
||||
break;
|
||||
was_multiple_of_64 = !(n % 64);
|
||||
@@ -237,54 +232,15 @@ static void file_checksum1(char *fname)
|
||||
|
||||
mdfour_result(&md, sum);
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
for (i = 0; i < MD4_DIGEST_LEN; i++)
|
||||
printf("%02X", sum[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include "../md4.h"
|
||||
|
||||
static void file_checksum2(char *fname)
|
||||
{
|
||||
int fd, i;
|
||||
MDstruct md;
|
||||
unsigned char buf[64], sum[16];
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("fname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MDbegin(&md);
|
||||
|
||||
while (1) {
|
||||
int n = read(fd, buf, sizeof(buf));
|
||||
if (n <= 0) break;
|
||||
MDupdate(&md, buf, n*8);
|
||||
}
|
||||
|
||||
if (!md.done) {
|
||||
MDupdate(&md, buf, 0);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
memcpy(sum, md.buffer, 16);
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
printf("%02X", sum[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
file_checksum1(argv[1]);
|
||||
#if 0
|
||||
file_checksum2(argv[1]);
|
||||
#endif
|
||||
while (--argc)
|
||||
file_checksum1(*++argv);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
32
lib/mdfour.h
32
lib/mdfour.h
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Unix SMB/Netbios implementation.
|
||||
* Version 1.9.
|
||||
* An implementation of MD4 designed for use in the SMB authentication protocol.
|
||||
*
|
||||
* Copyright (C) 1997-1998 Andrew Tridgell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
struct mdfour {
|
||||
uint32 A, B, C, D;
|
||||
uint32 totalN; /* bit count, lower 32 bits */
|
||||
uint32 totalN2; /* bit count, upper 32 bits */
|
||||
};
|
||||
|
||||
void mdfour_begin(struct mdfour *md);
|
||||
void mdfour_update(struct mdfour *md, unsigned char *in, uint32 n);
|
||||
void mdfour_result(struct mdfour *md, unsigned char *out);
|
||||
void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
26
lib/mdigest.h
Normal file
26
lib/mdigest.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* The include file for both the MD4 and MD5 routines. */
|
||||
|
||||
#define MD4_DIGEST_LEN 16
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
typedef struct {
|
||||
uint32 A, B, C, D;
|
||||
uint32 totalN; /* bit count, lower 32 bits */
|
||||
uint32 totalN2; /* bit count, upper 32 bits */
|
||||
uchar buffer[CSUM_CHUNK];
|
||||
} md_context;
|
||||
|
||||
void mdfour_begin(md_context *md);
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length);
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]);
|
||||
|
||||
void get_mdfour(uchar digest[MD4_DIGEST_LEN], const uchar *in, int length);
|
||||
|
||||
void md5_begin(md_context *ctx);
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length);
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]);
|
||||
|
||||
void get_md5(uchar digest[MD5_DIGEST_LEN], const uchar *input, int n);
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
169
lib/pool_alloc.3
169
lib/pool_alloc.3
@@ -28,7 +28,7 @@ See \fB\\$1\fP in \fB\\$2\fP for details.
|
||||
..
|
||||
.TH POOL_ALLOC 3
|
||||
.SH NAME
|
||||
pool_alloc, pool_free, pool_talloc, pool_tfree, pool_create, pool_destroy
|
||||
pool_alloc, pool_free, pool_free_old, pool_talloc, pool_tfree, pool_create, pool_destroy, pool_boundary
|
||||
\- Allocate and free memory in managed allocation pools.
|
||||
.SH SYNOPSIS
|
||||
.B #include "pool_alloc.h"
|
||||
@@ -39,42 +39,45 @@ pool_alloc, pool_free, pool_talloc, pool_tfree, pool_create, pool_destroy
|
||||
|
||||
\fBvoid *pool_alloc(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, char *\fImsg\fB);
|
||||
|
||||
\fBvoid pool_free(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB, void *\fIaddr\fB);
|
||||
\fBvoid pool_free(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid pool_free_old(struct alloc_pool *\fIpool\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid *pool_talloc(struct alloc_pool *\fIpool\fB, \fItype\fB), int \fIcount\fB, char *\fImsg\fB);
|
||||
|
||||
\fBvoid pool_tfree(struct alloc_pool *\fIpool\fB, \fItype\fB, int \fIcount\fB, void *\fIaddr\fB);
|
||||
|
||||
\fBvoid pool_boundary(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB);
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
The pool allocation routines use
|
||||
.B malloc()
|
||||
for underlying memory management.
|
||||
What allocation pools do is cause
|
||||
memory within a given pool to be in large contigious blocks
|
||||
(called extents) that when freed will be reusable. Unlike
|
||||
.B malloc()
|
||||
What allocation pools do is cause memory within a given pool
|
||||
to be allocated in large contiguous blocks
|
||||
(called extents) that will be reusable when freed. Unlike
|
||||
.BR malloc() ,
|
||||
the allocations are not managed individually.
|
||||
Instead each extent tracks the total free memory within the
|
||||
Instead, each extent tracks the total free memory within the
|
||||
extent. Each extent can either be used to allocate memory
|
||||
or to manage the freeing of memory within that extent.
|
||||
When an extent has less free memory than a given
|
||||
allocation request or when the first request to free
|
||||
memory within that extent is received the extent ceases to
|
||||
be used for allocation.
|
||||
allocation request, the current extent ceases to be used
|
||||
for allocation. See also the
|
||||
.B pool_boundary()
|
||||
function.
|
||||
.P
|
||||
This form of memory management is suited to large numbers of small
|
||||
related allocations that are held for a while
|
||||
and then freed as a group.
|
||||
Because the
|
||||
underlying allocations are done in large contigious extents
|
||||
when an extent is freed it releases a large enough
|
||||
contigious block of memory to be useful to subsequent
|
||||
underlying allocations are done in large contiguous extents,
|
||||
when an extent is freed, it can release a large enough
|
||||
contiguous block of memory to allow the memory to be returned
|
||||
to the OS for use by whatever program needs it.
|
||||
You can allocate from one or more memory pools and/or
|
||||
.B malloc()
|
||||
and
|
||||
.B pool_alloc()
|
||||
calls even if allocations from other pools or from
|
||||
.B malloc()
|
||||
are made between allocations from a given pool.
|
||||
all at the same time without interfering with how pools work.
|
||||
.P
|
||||
.B pool_create()
|
||||
Creates an allocation pool for subsequent calls to the pool
|
||||
@@ -90,22 +93,32 @@ Specifying
|
||||
.B 0
|
||||
for
|
||||
.I quantum
|
||||
Will produce a quantum that should meet maximal allignment
|
||||
will produce a quantum that should meet maximal alignment
|
||||
on most platforms.
|
||||
If the
|
||||
If
|
||||
.B POOL_QALIGN
|
||||
.I flag
|
||||
is set allocations will be aligned to addresses that are a
|
||||
is set in the
|
||||
.IR flags ,
|
||||
allocations will be aligned to addresses that are a
|
||||
multiple of
|
||||
.IR quantum .
|
||||
If the
|
||||
If
|
||||
.B POOL_CLEAR
|
||||
.I flag
|
||||
is set all allocations from the pool will be zero filled.
|
||||
is set in the
|
||||
.IR flags ,
|
||||
all allocations from the pool will be initialized to zeros.
|
||||
You may specify a
|
||||
.B NULL
|
||||
for the
|
||||
.I bomb
|
||||
function pointer if you don't wish to use it. (See the
|
||||
.B pool_alloc()
|
||||
function for how it is used.)
|
||||
.P
|
||||
.B pool_destroy()
|
||||
destroys an allocation pool and frees all memory allocated
|
||||
in that pool.
|
||||
destroys an allocation
|
||||
.I pool
|
||||
and frees all its associated memory.
|
||||
.P
|
||||
.B pool_alloc()
|
||||
allocates
|
||||
@@ -115,57 +128,97 @@ bytes from the specified
|
||||
If
|
||||
.I size
|
||||
is
|
||||
.B 0
|
||||
.BR 0 ,
|
||||
.I quantum
|
||||
bytes will be freed.
|
||||
If the requested memory cannot be allocated
|
||||
.B pool_alloc()
|
||||
will call
|
||||
bytes will be allocated.
|
||||
If the pool has been created with
|
||||
.BR POOL_QALIGN ,
|
||||
every chunk of memory that is returned will be suitably aligned.
|
||||
You can use this with the default
|
||||
.I quantum
|
||||
size to ensure that all memory can store a variable of any type.
|
||||
If the requested memory cannot be allocated, the
|
||||
.I bomb()
|
||||
function, if defined, with
|
||||
function will be called with
|
||||
.I msg
|
||||
as it's sole argument and
|
||||
as its sole argument (if the function was defined at the time
|
||||
the pool was created), and then a
|
||||
.B NULL
|
||||
will be returned.
|
||||
address is returned (assuming that the bomb function didn't exit).
|
||||
.P
|
||||
.B pool_free()
|
||||
frees
|
||||
.I size
|
||||
bytes pointed to by
|
||||
bytes pointed to by an
|
||||
.I addr
|
||||
previously allocated in the specified
|
||||
that was previously allocated in the specified
|
||||
.IR pool .
|
||||
The memory freed within an extent will not be reusable until
|
||||
all of the memory in that extent has been freed but
|
||||
depending on the order in which the
|
||||
allocations are freed some extents may be released for reuse
|
||||
while others are still in use.
|
||||
If
|
||||
.I size
|
||||
is
|
||||
.B 0
|
||||
.BR 0 ,
|
||||
.I quantum
|
||||
bytes will be freed.
|
||||
The memory freed within an extent will not be reusable until
|
||||
all of the memory in that extent has been freed with one
|
||||
exception: the most recent pool allocation may be freed back
|
||||
into the pool prior to making any further allocations.
|
||||
If enough free calls are made to indicate that an extent has no
|
||||
remaining allocated objects (as computed by the total freed size for
|
||||
an extent), its memory will be completely freed back to the system.
|
||||
If
|
||||
.I addr
|
||||
is
|
||||
.B 0
|
||||
no memory will be freed but subsequent allocations will come
|
||||
.BR 0 ,
|
||||
no memory will be freed, but subsequent allocations will come
|
||||
from a new extent.
|
||||
.P
|
||||
.B pool_talloc()
|
||||
is a macro that take a
|
||||
.I type
|
||||
.B pool_free_old()
|
||||
takes a boundary
|
||||
.I addr
|
||||
value that was returned by
|
||||
.B pool_boundary()
|
||||
and frees up any extents in the
|
||||
.I pool
|
||||
that have data allocated from that point backward in time.
|
||||
NOTE: you must NOT mix calls to both
|
||||
.B pool_free
|
||||
and
|
||||
.B pool_free_old
|
||||
on the same pool!
|
||||
.P
|
||||
.B pool_boundary()
|
||||
asks for a boundary value that can be sent to
|
||||
.B pool_free_old()
|
||||
at a later time to free up all memory allocated prior to a particular
|
||||
moment in time.
|
||||
If the extent that holds the boundary point has allocations from after the
|
||||
boundary point, it will not be freed until a future
|
||||
.B pool_free_old()
|
||||
call encompasses the entirety of the extent's data.
|
||||
If
|
||||
.I len
|
||||
is non-zero, the call will also check if the active extent has at least
|
||||
that much free memory available in it, and if not, it will mark the
|
||||
extent as inactive, forcing a new extent to be used for future allocations.
|
||||
(You can specify -1 for
|
||||
.I len
|
||||
if you want to force a new extent to start.)
|
||||
.P
|
||||
.B pool_talloc()
|
||||
is a macro that takes a
|
||||
.I type
|
||||
and a
|
||||
.I count
|
||||
instead of
|
||||
.I size
|
||||
and will cast the return value to the correct type.
|
||||
instead of a
|
||||
.IR size .
|
||||
It casts the return value to the correct pointer type.
|
||||
.P
|
||||
.B pool_tfree
|
||||
is a macro to free memory previously allocated in the
|
||||
specified
|
||||
.IR pool .
|
||||
is a macro that calls
|
||||
.B pool_free
|
||||
on memory that was allocated by
|
||||
.BR pool_talloc() .
|
||||
.SH RETURN VALUE
|
||||
.B pool_create()
|
||||
returns a pointer to
|
||||
@@ -176,9 +229,6 @@ and
|
||||
.B pool_talloc()
|
||||
return pointers to the allocated memory,
|
||||
or NULL if the request fails.
|
||||
For each extent so long as no allocations are smaller than varaible
|
||||
allignment requirements this pointer will be suitably
|
||||
alligned for any kind of variable.
|
||||
The return type of
|
||||
.B pool_alloc()
|
||||
will normally require casting to the desired type but
|
||||
@@ -186,7 +236,12 @@ will normally require casting to the desired type but
|
||||
will returns a pointer of the requested
|
||||
.IR type .
|
||||
.P
|
||||
.B pool_boundary()
|
||||
returns a pointer that should only be used in a call to
|
||||
.BR pool_free_old() .
|
||||
.P
|
||||
.BR pool_free() ,
|
||||
.BR pool_free_old() ,
|
||||
.B pool_tfree()
|
||||
and
|
||||
.B pool_destroy()
|
||||
|
||||
242
lib/pool_alloc.c
242
lib/pool_alloc.c
@@ -6,11 +6,8 @@ struct alloc_pool
|
||||
{
|
||||
size_t size; /* extent size */
|
||||
size_t quantum; /* allocation quantum */
|
||||
struct pool_extent *live; /* current extent for
|
||||
* allocations */
|
||||
struct pool_extent *free; /* unfreed extent list */
|
||||
void (*bomb)();
|
||||
/* function to call if
|
||||
struct pool_extent *extents; /* top extent is "live" */
|
||||
void (*bomb)(); /* function to call if
|
||||
* malloc fails */
|
||||
int flags;
|
||||
|
||||
@@ -33,8 +30,8 @@ struct pool_extent
|
||||
};
|
||||
|
||||
struct align_test {
|
||||
void *foo;
|
||||
int64 bar;
|
||||
void *foo;
|
||||
int64 bar;
|
||||
};
|
||||
|
||||
#define MINALIGN offsetof(struct align_test, bar)
|
||||
@@ -44,19 +41,18 @@ struct align_test {
|
||||
#define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
|
||||
|
||||
alloc_pool_t
|
||||
pool_create(size_t size, size_t quantum,
|
||||
void (*bomb)(char *), int flags)
|
||||
pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
|
||||
{
|
||||
struct alloc_pool *pool;
|
||||
|
||||
if (!(pool = (struct alloc_pool*) malloc(sizeof (struct alloc_pool))))
|
||||
if (!(pool = new(struct alloc_pool)))
|
||||
return pool;
|
||||
memset(pool, 0, sizeof (struct alloc_pool));
|
||||
|
||||
pool->size = size /* round extent size to min alignment reqs */
|
||||
? (size + MINALIGN - 1) & ~(MINALIGN - 1)
|
||||
: POOL_DEF_EXTENT;
|
||||
if (pool->flags & POOL_INTERN) {
|
||||
if (flags & POOL_INTERN) {
|
||||
pool->size -= sizeof (struct pool_extent);
|
||||
flags |= POOL_APPEND;
|
||||
}
|
||||
@@ -76,13 +72,7 @@ pool_destroy(alloc_pool_t p)
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
if (pool->live) {
|
||||
cur = pool->live;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
}
|
||||
for (cur = pool->free; cur; cur = next) {
|
||||
for (cur = pool->extents; cur; cur = next) {
|
||||
next = cur->next;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
@@ -92,7 +82,7 @@ pool_destroy(alloc_pool_t p)
|
||||
}
|
||||
|
||||
void *
|
||||
pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
if (!pool)
|
||||
@@ -104,19 +94,15 @@ pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
len += pool->quantum - len % pool->quantum;
|
||||
|
||||
if (len > pool->size)
|
||||
goto bomb;
|
||||
goto bomb_out;
|
||||
|
||||
if (!pool->live || len > pool->live->free) {
|
||||
if (!pool->extents || len > pool->extents->free) {
|
||||
void *start;
|
||||
size_t free;
|
||||
size_t bound;
|
||||
size_t sqew;
|
||||
size_t skew;
|
||||
size_t asize;
|
||||
|
||||
if (pool->live) {
|
||||
pool->live->next = pool->free;
|
||||
pool->free = pool->live;
|
||||
}
|
||||
struct pool_extent *ext;
|
||||
|
||||
free = pool->size;
|
||||
bound = 0;
|
||||
@@ -125,25 +111,26 @@ pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
if (pool->flags & POOL_APPEND)
|
||||
asize += sizeof (struct pool_extent);
|
||||
|
||||
if (!(start = (void *) malloc(asize)))
|
||||
goto bomb;
|
||||
if (!(start = new_array(char, asize)))
|
||||
goto bomb_out;
|
||||
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(start, 0, pool->size);
|
||||
memset(start, 0, free);
|
||||
|
||||
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;
|
||||
ext = PTR_ADD(start, free);
|
||||
else if (!(ext = new(struct pool_extent)))
|
||||
goto bomb_out;
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (sqew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
|
||||
bound += sqew;
|
||||
free -= sqew;
|
||||
&& (skew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
|
||||
bound += skew;
|
||||
free -= skew;
|
||||
}
|
||||
pool->live->start = start;
|
||||
pool->live->free = free;
|
||||
pool->live->bound = bound;
|
||||
pool->live->next = NULL;
|
||||
ext->start = start;
|
||||
ext->free = free;
|
||||
ext->bound = bound;
|
||||
ext->next = pool->extents;
|
||||
pool->extents = ext;
|
||||
|
||||
pool->e_created++;
|
||||
}
|
||||
@@ -151,22 +138,24 @@ pool_alloc(alloc_pool_t p, size_t len, char *bomb)
|
||||
pool->n_allocated++;
|
||||
pool->b_allocated += len;
|
||||
|
||||
pool->live->free -= len;
|
||||
pool->extents->free -= len;
|
||||
|
||||
return PTR_ADD(pool->live->start, pool->live->free);
|
||||
return PTR_ADD(pool->extents->start, pool->extents->free);
|
||||
|
||||
bomb:
|
||||
bomb_out:
|
||||
if (pool->bomb)
|
||||
(*pool->bomb)(bomb);
|
||||
(*pool->bomb)(bomb_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This function allows you to declare memory in the pool that you are done
|
||||
* using. If you free all the memory in a pool's extent, that extent will
|
||||
* be freed. */
|
||||
void
|
||||
pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur;
|
||||
struct pool_extent *prev;
|
||||
struct alloc_pool *pool = (struct alloc_pool *)p;
|
||||
struct pool_extent *cur, *prev;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
@@ -176,38 +165,10 @@ 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) {
|
||||
pool->live->next = pool->free;
|
||||
pool->free = pool->live;
|
||||
pool->live = NULL;
|
||||
return;
|
||||
}
|
||||
pool->n_freed++;
|
||||
pool->b_freed += len;
|
||||
|
||||
cur = pool->live;
|
||||
if (cur && addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size)) {
|
||||
if (addr == PTR_ADD(cur->start, cur->free)) {
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, len);
|
||||
pool->b_freed += len;
|
||||
} else
|
||||
cur->bound += len;
|
||||
if (cur->free + cur->bound >= pool->size) {
|
||||
size_t sqew;
|
||||
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (sqew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
|
||||
cur->bound += sqew;
|
||||
cur->free -= sqew;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (prev = NULL, cur = pool->free; cur; prev = cur, cur = cur->next) {
|
||||
for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
|
||||
if (addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
break;
|
||||
@@ -215,22 +176,122 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
if (prev) {
|
||||
prev->next = cur->next;
|
||||
cur->next = pool->free;
|
||||
pool->free = cur;
|
||||
if (!prev) {
|
||||
/* The "live" extent is kept ready for more allocations. */
|
||||
if (cur->free + cur->bound + len >= pool->size) {
|
||||
size_t skew;
|
||||
|
||||
if (pool->flags & POOL_CLEAR) {
|
||||
memset(PTR_ADD(cur->start, cur->free), 0,
|
||||
pool->size - cur->free);
|
||||
}
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
|
||||
cur->bound += skew;
|
||||
cur->free -= skew;
|
||||
}
|
||||
} else if (addr == PTR_ADD(cur->start, cur->free)) {
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, len);
|
||||
cur->free += len;
|
||||
} else
|
||||
cur->bound += len;
|
||||
} else {
|
||||
cur->bound += len;
|
||||
|
||||
if (cur->free + cur->bound >= pool->size) {
|
||||
prev->next = cur->next;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
pool->e_freed++;
|
||||
} else if (prev != pool->extents) {
|
||||
/* Move the extent to be the first non-live extent. */
|
||||
prev->next = cur->next;
|
||||
cur->next = pool->extents->next;
|
||||
pool->extents->next = cur;
|
||||
}
|
||||
}
|
||||
cur->bound += len;
|
||||
}
|
||||
|
||||
if (cur->free + cur->bound >= pool->size) {
|
||||
pool->free = cur->next;
|
||||
/* This allows you to declare that the given address marks the edge of some
|
||||
* pool memory that is no longer needed. Any extents that hold only data
|
||||
* older than the boundary address are freed. NOTE: You MUST NOT USE BOTH
|
||||
* pool_free() and pool_free_old() on the same pool!! */
|
||||
void
|
||||
pool_free_old(alloc_pool_t p, void *addr)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *)p;
|
||||
struct pool_extent *cur, *prev, *next;
|
||||
|
||||
if (!pool || !addr)
|
||||
return;
|
||||
|
||||
for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
|
||||
if (addr >= cur->start
|
||||
&& addr < PTR_ADD(cur->start, pool->size))
|
||||
break;
|
||||
}
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
if (addr == PTR_ADD(cur->start, cur->free)) {
|
||||
if (prev) {
|
||||
prev->next = NULL;
|
||||
next = cur;
|
||||
} else {
|
||||
size_t skew;
|
||||
|
||||
/* The most recent live extent can just be reset. */
|
||||
if (pool->flags & POOL_CLEAR)
|
||||
memset(addr, 0, pool->size - cur->free);
|
||||
cur->free = pool->size;
|
||||
cur->bound = 0;
|
||||
if (pool->flags & POOL_QALIGN && pool->quantum > 1
|
||||
&& (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
|
||||
cur->bound += skew;
|
||||
cur->free -= skew;
|
||||
}
|
||||
next = cur->next;
|
||||
cur->next = NULL;
|
||||
}
|
||||
} else {
|
||||
next = cur->next;
|
||||
cur->next = NULL;
|
||||
}
|
||||
|
||||
while ((cur = next) != NULL) {
|
||||
next = cur->next;
|
||||
free(cur->start);
|
||||
if (!(pool->flags & POOL_APPEND))
|
||||
free(cur);
|
||||
pool->e_freed++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the current extent doesn't have "len" free space in it, mark it as full
|
||||
* so that the next alloc will start a new extent. If len is (size_t)-1, this
|
||||
* bump will always occur. The function returns a boundary address that can
|
||||
* be used with pool_free_old(), or a NULL if no memory is allocated. */
|
||||
void *
|
||||
pool_boundary(alloc_pool_t p, size_t len)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *)p;
|
||||
struct pool_extent *cur;
|
||||
|
||||
if (!pool || !pool->extents)
|
||||
return NULL;
|
||||
|
||||
cur = pool->extents;
|
||||
|
||||
if (cur->free < len) {
|
||||
cur->bound += cur->free;
|
||||
cur->free = 0;
|
||||
}
|
||||
|
||||
return PTR_ADD(cur->start, cur->free);
|
||||
}
|
||||
|
||||
#define FDPRINT(label, value) \
|
||||
@@ -259,22 +320,17 @@ pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
FDPRINT(" Extents freed: %12ld\n", pool->e_freed);
|
||||
FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated);
|
||||
FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed);
|
||||
FDPRINT(" Alloc bytes: %12.0f\n", (double) pool->b_allocated);
|
||||
FDPRINT(" Free bytes: %12.0f\n", (double) pool->b_freed);
|
||||
FDPRINT(" Bytes allocated: %12.0f\n", (double) pool->b_allocated);
|
||||
FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed);
|
||||
|
||||
if (summarize)
|
||||
return;
|
||||
|
||||
if (!pool->live && !pool->free)
|
||||
if (!pool->extents)
|
||||
return;
|
||||
|
||||
write(fd, "\n", 1);
|
||||
|
||||
if (pool->live)
|
||||
FDEXTSTAT(pool->live);
|
||||
strlcpy(buf, " FREE BOUND\n", sizeof buf);
|
||||
write(fd, buf, strlen(buf));
|
||||
|
||||
for (cur = pool->free; cur; cur = cur->next)
|
||||
for (cur = pool->extents; cur; cur = cur->next)
|
||||
FDEXTSTAT(cur);
|
||||
}
|
||||
|
||||
@@ -7,14 +7,15 @@
|
||||
|
||||
typedef void *alloc_pool_t;
|
||||
|
||||
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(char *), int flags);
|
||||
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags);
|
||||
void pool_destroy(alloc_pool_t pool);
|
||||
void *pool_alloc(alloc_pool_t pool, size_t size, char *bomb);
|
||||
void *pool_alloc(alloc_pool_t pool, size_t size, const char *bomb_msg);
|
||||
void pool_free(alloc_pool_t pool, size_t size, void *addr);
|
||||
void pool_free_old(alloc_pool_t pool, void *addr);
|
||||
void *pool_boundary(alloc_pool_t pool, size_t size);
|
||||
|
||||
#define pool_talloc(pool, type, count, bomb) \
|
||||
((type *)pool_alloc(pool, sizeof(type) * count, bomb))
|
||||
#define pool_talloc(pool, type, count, bomb_msg) \
|
||||
((type *)pool_alloc(pool, sizeof(type) * count, bomb_msg))
|
||||
|
||||
#define pool_tfree(pool, type, count, addr) \
|
||||
(pool_free(pool, sizeof(type) * count, addr))
|
||||
|
||||
|
||||
2771
lib/sysacls.c
Normal file
2771
lib/sysacls.c
Normal file
File diff suppressed because it is too large
Load Diff
304
lib/sysacls.h
Normal file
304
lib/sysacls.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Unix SMB/Netbios implementation.
|
||||
* Version 2.2.x
|
||||
* Portable SMB ACL interface
|
||||
* Copyright (C) Jeremy Allison 2000
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
|
||||
#ifdef HAVE_SYS_ACL_H
|
||||
#include <sys/acl.h>
|
||||
#endif
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
#include <acl/libacl.h>
|
||||
#endif
|
||||
|
||||
#define SMB_MALLOC(cnt) new_array(char, cnt)
|
||||
#define SMB_MALLOC_P(obj) new_array(obj, 1)
|
||||
#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt)
|
||||
#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt)
|
||||
#define slprintf snprintf
|
||||
|
||||
#if defined HAVE_POSIX_ACLS /*-----------------------------------------------*/
|
||||
|
||||
/* This is an identity mapping (just remove the SMB_). */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACL_USER
|
||||
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
|
||||
#define SMB_ACL_GROUP ACL_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
|
||||
#define SMB_ACL_OTHER ACL_OTHER
|
||||
#define SMB_ACL_MASK ACL_MASK
|
||||
|
||||
#define SMB_ACL_T acl_t
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
|
||||
#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_TRU64_ACLS /*---------------------------------------------*/
|
||||
|
||||
/* This is for DEC/Compaq Tru64 UNIX */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACL_USER
|
||||
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
|
||||
#define SMB_ACL_GROUP ACL_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
|
||||
#define SMB_ACL_OTHER ACL_OTHER
|
||||
#define SMB_ACL_MASK ACL_MASK
|
||||
|
||||
#define SMB_ACL_T acl_t
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS /*-------------*/
|
||||
|
||||
/* Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
|
||||
* Modified by Toomas Soome <tsoome@ut.ee> for Solaris. */
|
||||
|
||||
/* SVR4.2 ES/MP ACLs */
|
||||
typedef int SMB_ACL_TAG_T;
|
||||
typedef int SMB_ACL_TYPE_T;
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER USER
|
||||
#define SMB_ACL_USER_OBJ USER_OBJ
|
||||
#define SMB_ACL_GROUP GROUP
|
||||
#define SMB_ACL_GROUP_OBJ GROUP_OBJ
|
||||
#define SMB_ACL_OTHER OTHER_OBJ
|
||||
#define SMB_ACL_MASK CLASS_OBJ
|
||||
|
||||
typedef struct SMB_ACL_T {
|
||||
int size;
|
||||
int count;
|
||||
int next;
|
||||
struct acl acl[1];
|
||||
} *SMB_ACL_T;
|
||||
|
||||
typedef struct acl *SMB_ACL_ENTRY_T;
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS 0
|
||||
#define SMB_ACL_TYPE_DEFAULT 1
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#define SMB_ACL_LOSES_SPECIAL_MODE_BITS
|
||||
#endif
|
||||
|
||||
#elif defined HAVE_HPUX_ACLS /*----------------------------------------------*/
|
||||
|
||||
/* Based on the Solaris & UnixWare code. */
|
||||
|
||||
#undef GROUP
|
||||
#include <sys/aclv.h>
|
||||
|
||||
/* SVR4.2 ES/MP ACLs */
|
||||
typedef int SMB_ACL_TAG_T;
|
||||
typedef int SMB_ACL_TYPE_T;
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER USER
|
||||
#define SMB_ACL_USER_OBJ USER_OBJ
|
||||
#define SMB_ACL_GROUP GROUP
|
||||
#define SMB_ACL_GROUP_OBJ GROUP_OBJ
|
||||
#define SMB_ACL_OTHER OTHER_OBJ
|
||||
#define SMB_ACL_MASK CLASS_OBJ
|
||||
|
||||
typedef struct SMB_ACL_T {
|
||||
int size;
|
||||
int count;
|
||||
int next;
|
||||
struct acl acl[1];
|
||||
} *SMB_ACL_T;
|
||||
|
||||
typedef struct acl *SMB_ACL_ENTRY_T;
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS 0
|
||||
#define SMB_ACL_TYPE_DEFAULT 1
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_IRIX_ACLS /*----------------------------------------------*/
|
||||
|
||||
/* IRIX ACLs */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACL_USER
|
||||
#define SMB_ACL_USER_OBJ ACL_USER_OBJ
|
||||
#define SMB_ACL_GROUP ACL_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
|
||||
#define SMB_ACL_OTHER ACL_OTHER_OBJ
|
||||
#define SMB_ACL_MASK ACL_MASK
|
||||
|
||||
typedef struct SMB_ACL_T {
|
||||
int next;
|
||||
BOOL freeaclp;
|
||||
struct acl *aclp;
|
||||
} *SMB_ACL_T;
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 0
|
||||
#define SMB_ACL_NEXT_ENTRY 1
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined HAVE_AIX_ACLS /*-----------------------------------------------*/
|
||||
|
||||
/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
|
||||
|
||||
#include "/usr/include/acl.h"
|
||||
|
||||
struct acl_entry_link{
|
||||
struct acl_entry_link *prevp;
|
||||
struct new_acl_entry *entryp;
|
||||
struct acl_entry_link *nextp;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct new_acl_entry{
|
||||
unsigned short ace_len;
|
||||
unsigned short ace_type;
|
||||
unsigned int ace_access;
|
||||
struct ace_id ace_id[1];
|
||||
};
|
||||
|
||||
#define SMB_ACL_ENTRY_T struct new_acl_entry*
|
||||
#define SMB_ACL_T struct acl_entry_link*
|
||||
|
||||
#define SMB_ACL_TAG_T unsigned short
|
||||
#define SMB_ACL_TYPE_T int
|
||||
|
||||
/* Types of ACLs. */
|
||||
#define SMB_ACL_USER ACEID_USER
|
||||
#define SMB_ACL_USER_OBJ 3
|
||||
#define SMB_ACL_GROUP ACEID_GROUP
|
||||
#define SMB_ACL_GROUP_OBJ 4
|
||||
#define SMB_ACL_OTHER 5
|
||||
#define SMB_ACL_MASK 6
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY 1
|
||||
#define SMB_ACL_NEXT_ENTRY 2
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS 0
|
||||
#define SMB_ACL_TYPE_DEFAULT 1
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1)
|
||||
|
||||
#define SMB_ACL_NEED_SORT
|
||||
|
||||
#elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
|
||||
|
||||
/* Special handling for OS X ACLs */
|
||||
|
||||
#define SMB_ACL_TAG_T acl_tag_t
|
||||
#define SMB_ACL_TYPE_T acl_type_t
|
||||
|
||||
#define SMB_ACL_T acl_t
|
||||
|
||||
#define SMB_ACL_ENTRY_T acl_entry_t
|
||||
|
||||
#define SMB_ACL_USER 1
|
||||
#define SMB_ACL_GROUP 2
|
||||
|
||||
#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
|
||||
#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
|
||||
|
||||
#define SMB_ACL_TYPE_ACCESS ACL_TYPE_EXTENDED
|
||||
#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
|
||||
|
||||
#define SMB_ACL_VALID_NAME_BITS ((1<<25)-1)
|
||||
#define SMB_ACL_VALID_OBJ_BITS 0
|
||||
|
||||
/*#undef SMB_ACL_NEED_SORT*/
|
||||
|
||||
#else /*---------------------------------------------------------------------*/
|
||||
|
||||
/* Unknown platform. */
|
||||
|
||||
#error Cannot handle ACLs on this platform!
|
||||
|
||||
#endif
|
||||
|
||||
int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
|
||||
int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
|
||||
int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p);
|
||||
SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
|
||||
SMB_ACL_T sys_acl_get_fd(int fd);
|
||||
SMB_ACL_T sys_acl_init(int count);
|
||||
int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
|
||||
int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype, uint32 bits, id_t u_g_id);
|
||||
int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits);
|
||||
int sys_acl_valid(SMB_ACL_T theacl);
|
||||
int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
|
||||
int sys_acl_set_fd(int fd, SMB_ACL_T theacl);
|
||||
int sys_acl_delete_def_file(const char *name);
|
||||
int sys_acl_free_acl(SMB_ACL_T the_acl);
|
||||
int no_acl_syscall_error(int err);
|
||||
|
||||
#endif /* SUPPORT_ACLS */
|
||||
134
lib/sysxattrs.c
Normal file
134
lib/sysxattrs.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Extended attribute support for rsync.
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
* Written by Jay Fenlason.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "sysxattrs.h"
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
|
||||
#if defined HAVE_LINUX_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return lgetxattr(path, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(filedes, name, value, size);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
return lsetxattr(path, name, value, size, 0);
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
return lremovexattr(path, name);
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
return llistxattr(path, list, size);
|
||||
}
|
||||
|
||||
#elif HAVE_OSX_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(filedes, name, value, size, 0, 0);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
return removexattr(path, name, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
return listxattr(path, list, size, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
#elif HAVE_FREEBSD_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
return extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
return extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name);
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
unsigned char keylen;
|
||||
ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
|
||||
|
||||
if (len <= 0 || (size_t)len > size)
|
||||
return len;
|
||||
|
||||
/* FreeBSD puts a single-byte length before each string, with no '\0'
|
||||
* terminator. We need to change this into a series of null-terminted
|
||||
* strings. Since the size is the same, we can simply transform the
|
||||
* output in place. */
|
||||
for (off = 0; off < len; off += keylen + 1) {
|
||||
keylen = ((unsigned char*)list)[off];
|
||||
if (off + keylen >= len) {
|
||||
/* Should be impossible, but kernel bugs happen! */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
memmove(list+off, list+off+1, keylen);
|
||||
list[off+keylen] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error You need to create xattr compatibility functions.
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SUPPORT_XATTRS */
|
||||
26
lib/sysxattrs.h
Normal file
26
lib/sysxattrs.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifdef SUPPORT_XATTRS
|
||||
|
||||
#if defined HAVE_ATTR_XATTR_H
|
||||
#include <attr/xattr.h>
|
||||
#elif defined HAVE_SYS_XATTR_H
|
||||
#include <sys/xattr.h>
|
||||
#elif defined HAVE_SYS_EXTATTR_H
|
||||
#include <sys/extattr.h>
|
||||
#endif
|
||||
|
||||
/* Linux 2.4 does not define this as a distinct errno value: */
|
||||
#ifndef ENOATTR
|
||||
#define ENOATTR ENODATA
|
||||
#endif
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size);
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size);
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size);
|
||||
int sys_lremovexattr(const char *path, const char *name);
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size);
|
||||
|
||||
#else
|
||||
|
||||
/* No xattrs available */
|
||||
|
||||
#endif
|
||||
@@ -165,7 +165,7 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
|
||||
} else if (p_ch == '[' && p[1] == ':') {
|
||||
const uchar *s;
|
||||
int i;
|
||||
for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {}
|
||||
for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
|
||||
if (!p_ch)
|
||||
return ABORT_ALL;
|
||||
i = p - s - 1;
|
||||
|
||||
31
loadparm.c
31
loadparm.c
@@ -4,7 +4,7 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -13,8 +13,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* some fixes
|
||||
@@ -51,6 +50,7 @@
|
||||
/* TODO: Parameter to set debug level on server. */
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
|
||||
#define strequal(a,b) (strcasecmp(a,b)==0)
|
||||
#define BOOLSTR(b) ((b) ? "Yes" : "No")
|
||||
@@ -61,6 +61,9 @@ typedef char pstring[1024];
|
||||
#define LOG_DAEMON 0
|
||||
#endif
|
||||
|
||||
#define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
|
||||
" *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg"
|
||||
|
||||
/* the following are used by loadparm for option lists */
|
||||
typedef enum
|
||||
{
|
||||
@@ -150,6 +153,7 @@ typedef struct
|
||||
int syslog_facility;
|
||||
int timeout;
|
||||
|
||||
BOOL fake_super;
|
||||
BOOL ignore_errors;
|
||||
BOOL ignore_nonreadable;
|
||||
BOOL list;
|
||||
@@ -169,7 +173,7 @@ static service sDefault =
|
||||
{
|
||||
/* auth_users; */ NULL,
|
||||
/* comment; */ NULL,
|
||||
/* dont_compress; */ "*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz",
|
||||
/* dont_compress; */ DEFAULT_DONT_COMPRESS,
|
||||
/* exclude; */ NULL,
|
||||
/* exclude_from; */ NULL,
|
||||
/* filter; */ NULL,
|
||||
@@ -197,6 +201,7 @@ static service sDefault =
|
||||
/* syslog_facility; */ LOG_DAEMON,
|
||||
/* timeout; */ 0,
|
||||
|
||||
/* fake_super; */ False,
|
||||
/* ignore_errors; */ False,
|
||||
/* ignore_nonreadable; */ False,
|
||||
/* list; */ True,
|
||||
@@ -298,6 +303,7 @@ static struct parm_struct parm_table[] =
|
||||
{"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},
|
||||
{"fake super", P_BOOL, P_LOCAL, &sDefault.fake_super, 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},
|
||||
@@ -412,6 +418,7 @@ 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_fake_super, fake_super)
|
||||
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
|
||||
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
@@ -524,12 +531,11 @@ static int strwicmp(char *psz1, char *psz2)
|
||||
/* sync the strings on first non-whitespace */
|
||||
while (1)
|
||||
{
|
||||
while (isspace(* (unsigned char *) psz1))
|
||||
while (isSpace(psz1))
|
||||
psz1++;
|
||||
while (isspace(* (unsigned char *) psz2))
|
||||
while (isSpace(psz2))
|
||||
psz2++;
|
||||
if (toupper(* (unsigned char *) psz1) != toupper(* (unsigned char *) psz2)
|
||||
|| *psz1 == '\0' || *psz2 == '\0')
|
||||
if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0')
|
||||
break;
|
||||
psz1++;
|
||||
psz2++;
|
||||
@@ -803,8 +809,6 @@ static BOOL do_section(char *sectionname)
|
||||
***************************************************************************/
|
||||
BOOL lp_load(char *pszFname, int globals_only)
|
||||
{
|
||||
extern int am_server;
|
||||
extern int am_root;
|
||||
pstring n2;
|
||||
BOOL bRetval;
|
||||
|
||||
@@ -814,12 +818,7 @@ BOOL lp_load(char *pszFname, int globals_only)
|
||||
|
||||
init_globals();
|
||||
|
||||
if (pszFname)
|
||||
pstrcpy(n2,pszFname);
|
||||
else if (am_server && !am_root)
|
||||
pstrcpy(n2,RSYNCD_USERCONF);
|
||||
else
|
||||
pstrcpy(n2,RSYNCD_SYSCONF);
|
||||
pstrcpy(n2, pszFname);
|
||||
|
||||
/* We get sections first, so have to start 'behind' to make up */
|
||||
iServiceIndex = -1;
|
||||
|
||||
260
log.c
260
log.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,20 +16,18 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int local_server;
|
||||
extern int quiet;
|
||||
extern int module_id;
|
||||
@@ -37,6 +35,8 @@ extern int msg_fd_out;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int preserve_times;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int stdout_format_has_i;
|
||||
extern int stdout_format_has_o_or_i;
|
||||
extern int logfile_format_has_i;
|
||||
@@ -46,10 +46,14 @@ extern char *auth_user;
|
||||
extern char *stdout_format;
|
||||
extern char *logfile_format;
|
||||
extern char *logfile_name;
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#ifdef ICONV_CONST
|
||||
extern iconv_t ic_chck;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
#endif
|
||||
extern char curr_dir[];
|
||||
extern char *module_dir;
|
||||
extern unsigned int module_dirlen;
|
||||
|
||||
static int log_initialised;
|
||||
@@ -103,7 +107,7 @@ static char const *rerr_name(int code)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void logit(int priority, char *buf)
|
||||
static void logit(int priority, const char *buf)
|
||||
{
|
||||
if (logfile_was_closed)
|
||||
logfile_reopen();
|
||||
@@ -214,11 +218,11 @@ static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
|
||||
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)))
|
||||
&& isDigit(s + 2)
|
||||
&& isDigit(s + 3)
|
||||
&& isDigit(s + 4))
|
||||
|| (*s != '\t'
|
||||
&& ((use_isprint && !isprint(*(uchar*)s))
|
||||
&& ((use_isprint && !isPrint(s))
|
||||
|| *(uchar*)s < ' '))) {
|
||||
if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
@@ -233,17 +237,25 @@ static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
|
||||
/* this is the underlying (unformatted) rsync debugging function. Call
|
||||
* it with FINFO, FERROR or FLOG. Note: recursion can happen with
|
||||
* certain fatal conditions. */
|
||||
void rwrite(enum logcode code, char *buf, int len)
|
||||
void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
{
|
||||
int trailing_CR_or_NL;
|
||||
FILE *f = NULL;
|
||||
#ifdef ICONV_OPTION
|
||||
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck;
|
||||
#else
|
||||
#ifdef ICONV_CONST
|
||||
iconv_t ic = ic_chck;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (am_server && msg_fd_out >= 0) {
|
||||
assert(!is_utf8);
|
||||
/* Pass the message to our sibling. */
|
||||
send_msg((enum msgcode)code, buf, len);
|
||||
send_msg((enum msgcode)code, buf, len, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -276,7 +288,7 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
|
||||
if (am_server) {
|
||||
/* Pass the message to the non-server side. */
|
||||
if (send_msg((enum msgcode)code, buf, len))
|
||||
if (send_msg((enum msgcode)code, buf, len, !is_utf8))
|
||||
return;
|
||||
if (am_daemon) {
|
||||
/* TODO: can we send the error to the user somehow? */
|
||||
@@ -299,27 +311,27 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
|
||||
? buf[--len] : 0;
|
||||
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
if (ic_chck != (iconv_t)-1) {
|
||||
#ifdef ICONV_CONST
|
||||
if (ic != (iconv_t)-1) {
|
||||
xbuf outbuf, inbuf;
|
||||
char convbuf[1024];
|
||||
char *in_buf = buf, *out_buf = convbuf;
|
||||
size_t in_cnt = len, out_cnt = sizeof convbuf - 1;
|
||||
int ierrno;
|
||||
|
||||
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;
|
||||
INIT_CONST_XBUF(outbuf, convbuf);
|
||||
INIT_XBUF(inbuf, (char*)buf, len, -1);
|
||||
|
||||
while (inbuf.len) {
|
||||
iconvbufs(ic, &inbuf, &outbuf, 0);
|
||||
ierrno = errno;
|
||||
if (outbuf.len) {
|
||||
filtered_fwrite(f, convbuf, outbuf.len, 0);
|
||||
outbuf.len = 0;
|
||||
}
|
||||
if (errno == E2BIG)
|
||||
if (!ierrno || ierrno == E2BIG)
|
||||
continue;
|
||||
fprintf(f, "\\#%03o", *(uchar*)in_buf++);
|
||||
in_cnt--;
|
||||
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
|
||||
inbuf.len--;
|
||||
}
|
||||
if (out_buf != convbuf)
|
||||
filtered_fwrite(f, convbuf, out_buf - convbuf, 0);
|
||||
} else
|
||||
#endif
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars);
|
||||
@@ -368,7 +380,7 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
}
|
||||
}
|
||||
|
||||
rwrite(code, buf, len);
|
||||
rwrite(code, buf, len, 0);
|
||||
}
|
||||
|
||||
/* This is like rprintf, but it also tries to print some
|
||||
@@ -399,7 +411,7 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
if (len >= sizeof buf)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
rwrite(code, buf, len);
|
||||
rwrite(code, buf, len, 0);
|
||||
}
|
||||
|
||||
void rflush(enum logcode code)
|
||||
@@ -418,12 +430,14 @@ void rflush(enum logcode code)
|
||||
}
|
||||
|
||||
/* A generic logging routine for send/recv, with parameter substitiution. */
|
||||
static void log_formatted(enum logcode code, char *format, char *op,
|
||||
struct file_struct *file, struct stats *initial_stats,
|
||||
int iflags, char *hlink)
|
||||
static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
struct file_struct *file, const char *fname,
|
||||
struct stats *initial_stats, int iflags,
|
||||
const char *hlink)
|
||||
{
|
||||
char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
|
||||
char *p, *s, *n;
|
||||
char *p, *s, *c;
|
||||
const char *n;
|
||||
size_t len, total;
|
||||
int64 b;
|
||||
|
||||
@@ -442,14 +456,14 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
|
||||
for (p = buf; (p = strchr(p, '%')) != NULL; ) {
|
||||
s = p++;
|
||||
n = fmt + 1;
|
||||
c = fmt + 1;
|
||||
if (*p == '-')
|
||||
*n++ = *p++;
|
||||
while (isdigit(*(uchar*)p) && n - fmt < (int)(sizeof fmt) - 8)
|
||||
*n++ = *p++;
|
||||
*c++ = *p++;
|
||||
while (isDigit(p) && c - fmt < (int)(sizeof fmt) - 8)
|
||||
*c++ = *p++;
|
||||
if (!*p)
|
||||
break;
|
||||
*n = '\0';
|
||||
*c = '\0';
|
||||
n = NULL;
|
||||
|
||||
switch (*p) {
|
||||
@@ -464,22 +478,22 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
case 'l':
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(double)file->length);
|
||||
(double)F_LENGTH(file));
|
||||
n = buf2;
|
||||
break;
|
||||
case 'U':
|
||||
strlcat(fmt, "ld", sizeof fmt);
|
||||
strlcat(fmt, "u", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(long)file->uid);
|
||||
uid_ndx ? F_OWNER(file) : 0);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'G':
|
||||
if (file->gid == GID_NONE)
|
||||
if (!gid_ndx || file->flags & FLAG_SKIP_GROUP)
|
||||
n = "DEFAULT";
|
||||
else {
|
||||
strlcat(fmt, "ld", sizeof fmt);
|
||||
strlcat(fmt, "u", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
(long)file->gid);
|
||||
F_GROUP(file));
|
||||
n = buf2;
|
||||
}
|
||||
break;
|
||||
@@ -490,54 +504,65 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
n = buf2;
|
||||
break;
|
||||
case 'M':
|
||||
n = timestring(file->modtime);
|
||||
{
|
||||
char *cp = n;
|
||||
while ((cp = strchr(cp, ' ')) != NULL)
|
||||
*cp = '-';
|
||||
}
|
||||
n = c = timestring(file->modtime);
|
||||
while ((c = strchr(p, ' ')) != NULL)
|
||||
*c = '-';
|
||||
break;
|
||||
case 'B':
|
||||
n = buf2 + MAXPATHLEN - PERMSTRING_SIZE;
|
||||
permstring(n - 1, file->mode); /* skip the type char */
|
||||
c = buf2 + MAXPATHLEN - PERMSTRING_SIZE - 1;
|
||||
permstring(c, file->mode);
|
||||
n = c + 1; /* skip the type char */
|
||||
break;
|
||||
case 'o':
|
||||
n = op;
|
||||
break;
|
||||
case 'f':
|
||||
n = f_name(file, NULL);
|
||||
if (am_sender && file->dir.root) {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
file->dir.root, n);
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1])
|
||||
strlcpy(n, buf2, MAXPATHLEN);
|
||||
else
|
||||
n = buf2;
|
||||
} else if (*n != '/') {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
curr_dir + module_dirlen, n);
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1])
|
||||
strlcpy(n, buf2, MAXPATHLEN);
|
||||
else
|
||||
n = buf2;
|
||||
if (fname) {
|
||||
c = f_name_buf();
|
||||
strlcpy(c, fname, MAXPATHLEN);
|
||||
} else
|
||||
clean_fname(n, 0);
|
||||
c = f_name(file, NULL);
|
||||
if (am_sender && F_PATHNAME(file)) {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
F_PATHNAME(file), c);
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1]) {
|
||||
strlcpy(c, buf2, MAXPATHLEN);
|
||||
n = c;
|
||||
} else
|
||||
n = buf2;
|
||||
} else if (am_daemon && *c != '/') {
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
curr_dir + module_dirlen, c);
|
||||
clean_fname(buf2, 0);
|
||||
if (fmt[1]) {
|
||||
strlcpy(c, buf2, MAXPATHLEN);
|
||||
n = c;
|
||||
} else
|
||||
n = buf2;
|
||||
} else {
|
||||
clean_fname(c, 0);
|
||||
n = c;
|
||||
}
|
||||
if (*n == '/')
|
||||
n++;
|
||||
break;
|
||||
case 'n':
|
||||
n = f_name(file, NULL);
|
||||
if (fname) {
|
||||
c = f_name_buf();
|
||||
strlcpy(c, fname, MAXPATHLEN);
|
||||
} else
|
||||
c = f_name(file, NULL);
|
||||
if (S_ISDIR(file->mode))
|
||||
strlcat(n, "/", MAXPATHLEN);
|
||||
strlcat(c, "/", MAXPATHLEN);
|
||||
n = c;
|
||||
break;
|
||||
case 'L':
|
||||
if (hlink && *hlink) {
|
||||
n = hlink;
|
||||
strlcpy(buf2, " => ", sizeof buf2);
|
||||
} else if (S_ISLNK(file->mode) && file->u.link) {
|
||||
n = file->u.link;
|
||||
} else if (S_ISLNK(file->mode) && !fname) {
|
||||
n = F_SYMLINK(file);
|
||||
strlcpy(buf2, " -> ", sizeof buf2);
|
||||
} else {
|
||||
n = "";
|
||||
@@ -556,7 +581,7 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
n = timestring(time(NULL));
|
||||
break;
|
||||
case 'P':
|
||||
n = lp_path(module_id);
|
||||
n = module_dir;
|
||||
break;
|
||||
case 'u':
|
||||
n = auth_user;
|
||||
@@ -590,40 +615,41 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
n = "*deleting";
|
||||
break;
|
||||
}
|
||||
n = buf2 + MAXPATHLEN - 32;
|
||||
n[0] = iflags & ITEM_LOCAL_CHANGE
|
||||
n = c = buf2 + MAXPATHLEN - 32;
|
||||
c[0] = iflags & ITEM_LOCAL_CHANGE
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
n[1] = S_ISDIR(file->mode) ? 'd'
|
||||
c[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) ? '.'
|
||||
c[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
|
||||
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !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] = '.';
|
||||
n[9] = '\0';
|
||||
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
|
||||
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
|
||||
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
|
||||
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
|
||||
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
|
||||
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
|
||||
c[11] = '\0';
|
||||
|
||||
if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
|
||||
char ch = iflags & ITEM_IS_NEW ? '+' : '?';
|
||||
int i;
|
||||
for (i = 2; n[i]; i++)
|
||||
n[i] = ch;
|
||||
} else if (n[0] == '.' || n[0] == 'h'
|
||||
|| (n[0] == 'c' && n[1] == 'f')) {
|
||||
for (i = 2; c[i]; i++)
|
||||
c[i] = ch;
|
||||
} else if (c[0] == '.' || c[0] == 'h' || c[0] == 'c') {
|
||||
int i;
|
||||
for (i = 2; n[i]; i++) {
|
||||
if (n[i] != '.')
|
||||
for (i = 2; c[i]; i++) {
|
||||
if (c[i] != '.')
|
||||
break;
|
||||
}
|
||||
if (!n[i]) {
|
||||
for (i = 2; n[i]; i++)
|
||||
n[i] = ' ';
|
||||
if (!c[i]) {
|
||||
for (i = 2; c[i]; i++)
|
||||
c[i] = ' ';
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -662,7 +688,7 @@ static void log_formatted(enum logcode code, char *format, char *op,
|
||||
p = s + len;
|
||||
}
|
||||
|
||||
rwrite(code, buf, total);
|
||||
rwrite(code, buf, total, 0);
|
||||
}
|
||||
|
||||
/* Return 1 if the format escape is in the log-format string (e.g. look for
|
||||
@@ -677,7 +703,7 @@ int log_format_has(const char *format, char esc)
|
||||
for (p = format; (p = strchr(p, '%')) != NULL; ) {
|
||||
if (*++p == '-')
|
||||
p++;
|
||||
while (isdigit(*(uchar*)p))
|
||||
while (isDigit(p))
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
@@ -691,22 +717,22 @@ int log_format_has(const char *format, char esc)
|
||||
* to stdout. If it is FLOG, it just goes to the log file. Otherwise we
|
||||
* output to both. */
|
||||
void log_item(enum logcode code, struct file_struct *file,
|
||||
struct stats *initial_stats, int iflags, char *hlink)
|
||||
struct stats *initial_stats, int iflags, const char *hlink)
|
||||
{
|
||||
char *s_or_r = am_sender ? "send" : "recv";
|
||||
const char *s_or_r = am_sender ? "send" : "recv";
|
||||
|
||||
if (code != FLOG && stdout_format && !am_server) {
|
||||
log_formatted(FCLIENT, stdout_format, s_or_r,
|
||||
file, initial_stats, iflags, hlink);
|
||||
file, NULL, initial_stats, iflags, hlink);
|
||||
}
|
||||
if (code != FCLIENT && logfile_format && *logfile_format) {
|
||||
log_formatted(FLOG, logfile_format, s_or_r,
|
||||
file, initial_stats, iflags, hlink);
|
||||
file, NULL, initial_stats, iflags, hlink);
|
||||
}
|
||||
}
|
||||
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
char *buf)
|
||||
const char *buf)
|
||||
{
|
||||
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
|
||||
int see_item = itemizing && (significant_flags || *buf
|
||||
@@ -723,24 +749,26 @@ void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
}
|
||||
}
|
||||
|
||||
void log_delete(char *fname, int mode)
|
||||
void log_delete(const char *fname, int mode)
|
||||
{
|
||||
static struct file_struct file;
|
||||
static struct {
|
||||
union file_extras ex[4]; /* just in case... */
|
||||
struct file_struct file;
|
||||
} x;
|
||||
int len = strlen(fname);
|
||||
char *fmt;
|
||||
const char *fmt;
|
||||
|
||||
file.mode = mode;
|
||||
file.basename = fname;
|
||||
x.file.mode = mode;
|
||||
|
||||
if (!verbose && !stdout_format)
|
||||
;
|
||||
else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
|
||||
if (S_ISDIR(mode))
|
||||
len++; /* directories include trailing null */
|
||||
send_msg(MSG_DELETED, fname, len);
|
||||
send_msg(MSG_DELETED, fname, len, am_generator);
|
||||
} else {
|
||||
fmt = stdout_format_has_o_or_i ? stdout_format : "deleting %n";
|
||||
log_formatted(FCLIENT, fmt, "del.", &file, &stats,
|
||||
log_formatted(FCLIENT, fmt, "del.", &x.file, fname, &stats,
|
||||
ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
@@ -748,7 +776,7 @@ void log_delete(char *fname, int mode)
|
||||
return;
|
||||
|
||||
fmt = logfile_format_has_o_or_i ? logfile_format : "deleting %n";
|
||||
log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL);
|
||||
log_formatted(FLOG, fmt, "del.", &x.file, fname, &stats, ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -764,7 +792,7 @@ void log_exit(int code, const char *file, int line)
|
||||
(double)stats.total_written,
|
||||
(double)stats.total_read,
|
||||
(double)stats.total_size);
|
||||
} else {
|
||||
} else if (am_server != 2) {
|
||||
const char *name;
|
||||
|
||||
name = rerr_name(code);
|
||||
|
||||
469
main.c
469
main.c
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,11 +17,12 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#include "io.h"
|
||||
#if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
@@ -34,9 +35,9 @@ extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int am_daemon;
|
||||
extern int inc_recurse;
|
||||
extern int blocking_io;
|
||||
extern int remove_source_files;
|
||||
extern int daemon_over_rsh;
|
||||
extern int need_messages_from_generator;
|
||||
extern int kluge_around_eof;
|
||||
extern int do_stats;
|
||||
@@ -47,7 +48,10 @@ extern int copy_dirlinks;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int protocol_version;
|
||||
extern int file_total;
|
||||
extern int recurse;
|
||||
extern int xfer_dirs;
|
||||
extern int protect_args;
|
||||
extern int relative_paths;
|
||||
extern int sanitize_paths;
|
||||
extern int curr_dir_depth;
|
||||
@@ -58,7 +62,6 @@ extern int whole_file;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int batch_fd;
|
||||
extern int batch_gen_fd;
|
||||
extern int filesfrom_fd;
|
||||
extern pid_t cleanup_child_pid;
|
||||
extern struct stats stats;
|
||||
@@ -68,13 +71,18 @@ extern char *basis_dir[];
|
||||
extern char *rsync_path;
|
||||
extern char *shell_cmd;
|
||||
extern char *batch_name;
|
||||
extern char *password_file;
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern struct file_list *first_flist;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send;
|
||||
#endif
|
||||
|
||||
int local_server = 0;
|
||||
int new_root_dir = 0;
|
||||
int daemon_over_rsh = 0;
|
||||
mode_t orig_umask = 0;
|
||||
struct file_list *the_file_list;
|
||||
int batch_gen_fd = -1;
|
||||
|
||||
/* There's probably never more than at most 2 outstanding child processes,
|
||||
* but set it higher, just in case. */
|
||||
@@ -103,7 +111,11 @@ static void show_malloc_stats(void);
|
||||
* 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 = waitpid(pid, status_ptr, flags);
|
||||
pid_t waited_pid;
|
||||
|
||||
do {
|
||||
waited_pid = waitpid(pid, status_ptr, flags);
|
||||
} while (waited_pid == -1 && errno == EINTR);
|
||||
|
||||
if (waited_pid == -1 && errno == ECHILD) {
|
||||
/* Status of requested child no longer available: check to
|
||||
@@ -185,12 +197,12 @@ static void handle_stats(int f)
|
||||
|
||||
if (am_server) {
|
||||
if (am_sender) {
|
||||
write_longint(f, total_read);
|
||||
write_longint(f, total_written);
|
||||
write_longint(f, stats.total_size);
|
||||
write_varlong30(f, total_read, 3);
|
||||
write_varlong30(f, total_written, 3);
|
||||
write_varlong30(f, stats.total_size, 3);
|
||||
if (protocol_version >= 29) {
|
||||
write_longint(f, stats.flist_buildtime);
|
||||
write_longint(f, stats.flist_xfertime);
|
||||
write_varlong30(f, stats.flist_buildtime, 3);
|
||||
write_varlong30(f, stats.flist_xfertime, 3);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -203,22 +215,22 @@ static void handle_stats(int f)
|
||||
else if (!am_sender) {
|
||||
/* Read the first two in opposite order because the meaning of
|
||||
* read/write swaps when switching from sender to receiver. */
|
||||
total_written = read_longint(f);
|
||||
total_read = read_longint(f);
|
||||
stats.total_size = read_longint(f);
|
||||
total_written = read_varlong30(f, 3);
|
||||
total_read = read_varlong30(f, 3);
|
||||
stats.total_size = read_varlong30(f, 3);
|
||||
if (protocol_version >= 29) {
|
||||
stats.flist_buildtime = read_longint(f);
|
||||
stats.flist_xfertime = read_longint(f);
|
||||
stats.flist_buildtime = read_varlong30(f, 3);
|
||||
stats.flist_xfertime = read_varlong30(f, 3);
|
||||
}
|
||||
} else if (write_batch) {
|
||||
/* The --read-batch process is going to be a client
|
||||
* receiver, so we need to give it the stats. */
|
||||
write_longint(batch_fd, total_read);
|
||||
write_longint(batch_fd, total_written);
|
||||
write_longint(batch_fd, stats.total_size);
|
||||
write_varlong30(batch_fd, total_read, 3);
|
||||
write_varlong30(batch_fd, total_written, 3);
|
||||
write_varlong30(batch_fd, stats.total_size, 3);
|
||||
if (protocol_version >= 29) {
|
||||
write_longint(batch_fd, stats.flist_buildtime);
|
||||
write_longint(batch_fd, stats.flist_xfertime);
|
||||
write_varlong30(batch_fd, stats.flist_buildtime, 3);
|
||||
write_varlong30(batch_fd, stats.flist_xfertime, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +250,8 @@ static void output_summary(void)
|
||||
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);
|
||||
rprintf(FINFO,"File list size: %s\n",
|
||||
human_num(stats.flist_size));
|
||||
if (stats.flist_buildtime) {
|
||||
rprintf(FINFO,
|
||||
"File list generation time: %.3f seconds\n",
|
||||
@@ -310,8 +323,8 @@ static void show_malloc_stats(void)
|
||||
|
||||
|
||||
/* Start the remote shell. cmd may be NULL to use the default. */
|
||||
static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
int *f_in, int *f_out)
|
||||
static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, int remote_argc,
|
||||
int *f_in_p, int *f_out_p)
|
||||
{
|
||||
int i, argc = 0;
|
||||
char *args[MAX_ARGS];
|
||||
@@ -334,10 +347,8 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
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);
|
||||
}
|
||||
if (argc >= MAX_ARGS - MAX_SERVER_ARGS)
|
||||
goto arg_overflow;
|
||||
args[argc++] = t;
|
||||
while (*f != ' ' || in_quote) {
|
||||
if (!*f) {
|
||||
@@ -401,16 +412,23 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
|
||||
server_options(args,&argc);
|
||||
|
||||
if (argc >= MAX_ARGS - 2) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (argc >= MAX_ARGS - 2)
|
||||
goto arg_overflow;
|
||||
}
|
||||
|
||||
args[argc++] = ".";
|
||||
|
||||
if (!daemon_over_rsh && path && *path)
|
||||
args[argc++] = path;
|
||||
if (!daemon_over_rsh) {
|
||||
while (remote_argc > 0) {
|
||||
if (argc >= MAX_ARGS - 1) {
|
||||
arg_overflow:
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
args[argc++] = *remote_argv++;
|
||||
remote_argc--;
|
||||
}
|
||||
}
|
||||
|
||||
args[argc] = NULL;
|
||||
|
||||
@@ -427,17 +445,63 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
batch_gen_fd = from_gen_pipe[0];
|
||||
*f_out = from_gen_pipe[1];
|
||||
*f_in = batch_fd;
|
||||
*f_out_p = from_gen_pipe[1];
|
||||
*f_in_p = batch_fd;
|
||||
ret = -1; /* no child pid */
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
} else if (local_server) {
|
||||
/* If the user didn't request --[no-]whole-file, force
|
||||
* it on, but only if we're not batch processing. */
|
||||
if (whole_file < 0 && !write_batch)
|
||||
whole_file = 1;
|
||||
ret = local_child(argc, args, f_in, f_out, child_main);
|
||||
} else
|
||||
ret = piped_child(args,f_in,f_out);
|
||||
ret = local_child(argc, args, f_in_p, f_out_p, child_main);
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
} else {
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
if (protect_args) {
|
||||
int fd;
|
||||
#ifdef ICONV_OPTION
|
||||
int convert = ic_send != (iconv_t)-1;
|
||||
xbuf outbuf, inbuf;
|
||||
|
||||
if (convert)
|
||||
alloc_xbuf(&outbuf, 1024);
|
||||
#endif
|
||||
|
||||
ret = piped_child(args, f_in_p, f_out_p);
|
||||
|
||||
for (i = 0; args[i]; i++) {} /* find first NULL */
|
||||
args[i] = "rsync"; /* set a new arg0 */
|
||||
if (verbose > 1)
|
||||
print_child_argv("protected args:", args + i + 1);
|
||||
fd = *f_out_p;
|
||||
do {
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert) {
|
||||
INIT_XBUF_STRLEN(inbuf, args[i]);
|
||||
iconvbufs(ic_send, &inbuf, &outbuf,
|
||||
ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
|
||||
outbuf.buf[outbuf.len] = '\0';
|
||||
write_buf(fd, outbuf.buf, outbuf.len + 1);
|
||||
outbuf.len = 0;
|
||||
} else
|
||||
#endif
|
||||
write_buf(fd, args[i], strlen(args[i]) + 1);
|
||||
} while (args[++i]);
|
||||
write_byte(fd, 0);
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert)
|
||||
free(outbuf.buf);
|
||||
#endif
|
||||
} else
|
||||
ret = piped_child(args, f_in_p, f_out_p);
|
||||
}
|
||||
|
||||
if (dir)
|
||||
free(dir);
|
||||
@@ -470,7 +534,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "get_local_name count=%d %s\n",
|
||||
flist->count, NS(dest_path));
|
||||
file_total, NS(dest_path));
|
||||
}
|
||||
|
||||
if (!dest_path || list_only)
|
||||
@@ -487,14 +551,13 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (flist->count > 1) {
|
||||
if (file_total > 1) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: destination must be a directory when"
|
||||
" copying more than 1 file\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
/* Caution: flist->count could be 0! */
|
||||
if (flist->count == 1 && S_ISDIR(flist->files[0]->mode)) {
|
||||
if (file_total == 1 && S_ISDIR(flist->files[0]->mode)) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: cannot overwrite non-directory"
|
||||
" with a directory\n");
|
||||
@@ -512,7 +575,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
/* If we need a destination directory because the transfer is not
|
||||
* of a single non-directory or the user has requested one via a
|
||||
* destination path ending in a slash, create one and use mode 1. */
|
||||
if (flist->count > 1 || (cp && !cp[1])) {
|
||||
if (file_total > 1 || (cp && !cp[1])) {
|
||||
/* Lop off the final slash (if any). */
|
||||
if (cp && !cp[1])
|
||||
*cp = '\0';
|
||||
@@ -529,7 +592,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
new_root_dir = 1;
|
||||
if (flist->high >= flist->low
|
||||
&& strcmp(flist->files[flist->low]->basename, ".") == 0)
|
||||
flist->files[0]->flags |= FLAG_DIR_CREATED;
|
||||
|
||||
if (verbose)
|
||||
rprintf(FINFO, "created directory %s\n", dest_path);
|
||||
@@ -603,29 +668,26 @@ static void fix_basis_dirs(void)
|
||||
}
|
||||
|
||||
/* This is only called by the sender. */
|
||||
static void read_final_goodbye(int f_in, int f_out)
|
||||
static void read_final_goodbye(int f_in)
|
||||
{
|
||||
int i;
|
||||
int i, iflags, xlen;
|
||||
uchar fnamecmp_type;
|
||||
char xname[MAXPATHLEN];
|
||||
|
||||
if (protocol_version < 29)
|
||||
i = read_int(f_in);
|
||||
else {
|
||||
while ((i = read_int(f_in)) == the_file_list->count
|
||||
&& read_shortint(f_in) == ITEM_IS_NEW) {
|
||||
/* Forward the keep-alive (no-op) to the receiver. */
|
||||
write_int(f_out, the_file_list->count);
|
||||
write_shortint(f_out, ITEM_IS_NEW);
|
||||
}
|
||||
i = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
}
|
||||
|
||||
if (i != -1) {
|
||||
if (i != NDX_DONE) {
|
||||
rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n",
|
||||
i, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
struct file_list *flist;
|
||||
@@ -666,25 +728,22 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
|
||||
}
|
||||
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
if (!flist || flist->count == 0) {
|
||||
if (!flist || flist->used == 0)
|
||||
exit_cleanup(0);
|
||||
}
|
||||
the_file_list = flist;
|
||||
|
||||
io_start_buffering_in();
|
||||
io_start_buffering_out();
|
||||
io_start_buffering_in(f_in);
|
||||
|
||||
send_files(flist,f_out,f_in);
|
||||
send_files(f_in, f_out);
|
||||
io_flush(FULL_FLUSH);
|
||||
handle_stats(f_out);
|
||||
if (protocol_version >= 24)
|
||||
read_final_goodbye(f_in, f_out);
|
||||
read_final_goodbye(f_in);
|
||||
io_flush(FULL_FLUSH);
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
|
||||
static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
static int do_recv(int f_in, int f_out, char *local_name)
|
||||
{
|
||||
int pid;
|
||||
int exit_code = 0;
|
||||
@@ -694,8 +753,10 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
* points to an identical file won't be replaced by the referent. */
|
||||
copy_links = copy_dirlinks = 0;
|
||||
|
||||
if (preserve_hard_links)
|
||||
init_hard_links();
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (preserve_hard_links && !inc_recurse)
|
||||
match_hard_links(first_flist);
|
||||
#endif
|
||||
|
||||
if (fd_pair(error_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe failed in do_recv");
|
||||
@@ -715,26 +776,32 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
close(f_out);
|
||||
|
||||
/* we can't let two processes write to the socket at one time */
|
||||
close_multiplexing_out();
|
||||
io_end_multiplex_out();
|
||||
|
||||
/* set place to send errors */
|
||||
set_msg_fd_out(error_pipe[1]);
|
||||
io_start_buffering_out(error_pipe[1]);
|
||||
|
||||
recv_files(f_in, flist, local_name);
|
||||
recv_files(f_in, local_name);
|
||||
io_flush(FULL_FLUSH);
|
||||
handle_stats(f_in);
|
||||
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
send_msg(MSG_DONE, "", 1, 0);
|
||||
write_varlong(error_pipe[1], stats.total_read, 3);
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
/* Handle any keep-alive packets from the post-processing work
|
||||
* that the generator does. */
|
||||
if (protocol_version >= 29) {
|
||||
int iflags, xlen;
|
||||
uchar fnamecmp_type;
|
||||
char xname[MAXPATHLEN];
|
||||
|
||||
kluge_around_eof = -1;
|
||||
|
||||
/* This should only get stopped via a USR2 signal. */
|
||||
while (read_int(f_in) == flist->count
|
||||
&& read_shortint(f_in) == ITEM_IS_NEW) {}
|
||||
read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
|
||||
rprintf(FERROR, "Invalid packet at end of run [%s]\n",
|
||||
who_am_i());
|
||||
@@ -749,7 +816,8 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
}
|
||||
|
||||
am_generator = 1;
|
||||
close_multiplexing_in();
|
||||
|
||||
io_end_multiplex_in();
|
||||
if (write_batch && !am_server)
|
||||
stop_write_batch();
|
||||
|
||||
@@ -757,17 +825,26 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
if (f_in != f_out)
|
||||
close(f_in);
|
||||
|
||||
io_start_buffering_out();
|
||||
io_start_buffering_out(f_out);
|
||||
|
||||
set_msg_fd_in(error_pipe[0]);
|
||||
io_start_buffering_in(error_pipe[0]);
|
||||
|
||||
generate_files(f_out, flist, local_name);
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (preserve_hard_links && inc_recurse) {
|
||||
struct file_list *flist;
|
||||
for (flist = first_flist; flist; flist = flist->next)
|
||||
match_hard_links(flist);
|
||||
}
|
||||
#endif
|
||||
|
||||
generate_files(f_out, local_name);
|
||||
|
||||
handle_stats(-1);
|
||||
io_flush(FULL_FLUSH);
|
||||
if (protocol_version >= 24) {
|
||||
/* send a final goodbye message */
|
||||
write_int(f_out, -1);
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
}
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
@@ -777,8 +854,7 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
||||
static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
int exit_code;
|
||||
struct file_list *flist;
|
||||
@@ -814,7 +890,10 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
io_start_buffering_in();
|
||||
if (protocol_version >= 30)
|
||||
io_start_multiplex_in();
|
||||
else
|
||||
io_start_buffering_in(f_in);
|
||||
recv_filter_list(f_in);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
@@ -828,12 +907,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
}
|
||||
|
||||
flist = recv_file_list(f_in);
|
||||
verbose = save_verbose;
|
||||
if (!flist) {
|
||||
rprintf(FERROR,"server_recv: recv_file_list error\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
the_file_list = flist;
|
||||
if (inc_recurse && file_total == 1)
|
||||
recv_additional_file_list(f_in);
|
||||
verbose = save_verbose;
|
||||
|
||||
if (argc > 0)
|
||||
local_name = get_local_name(flist,argv[0]);
|
||||
@@ -868,7 +948,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
exit_code = do_recv(f_in,f_out,flist,local_name);
|
||||
exit_code = do_recv(f_in, f_out, local_name);
|
||||
exit_cleanup(exit_code);
|
||||
}
|
||||
|
||||
@@ -887,9 +967,6 @@ 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();
|
||||
@@ -898,12 +975,10 @@ void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
if (need_messages_from_generator)
|
||||
io_start_multiplex_in();
|
||||
|
||||
recv_filter_list(f_in);
|
||||
do_server_sender(f_in, f_out, argc, argv);
|
||||
} else {
|
||||
} else
|
||||
do_server_recv(f_in, f_out, argc, argv);
|
||||
}
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
@@ -926,12 +1001,6 @@ 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();
|
||||
|
||||
/* We set our stderr file handle to blocking because ssh might have
|
||||
* set it to non-blocking. This can be particularly troublesome if
|
||||
@@ -945,7 +1014,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
|
||||
if (am_sender) {
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
io_start_buffering_out();
|
||||
if (protocol_version >= 30)
|
||||
io_start_multiplex_out();
|
||||
else
|
||||
io_start_buffering_out(f_out);
|
||||
if (!filesfrom_host)
|
||||
set_msg_fd_in(f_in);
|
||||
send_filter_list(f_out);
|
||||
@@ -958,14 +1030,16 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
set_msg_fd_in(-1);
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"file list sent\n");
|
||||
the_file_list = flist;
|
||||
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_in();
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
send_files(flist,f_out,f_in);
|
||||
send_files(f_in, f_out);
|
||||
io_flush(FULL_FLUSH);
|
||||
handle_stats(-1);
|
||||
if (protocol_version >= 24)
|
||||
read_final_goodbye(f_in, f_out);
|
||||
read_final_goodbye(f_in);
|
||||
if (pid != -1) {
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
|
||||
@@ -977,11 +1051,17 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
exit_cleanup(exit_code);
|
||||
}
|
||||
|
||||
if (need_messages_from_generator && !read_batch)
|
||||
io_start_multiplex_out();
|
||||
if (!read_batch) {
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_in();
|
||||
if (need_messages_from_generator)
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
if (argc == 0)
|
||||
if (argc == 0) {
|
||||
list_only |= 1;
|
||||
xfer_dirs |= 1;
|
||||
}
|
||||
|
||||
send_filter_list(read_batch ? -1 : f_out);
|
||||
|
||||
@@ -993,14 +1073,15 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (write_batch && !am_server)
|
||||
start_write_batch(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
the_file_list = flist;
|
||||
if (inc_recurse && file_total == 1)
|
||||
recv_additional_file_list(f_in);
|
||||
|
||||
if (flist && flist->count > 0) {
|
||||
if (flist && flist->used > 0) {
|
||||
local_name = get_local_name(flist, argv[0]);
|
||||
|
||||
fix_basis_dirs();
|
||||
|
||||
exit_code2 = do_recv(f_in, f_out, flist, local_name);
|
||||
exit_code2 = do_recv(f_in, f_out, local_name);
|
||||
} else {
|
||||
handle_stats(-1);
|
||||
output_summary();
|
||||
@@ -1016,7 +1097,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
return MAX(exit_code, exit_code2);
|
||||
}
|
||||
|
||||
static int copy_argv (char *argv[])
|
||||
static int copy_argv(char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1042,66 +1123,69 @@ static int copy_argv (char *argv[])
|
||||
**/
|
||||
static int start_client(int argc, char *argv[])
|
||||
{
|
||||
char *p;
|
||||
char *shell_machine = NULL;
|
||||
char *shell_path = NULL;
|
||||
char *shell_user = NULL;
|
||||
char *p, *shell_machine = NULL, *shell_user = NULL;
|
||||
char **remote_argv;
|
||||
int remote_argc;
|
||||
int f_in, f_out;
|
||||
int ret;
|
||||
pid_t pid;
|
||||
int f_in,f_out;
|
||||
int rc;
|
||||
|
||||
/* Don't clobber argv[] so that ps(1) can still show the right
|
||||
* command line. */
|
||||
if ((rc = copy_argv(argv)))
|
||||
return rc;
|
||||
if ((ret = copy_argv(argv)) != 0)
|
||||
return ret;
|
||||
|
||||
if (!read_batch) { /* for read_batch, NO source is specified */
|
||||
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)) {
|
||||
char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
|
||||
if (path) { /* source is remote */
|
||||
char *dummy_host;
|
||||
int dummy_port = 0;
|
||||
*argv = path;
|
||||
remote_argv = argv;
|
||||
remote_argc = argc;
|
||||
argv += argc - 1;
|
||||
if (argc == 1 || **argv == ':')
|
||||
argc = 0; /* no dest arg */
|
||||
else if (check_for_hostspec(*argv, &dummy_host, &dummy_port)) {
|
||||
rprintf(FERROR,
|
||||
"The source and destination cannot both be remote.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
} else {
|
||||
remote_argc--; /* don't count dest */
|
||||
argc = 1;
|
||||
}
|
||||
argv++;
|
||||
if (filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (rsync_port) {
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(shell_machine,
|
||||
shell_path,
|
||||
argc, argv);
|
||||
}
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
am_sender = 0;
|
||||
if (rsync_port)
|
||||
daemon_over_rsh = shell_cmd ? 1 : -1;
|
||||
} else { /* source is local, check dest arg */
|
||||
am_sender = 1;
|
||||
|
||||
if (argc > 1)
|
||||
if (argc > 1) {
|
||||
p = argv[--argc];
|
||||
else {
|
||||
p = ".";
|
||||
list_only = 1;
|
||||
remote_argv = argv + argc;
|
||||
} else {
|
||||
static char *dotarg[1] = { "." };
|
||||
p = dotarg[0];
|
||||
remote_argv = dotarg;
|
||||
list_only |= 1;
|
||||
xfer_dirs |= 1;
|
||||
}
|
||||
remote_argc = 1;
|
||||
|
||||
shell_path = check_for_hostspec(p, &shell_machine, &rsync_port);
|
||||
if (shell_path && filesfrom_host && *filesfrom_host
|
||||
path = check_for_hostspec(p, &shell_machine, &rsync_port);
|
||||
if (path && filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (!shell_path) { /* no hostspec found, so src & dest are local */
|
||||
if (!path) { /* no hostspec found, so src & dest are local */
|
||||
local_server = 1;
|
||||
if (filesfrom_host) {
|
||||
rprintf(FERROR,
|
||||
@@ -1109,23 +1193,72 @@ static int start_client(int argc, char *argv[])
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
shell_machine = NULL;
|
||||
shell_path = p;
|
||||
} else if (rsync_port) {
|
||||
if (!shell_cmd) {
|
||||
return start_socket_client(shell_machine,
|
||||
shell_path,
|
||||
argc, argv);
|
||||
}
|
||||
daemon_over_rsh = 1;
|
||||
} else { /* hostspec was found, so dest is remote */
|
||||
argv[argc] = path;
|
||||
if (rsync_port)
|
||||
daemon_over_rsh = shell_cmd ? 1 : -1;
|
||||
}
|
||||
}
|
||||
} else { /* read_batch */
|
||||
local_server = 1;
|
||||
shell_path = argv[argc-1];
|
||||
if (check_for_hostspec(shell_path, &shell_machine, &rsync_port)) {
|
||||
if (check_for_hostspec(argv[argc-1], &shell_machine, &rsync_port)) {
|
||||
rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
remote_argv = argv + argc - 1;
|
||||
remote_argc = 1;
|
||||
}
|
||||
|
||||
if (am_sender) {
|
||||
char *dummy_host;
|
||||
int dummy_port = rsync_port;
|
||||
int i;
|
||||
/* For local source, extra source args must not have hostspec. */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) {
|
||||
rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char *dummy_host;
|
||||
int dummy_port = rsync_port;
|
||||
int i;
|
||||
/* For remote source, any extra source args must have either
|
||||
* the same hostname or an empty hostname. */
|
||||
for (i = 1; i < remote_argc; i++) {
|
||||
char *arg = check_for_hostspec(remote_argv[i], &dummy_host, &dummy_port);
|
||||
if (!arg) {
|
||||
rprintf(FERROR, "Unexpected local arg: %s\n", remote_argv[i]);
|
||||
rprintf(FERROR, "If arg is a remote file/dir, prefix it with a colon (:).\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (*dummy_host && strcmp(dummy_host, shell_machine) != 0) {
|
||||
rprintf(FERROR, "All source args must come from the same machine.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (rsync_port != dummy_port) {
|
||||
if (!rsync_port || !dummy_port)
|
||||
rprintf(FERROR, "All source args must use the same hostspec format.\n");
|
||||
else
|
||||
rprintf(FERROR, "All source args must use the same port number.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
remote_argv[i] = arg;
|
||||
}
|
||||
if (argc == 0) {
|
||||
list_only |= 1;
|
||||
xfer_dirs |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon_over_rsh < 0)
|
||||
return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv);
|
||||
|
||||
if (password_file && !daemon_over_rsh) {
|
||||
rprintf(FERROR, "The --password-file option may only be "
|
||||
"used when accessing an rsync daemon.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (shell_machine) {
|
||||
@@ -1139,31 +1272,18 @@ static int start_client(int argc, char *argv[])
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
|
||||
shell_cmd ? shell_cmd : "",
|
||||
shell_machine ? shell_machine : "",
|
||||
shell_user ? shell_user : "",
|
||||
shell_path ? shell_path : "");
|
||||
NS(shell_cmd), NS(shell_machine), NS(shell_user),
|
||||
remote_argv ? NS(remote_argv[0]) : "");
|
||||
}
|
||||
|
||||
/* for remote source, only single dest arg can remain ... */
|
||||
if (!am_sender && argc > 1) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
/* ... or no dest at all */
|
||||
if (!am_sender && argc == 0)
|
||||
list_only |= 1;
|
||||
|
||||
pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,
|
||||
&f_in,&f_out);
|
||||
pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
|
||||
&f_in, &f_out);
|
||||
|
||||
/* if we're running an rsync server on the remote host over a
|
||||
* remote shell command, we need to do the RSYNCD protocol first */
|
||||
if (daemon_over_rsh) {
|
||||
int tmpret;
|
||||
tmpret = start_inband_exchange(shell_user, shell_path,
|
||||
f_in, f_out, argc);
|
||||
tmpret = start_inband_exchange(f_in, f_out, shell_user, remote_argc, remote_argv);
|
||||
if (tmpret < 0)
|
||||
return tmpret;
|
||||
}
|
||||
@@ -1358,13 +1478,30 @@ int main(int argc,char *argv[])
|
||||
}
|
||||
if (read_batch)
|
||||
read_stream_flags(batch_fd);
|
||||
else
|
||||
write_stream_flags(batch_fd);
|
||||
|
||||
}
|
||||
if (write_batch < 0)
|
||||
dry_run = 1;
|
||||
|
||||
if (am_daemon && !am_server)
|
||||
if (am_server) {
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
} else if (am_daemon)
|
||||
return daemon_main();
|
||||
|
||||
if (am_server && protect_args) {
|
||||
char buf[MAXPATHLEN];
|
||||
protect_args = 2;
|
||||
read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL);
|
||||
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
|
||||
option_error();
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
|
||||
56
match.c
56
match.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -85,7 +84,7 @@ static OFF_T last_match;
|
||||
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
OFF_T offset, int32 i)
|
||||
{
|
||||
int32 n = offset - last_match; /* max value: block_size (int32) */
|
||||
int32 n = (int32)(offset - last_match); /* max value: block_size (int32) */
|
||||
int32 j;
|
||||
|
||||
if (verbose > 2 && i >= 0) {
|
||||
@@ -121,8 +120,8 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
static void hash_search(int f,struct sum_struct *s,
|
||||
struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
OFF_T offset, end, backup;
|
||||
int32 k, want_i;
|
||||
OFF_T offset, end;
|
||||
int32 k, want_i, backup;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
@@ -254,7 +253,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
} while ((i = s->sums[i].chain) >= 0);
|
||||
|
||||
null_hash:
|
||||
backup = offset - last_match;
|
||||
backup = (int32)(offset - last_match);
|
||||
/* We sometimes read 1 byte prior to last_match... */
|
||||
if (backup < 0)
|
||||
backup = 0;
|
||||
@@ -304,7 +303,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
**/
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
char file_sum[MD4_SUM_LENGTH];
|
||||
char file_sum[MAX_DIGEST_LEN];
|
||||
int sum_len;
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
@@ -314,22 +314,24 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
|
||||
sum_init(checksum_seed);
|
||||
|
||||
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;
|
||||
if (append_mode > 0) {
|
||||
if (append_mode == 2) {
|
||||
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 n = (int32)(s->flength - last_match);
|
||||
if (buf && do_progress)
|
||||
show_progress(last_match, buf->file_size);
|
||||
sum_update(map_ptr(buf, last_match, n), n);
|
||||
}
|
||||
}
|
||||
last_match = s->flength;
|
||||
s->count = 0;
|
||||
}
|
||||
|
||||
@@ -339,7 +341,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"built hash table\n");
|
||||
|
||||
hash_search(f,s,buf,len);
|
||||
hash_search(f, s, buf, len);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"done hash search\n");
|
||||
@@ -351,14 +353,14 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
matched(f, s, buf, len, -1);
|
||||
}
|
||||
|
||||
sum_end(file_sum);
|
||||
sum_len = sum_end(file_sum);
|
||||
/* If we had a read error, send a bad checksum. */
|
||||
if (buf && buf->status != 0)
|
||||
file_sum[0]++;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f,file_sum,MD4_SUM_LENGTH);
|
||||
write_buf(f, file_sum, sum_len);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
|
||||
|
||||
66
mkrounding.c
Normal file
66
mkrounding.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* A pre-compilation helper program to aid in the creation of rounding.h.
|
||||
*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
struct test1 {
|
||||
union file_extras extras1[1];
|
||||
struct {
|
||||
# include "mkrounding.h"
|
||||
} file;
|
||||
};
|
||||
|
||||
struct test2 {
|
||||
union file_extras extras2[2];
|
||||
struct {
|
||||
# include "mkrounding.h"
|
||||
} file;
|
||||
};
|
||||
|
||||
struct test4 {
|
||||
union file_extras extras4[4];
|
||||
struct {
|
||||
# include "mkrounding.h"
|
||||
} file;
|
||||
};
|
||||
|
||||
#define SIZE_TEST(n) (sizeof (struct test ## n) == EXTRA_LEN * n + sizeof (struct file_struct))
|
||||
|
||||
int main(UNUSED(int argc), UNUSED(char *argv[]))
|
||||
{
|
||||
int cnt;
|
||||
if (SIZE_TEST(1))
|
||||
cnt = 0;
|
||||
else if (SIZE_TEST(2))
|
||||
cnt = 1;
|
||||
else if (SIZE_TEST(4))
|
||||
cnt = 3;
|
||||
else {
|
||||
fprintf(stderr, "Unable to determine required file_extras rounding!\n");
|
||||
cnt = 3;
|
||||
}
|
||||
if (cnt)
|
||||
fprintf(stderr, "Rounding file_extras in multiples of %d", cnt + 1);
|
||||
else
|
||||
fprintf(stderr, "No rounding needed for file_extras");
|
||||
fprintf(stderr, " (EXTRA_LEN=%d, FILE_STRUCT_LEN=%d)\n",
|
||||
(int)EXTRA_LEN, (int)FILE_STRUCT_LEN);
|
||||
printf("#define EXTRA_ROUNDING %d\n", cnt);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
Summary: A program for synchronizing files over a network.
|
||||
Name: rsync
|
||||
Version: 2.6.9
|
||||
Version: 3.0.0pre2
|
||||
Release: 1
|
||||
Group: Applications/Internet
|
||||
Source: ftp://rsync.samba.org/pub/rsync/rsync-%{version}.tar.gz
|
||||
|
||||
@@ -96,7 +96,15 @@ foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) {
|
||||
unlink($fn);
|
||||
}
|
||||
|
||||
system "find . -name 'rsync-HEAD-*' -daystart -mtime +14 | xargs rm -f";
|
||||
my $cnt = 0;
|
||||
open(PIPE, '-|', 'ls -1t rsync-HEAD-*') or die $!;
|
||||
while (<PIPE>) {
|
||||
chomp;
|
||||
next if $cnt++ < 10;
|
||||
unlink($_);
|
||||
}
|
||||
close PIPE;
|
||||
|
||||
system 'ls -ltr';
|
||||
|
||||
if ($upload) {
|
||||
|
||||
@@ -67,7 +67,7 @@ while (<CVS>) {
|
||||
chdir('rsync') or die $!;
|
||||
|
||||
my($version, $lastversion);
|
||||
open(IN, 'configure.in') or die $!;
|
||||
open(IN, '<', 'configure.in') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$version = $lastversion = $1;
|
||||
@@ -76,7 +76,13 @@ while (<IN>) {
|
||||
}
|
||||
close IN;
|
||||
|
||||
$lastversion =~ s/(\d+)cvs$/ $1 - 1 /e;
|
||||
if ($lastversion =~ /cvs$/) {
|
||||
open(IN, '<', 'OLDNEWS') or die $!;
|
||||
$_ = <IN>;
|
||||
close IN;
|
||||
($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
}
|
||||
|
||||
$version =~ s/cvs/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
|
||||
|
||||
print $break, "\nPlease enter the version number of this release: [$version] ";
|
||||
@@ -130,8 +136,9 @@ print "\n", $break, <<EOT;
|
||||
\$release is "$release"
|
||||
|
||||
About to:
|
||||
- make sure that configure, config.h.in, and proto.h are updated
|
||||
- make sure that SUBPROTOCOL_VERSION is 0$skipping2
|
||||
- tweak the version in configure.in, configure, and the spec files
|
||||
- make sure that configure, config.h.in, and proto.h are updated
|
||||
- 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
|
||||
@@ -148,7 +155,7 @@ 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 ));
|
||||
push(@tweak_files, qw( rsync.h NEWS OLDNEWS ));
|
||||
}
|
||||
foreach my $fn (@tweak_files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
@@ -165,6 +172,8 @@ foreach my $fn (@tweak_files) {
|
||||
} elsif ($fn eq 'NEWS') {
|
||||
s/^(NEWS for rsync \Q$version\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/mi
|
||||
or die "Couldn't update NEWS file with release date!\n";
|
||||
} elsif ($fn eq 'rsync.h') {
|
||||
s/(#define\s+SUBPROTOCOL_VERSION)\s+\d+/$1 0/;
|
||||
} elsif ($fn eq 'OLDNEWS') {
|
||||
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$version\E)/\t$ztoday$1/m
|
||||
or die "Couldn't update OLDNEWS file with release date!\n";
|
||||
@@ -176,8 +185,8 @@ foreach my $fn (@tweak_files) {
|
||||
close OUT;
|
||||
}
|
||||
|
||||
system "yodl2man -o rsync.1 rsync.yo; ./tweak_manpage_dashes rsync.1";
|
||||
system "yodl2man -o rsyncd.conf.5 rsyncd.conf.yo; ./tweak_manpage_dashes rsyncd.conf.5";
|
||||
system "yodl2man -o rsync.1 rsync.yo; ./tweak_manpage rsync.1";
|
||||
system "yodl2man -o rsyncd.conf.5 rsyncd.conf.yo; ./tweak_manpage rsyncd.conf.5";
|
||||
|
||||
mkdir('patches/tmp') or die $!;
|
||||
system "rsync -a --exclude=patches/ --exclude-from=.cvsignore . patches/tmp/cvsdir/";
|
||||
|
||||
10
params.c
10
params.c
@@ -4,7 +4,7 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -13,8 +13,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
@@ -75,6 +74,7 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Constants...
|
||||
@@ -165,7 +165,7 @@ static int Continuation( char *line, int pos )
|
||||
*/
|
||||
{
|
||||
pos--;
|
||||
while( (pos >= 0) && isspace(((unsigned char *)line)[pos]) )
|
||||
while( pos >= 0 && isSpace(line + pos) )
|
||||
pos--;
|
||||
|
||||
return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
|
||||
@@ -387,7 +387,7 @@ static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
|
||||
c = 0;
|
||||
else
|
||||
{
|
||||
for( end = i; (end >= 0) && isspace(((unsigned char *) bufr)[end]); end-- )
|
||||
for( end = i; end >= 0 && isSpace(bufr + end); end-- )
|
||||
;
|
||||
c = getc( InFile );
|
||||
}
|
||||
|
||||
15
pipe.c
15
pipe.c
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -50,9 +49,8 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
|
||||
if (verbose >= 2) {
|
||||
print_child_argv(command);
|
||||
}
|
||||
if (verbose >= 2)
|
||||
print_child_argv("opening connection using:", command);
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
@@ -146,6 +144,9 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO)
|
||||
close(from_child_pipe[1]);
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
* \file popt/findme.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "findme.h"
|
||||
|
||||
const char * findProgramPath(const char * argv0) {
|
||||
const char * findProgramPath(const char * argv0)
|
||||
{
|
||||
char * path = getenv("PATH");
|
||||
char * pathbuf;
|
||||
char * start, * chptr;
|
||||
char * buf;
|
||||
size_t bufsize;
|
||||
|
||||
if (argv0 == NULL) return NULL; /* XXX can't happen */
|
||||
/* If there is a / in the argv[0], it has to be an absolute path */
|
||||
@@ -22,17 +24,20 @@ const char * findProgramPath(const char * argv0) {
|
||||
|
||||
if (path == NULL) return NULL;
|
||||
|
||||
start = pathbuf = alloca(strlen(path) + 1);
|
||||
buf = malloc(strlen(path) + strlen(argv0) + sizeof("/"));
|
||||
bufsize = strlen(path) + 1;
|
||||
start = pathbuf = alloca(bufsize);
|
||||
if (pathbuf == NULL) return NULL; /* XXX can't happen */
|
||||
strlcpy(pathbuf, path, bufsize);
|
||||
bufsize += sizeof "/" - 1 + strlen(argv0);
|
||||
buf = malloc(bufsize);
|
||||
if (buf == NULL) return NULL; /* XXX can't happen */
|
||||
strcpy(pathbuf, path);
|
||||
|
||||
chptr = NULL;
|
||||
/*@-branchstate@*/
|
||||
do {
|
||||
if ((chptr = strchr(start, ':')))
|
||||
*chptr = '\0';
|
||||
sprintf(buf, "%s/%s", start, argv0);
|
||||
snprintf(buf, bufsize, "%s/%s", start, argv0);
|
||||
|
||||
if (!access(buf, X_OK))
|
||||
return buf;
|
||||
|
||||
205
popt/popt.c
205
popt/popt.c
@@ -2,7 +2,7 @@
|
||||
* \file popt/popt.c
|
||||
*/
|
||||
|
||||
/* (C) 19982000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist */
|
||||
|
||||
@@ -18,8 +18,18 @@
|
||||
#include "findme.h"
|
||||
#include "poptint.h"
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
static char * strerror(int errno) {
|
||||
#ifndef DBL_EPSILON
|
||||
#define DBL_EPSILON 2.2204460492503131e-16
|
||||
#endif
|
||||
|
||||
#ifdef MYDEBUG
|
||||
/*@unchecked@*/
|
||||
int _popt_debug = 0;
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_STRERROR) && !defined(__LCLINT__)
|
||||
static char * strerror(int errno)
|
||||
{
|
||||
extern int sys_nerr;
|
||||
extern char * sys_errlist[];
|
||||
|
||||
@@ -31,7 +41,8 @@ static char * strerror(int errno) {
|
||||
#endif
|
||||
|
||||
#ifdef MYDEBUG
|
||||
/*@unused@*/ static void prtcon(const char *msg, poptContext con)
|
||||
/*@unused@*/
|
||||
static void prtcon(const char *msg, poptContext con)
|
||||
{
|
||||
if (msg) fprintf(stderr, "%s", msg);
|
||||
fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n",
|
||||
@@ -49,7 +60,7 @@ void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
|
||||
con->execPath = _free(con->execPath);
|
||||
con->execPath = xstrdup(path);
|
||||
con->execAbsolute = allowAbsolute;
|
||||
/*@-nullstate@*/ /* LCL: con->execPath can be NULL? */
|
||||
/*@-nullstate@*/ /* LCL: con->execPath not NULL */
|
||||
return;
|
||||
/*@=nullstate@*/
|
||||
}
|
||||
@@ -62,17 +73,22 @@ static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
|
||||
for (; opt->longName || opt->shortName || opt->arg; opt++) {
|
||||
if (opt->arg == NULL) continue; /* XXX program error. */
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
void * arg = opt->arg;
|
||||
/*@-branchstate@*/
|
||||
/* XXX sick hack to preserve pretense of ABI. */
|
||||
if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
|
||||
/*@=branchstate@*/
|
||||
/* Recurse on included sub-tables. */
|
||||
invokeCallbacksPRE(con, opt->arg);
|
||||
invokeCallbacksPRE(con, arg);
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
|
||||
(opt->argInfo & POPT_CBFLAG_PRE))
|
||||
{ /*@-castfcnptr@*/
|
||||
poptCallbackType cb = (poptCallbackType)opt->arg;
|
||||
/*@=castfcnptr@*/
|
||||
/* Perform callback. */
|
||||
/*@-moduncon -noeffectuncon @*/
|
||||
/*@-noeffectuncon @*/
|
||||
cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
|
||||
/*@=moduncon =noeffectuncon @*/
|
||||
/*@=noeffectuncon @*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,17 +101,22 @@ static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt)
|
||||
for (; opt->longName || opt->shortName || opt->arg; opt++) {
|
||||
if (opt->arg == NULL) continue; /* XXX program error. */
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
void * arg = opt->arg;
|
||||
/*@-branchstate@*/
|
||||
/* XXX sick hack to preserve pretense of ABI. */
|
||||
if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
|
||||
/*@=branchstate@*/
|
||||
/* Recurse on included sub-tables. */
|
||||
invokeCallbacksPOST(con, opt->arg);
|
||||
invokeCallbacksPOST(con, arg);
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
|
||||
(opt->argInfo & POPT_CBFLAG_POST))
|
||||
{ /*@-castfcnptr@*/
|
||||
poptCallbackType cb = (poptCallbackType)opt->arg;
|
||||
/*@=castfcnptr@*/
|
||||
/* Perform callback. */
|
||||
/*@-moduncon -noeffectuncon @*/
|
||||
/*@-noeffectuncon @*/
|
||||
cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
|
||||
/*@=moduncon =noeffectuncon @*/
|
||||
/*@=noeffectuncon @*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,6 +133,11 @@ static void invokeCallbacksOPTION(poptContext con,
|
||||
if (opt != NULL)
|
||||
for (; opt->longName || opt->shortName || opt->arg; opt++) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
void * arg = opt->arg;
|
||||
/*@-branchstate@*/
|
||||
/* XXX sick hack to preserve pretense of ABI. */
|
||||
if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
|
||||
/*@=branchstate@*/
|
||||
/* Recurse on included sub-tables. */
|
||||
if (opt->arg != NULL) /* XXX program error */
|
||||
invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty);
|
||||
@@ -133,10 +159,10 @@ static void invokeCallbacksOPTION(poptContext con,
|
||||
const void * cbData = (cbopt->descrip ? cbopt->descrip : myData);
|
||||
/* Perform callback. */
|
||||
if (cb != NULL) { /* XXX program error */
|
||||
/*@-moduncon -noeffectuncon @*/
|
||||
/*@-noeffectuncon @*/
|
||||
cb(con, POPT_CALLBACK_REASON_OPTION, myOpt,
|
||||
con->os->nextArg, cbData);
|
||||
/*@=moduncon =noeffectuncon @*/
|
||||
/*@=noeffectuncon @*/
|
||||
}
|
||||
/* Terminate (unless explcitly continuing). */
|
||||
if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE))
|
||||
@@ -181,8 +207,12 @@ poptContext poptGetContext(const char * name, int argc, const char ** argv,
|
||||
con->flags |= POPT_CONTEXT_POSIXMEHARDER;
|
||||
|
||||
if (name) {
|
||||
char * t = malloc(strlen(name) + 1);
|
||||
if (t) con->appName = strcpy(t, name);
|
||||
size_t bufsize = strlen(name) + 1;
|
||||
char * t = malloc(bufsize);
|
||||
if (t) {
|
||||
strlcpy(t, name, bufsize);
|
||||
con->appName = t;
|
||||
}
|
||||
}
|
||||
|
||||
/*@-internalglobs@*/
|
||||
@@ -202,6 +232,7 @@ static void cleanOSE(/*@special@*/ struct optionStackEntry *os)
|
||||
os->argb = PBM_FREE(os->argb);
|
||||
}
|
||||
|
||||
/*@-boundswrite@*/
|
||||
void poptResetContext(poptContext con)
|
||||
{
|
||||
int i;
|
||||
@@ -222,10 +253,11 @@ void poptResetContext(poptContext con)
|
||||
con->doExec = NULL;
|
||||
|
||||
if (con->finalArgv != NULL)
|
||||
for (i = 0; i < con->finalArgvCount; i++)
|
||||
for (i = 0; i < con->finalArgvCount; i++) {
|
||||
/*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */
|
||||
con->finalArgv[i] = _free(con->finalArgv[i]);
|
||||
/*@=unqualifiedtrans@*/
|
||||
}
|
||||
|
||||
con->finalArgvCount = 0;
|
||||
con->arg_strip = PBM_FREE(con->arg_strip);
|
||||
@@ -233,8 +265,10 @@ void poptResetContext(poptContext con)
|
||||
return;
|
||||
/*@=nullstate@*/
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
/* Only one of longName, shortName should be set, not both. */
|
||||
/*@-boundswrite@*/
|
||||
static int handleExec(/*@special@*/ poptContext con,
|
||||
/*@null@*/ const char * longName, char shortName)
|
||||
/*@uses con->execs, con->numExecs, con->flags, con->doExec,
|
||||
@@ -277,12 +311,13 @@ static int handleExec(/*@special@*/ poptContext con,
|
||||
|
||||
i = con->finalArgvCount++;
|
||||
if (con->finalArgv != NULL) /* XXX can't happen */
|
||||
{ char *s = malloc((longName ? strlen(longName) : 0) + 3);
|
||||
{ size_t bufsize = (longName ? strlen(longName) : 0) + 3;
|
||||
char *s = malloc(bufsize);
|
||||
if (s != NULL) { /* XXX can't happen */
|
||||
if (longName)
|
||||
sprintf(s, "--%s", longName);
|
||||
snprintf(s, bufsize, "--%s", longName);
|
||||
else
|
||||
sprintf(s, "-%c", shortName);
|
||||
snprintf(s, bufsize, "-%c", shortName);
|
||||
con->finalArgv[i] = s;
|
||||
} else
|
||||
con->finalArgv[i] = NULL;
|
||||
@@ -292,11 +327,12 @@ static int handleExec(/*@special@*/ poptContext con,
|
||||
return 1;
|
||||
/*@=nullstate@*/
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
/* Only one of longName, shortName may be set at a time */
|
||||
static int handleAlias(/*@special@*/ poptContext con,
|
||||
/*@null@*/ const char * longName, char shortName,
|
||||
/*@keep@*/ /*@null@*/ const char * nextCharArg)
|
||||
/*@exposed@*/ /*@null@*/ const char * nextCharArg)
|
||||
/*@uses con->aliases, con->numAliases, con->optionStack, con->os,
|
||||
con->os->currAlias, con->os->currAlias->option.longName @*/
|
||||
/*@modifies con @*/
|
||||
@@ -330,8 +366,10 @@ static int handleAlias(/*@special@*/ poptContext con,
|
||||
if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
|
||||
return POPT_ERROR_OPTSTOODEEP;
|
||||
|
||||
/*@-boundsread@*/
|
||||
if (nextCharArg && *nextCharArg)
|
||||
con->os->nextCharArg = nextCharArg;
|
||||
/*@=boundsread@*/
|
||||
|
||||
con->os++;
|
||||
con->os->next = 0;
|
||||
@@ -346,13 +384,14 @@ static int handleAlias(/*@special@*/ poptContext con,
|
||||
return (rc ? rc : 1);
|
||||
}
|
||||
|
||||
/*@-bounds -boundswrite @*/
|
||||
static int execCommand(poptContext con)
|
||||
/*@*/
|
||||
/*@globals internalState @*/
|
||||
/*@modifies internalState @*/
|
||||
{
|
||||
poptItem item = con->doExec;
|
||||
const char ** argv;
|
||||
int argc = 0;
|
||||
int rc;
|
||||
|
||||
if (item == NULL) /*XXX can't happen*/
|
||||
return POPT_ERROR_NOARG;
|
||||
@@ -363,15 +402,15 @@ static int execCommand(poptContext con)
|
||||
|
||||
argv = malloc(sizeof(*argv) *
|
||||
(6 + item->argc + con->numLeftovers + con->finalArgvCount));
|
||||
if (argv == NULL) return POPT_ERROR_MALLOC; /* XXX can't happen */
|
||||
if (argv == NULL) return POPT_ERROR_MALLOC;
|
||||
|
||||
if (!strchr(item->argv[0], '/') && con->execPath) {
|
||||
char *s = alloca(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
|
||||
sprintf(s, "%s/%s", con->execPath, item->argv[0]);
|
||||
if (!strchr(item->argv[0], '/') && con->execPath != NULL) {
|
||||
size_t bufsize = strlen(con->execPath) + strlen(item->argv[0]) + sizeof "/";
|
||||
char *s = alloca(bufsize);
|
||||
snprintf(s, bufsize, "%s/%s", con->execPath, item->argv[0]);
|
||||
argv[argc] = s;
|
||||
} else {
|
||||
} else
|
||||
argv[argc] = findProgramPath(item->argv[0]);
|
||||
}
|
||||
if (argv[argc++] == NULL) return POPT_ERROR_NOARG;
|
||||
|
||||
if (item->argc > 1) {
|
||||
@@ -386,16 +425,16 @@ static int execCommand(poptContext con)
|
||||
}
|
||||
|
||||
if (con->leftovers != NULL && con->numLeftovers > 0) {
|
||||
#if 0
|
||||
argv[argc++] = "--";
|
||||
#endif
|
||||
memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers);
|
||||
argc += con->numLeftovers;
|
||||
}
|
||||
|
||||
argv[argc] = NULL;
|
||||
|
||||
{
|
||||
#ifdef __hpux
|
||||
int rc = setresgid(getgid(), getgid(),-1);
|
||||
if (rc) return POPT_ERROR_ERRNO;
|
||||
rc = setresuid(getuid(), getuid(),-1);
|
||||
if (rc) return POPT_ERROR_ERRNO;
|
||||
#else
|
||||
@@ -405,19 +444,26 @@ static int execCommand(poptContext con)
|
||||
* XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
|
||||
*/
|
||||
#if defined(HAVE_SETUID)
|
||||
int rc = setgid(getgid());
|
||||
if (rc) return POPT_ERROR_ERRNO;
|
||||
rc = setuid(getuid());
|
||||
if (rc) return POPT_ERROR_ERRNO;
|
||||
#elif defined (HAVE_SETREUID)
|
||||
rc = setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
|
||||
int rc = setregid(getgid(), getgid());
|
||||
if (rc) return POPT_ERROR_ERRNO;
|
||||
rc = setreuid(getuid(), getuid());
|
||||
if (rc) return POPT_ERROR_ERRNO;
|
||||
#else
|
||||
; /* Can't drop privileges */
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (argv[0] == NULL)
|
||||
return POPT_ERROR_NOARG;
|
||||
#ifdef MYDEBUG
|
||||
|
||||
#ifdef MYDEBUG
|
||||
if (_popt_debug)
|
||||
{ const char ** avp;
|
||||
fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc);
|
||||
for (avp = argv; *avp; avp++)
|
||||
@@ -426,10 +472,13 @@ static int execCommand(poptContext con)
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = execvp(argv[0], (char *const *)argv);
|
||||
execvp(argv[0], (char *const *)argv);
|
||||
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
/*@=bounds =boundswrite @*/
|
||||
|
||||
/*@-boundswrite@*/
|
||||
/*@observer@*/ /*@null@*/ static const struct poptOption *
|
||||
findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
|
||||
char shortName,
|
||||
@@ -448,10 +497,15 @@ findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
|
||||
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
const struct poptOption * opt2;
|
||||
void * arg = opt->arg;
|
||||
|
||||
/*@-branchstate@*/
|
||||
/* XXX sick hack to preserve pretense of ABI. */
|
||||
if (arg == poptHelpOptions) arg = poptHelpOptionsI18N;
|
||||
/*@=branchstate@*/
|
||||
/* Recurse on included sub-tables. */
|
||||
if (opt->arg == NULL) continue; /* XXX program error */
|
||||
opt2 = findOption(opt->arg, longName, shortName, callback,
|
||||
if (arg == NULL) continue; /* XXX program error */
|
||||
opt2 = findOption(arg, longName, shortName, callback,
|
||||
callbackData, singleDash);
|
||||
if (opt2 == NULL) continue;
|
||||
/* Sub-table data will be inheirited if no data yet. */
|
||||
@@ -496,6 +550,7 @@ findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
|
||||
|
||||
return opt;
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
static const char * findNextArg(/*@special@*/ poptContext con,
|
||||
unsigned argx, int delete_arg)
|
||||
@@ -534,6 +589,7 @@ static const char * findNextArg(/*@special@*/ poptContext con,
|
||||
return arg;
|
||||
}
|
||||
|
||||
/*@-boundswrite@*/
|
||||
static /*@only@*/ /*@null@*/ const char *
|
||||
expandNextArg(/*@special@*/ poptContext con, const char * s)
|
||||
/*@uses con->optionStack, con->os,
|
||||
@@ -541,7 +597,7 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
|
||||
/*@modifies con @*/
|
||||
{
|
||||
const char * a = NULL;
|
||||
size_t alen;
|
||||
size_t alen, pos;
|
||||
char *t, *te;
|
||||
size_t tn = strlen(s) + 1;
|
||||
char c;
|
||||
@@ -567,9 +623,9 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
|
||||
|
||||
alen = strlen(a);
|
||||
tn += alen;
|
||||
*te = '\0';
|
||||
pos = te - t;
|
||||
t = realloc(t, tn);
|
||||
te = t + strlen(t);
|
||||
te = t + pos;
|
||||
strncpy(te, a, alen); te += alen;
|
||||
continue;
|
||||
/*@notreached@*/ /*@switchbreak@*/ break;
|
||||
@@ -582,6 +638,7 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
|
||||
t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */
|
||||
return t;
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
static void poptStripArg(/*@special@*/ poptContext con, int which)
|
||||
/*@uses con->arg_strip, con->optionStack @*/
|
||||
@@ -599,26 +656,26 @@ static void poptStripArg(/*@special@*/ poptContext con, int which)
|
||||
/*@=compdef@*/
|
||||
}
|
||||
|
||||
static int poptSaveLong(const struct poptOption * opt, long aLong)
|
||||
/*@modifies opt->arg @*/
|
||||
int poptSaveLong(long * arg, int argInfo, long aLong)
|
||||
{
|
||||
if (opt->arg == NULL)
|
||||
/* XXX Check alignment, may fail on funky platforms. */
|
||||
if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
|
||||
return POPT_ERROR_NULLARG;
|
||||
|
||||
if (opt->argInfo & POPT_ARGFLAG_NOT)
|
||||
if (argInfo & POPT_ARGFLAG_NOT)
|
||||
aLong = ~aLong;
|
||||
switch (opt->argInfo & POPT_ARGFLAG_LOGICALOPS) {
|
||||
switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
|
||||
case 0:
|
||||
*((long *) opt->arg) = aLong;
|
||||
*arg = aLong;
|
||||
break;
|
||||
case POPT_ARGFLAG_OR:
|
||||
*((long *) opt->arg) |= aLong;
|
||||
*arg |= aLong;
|
||||
break;
|
||||
case POPT_ARGFLAG_AND:
|
||||
*((long *) opt->arg) &= aLong;
|
||||
*arg &= aLong;
|
||||
break;
|
||||
case POPT_ARGFLAG_XOR:
|
||||
*((long *) opt->arg) ^= aLong;
|
||||
*arg ^= aLong;
|
||||
break;
|
||||
default:
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
@@ -627,26 +684,26 @@ static int poptSaveLong(const struct poptOption * opt, long aLong)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poptSaveInt(const struct poptOption * opt, long aLong)
|
||||
/*@modifies opt->arg @*/
|
||||
int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
|
||||
{
|
||||
if (opt->arg == NULL)
|
||||
/* XXX Check alignment, may fail on funky platforms. */
|
||||
if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
|
||||
return POPT_ERROR_NULLARG;
|
||||
|
||||
if (opt->argInfo & POPT_ARGFLAG_NOT)
|
||||
if (argInfo & POPT_ARGFLAG_NOT)
|
||||
aLong = ~aLong;
|
||||
switch (opt->argInfo & POPT_ARGFLAG_LOGICALOPS) {
|
||||
switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
|
||||
case 0:
|
||||
*((int *) opt->arg) = aLong;
|
||||
*arg = aLong;
|
||||
break;
|
||||
case POPT_ARGFLAG_OR:
|
||||
*((int *) opt->arg) |= aLong;
|
||||
*arg |= aLong;
|
||||
break;
|
||||
case POPT_ARGFLAG_AND:
|
||||
*((int *) opt->arg) &= aLong;
|
||||
*arg &= aLong;
|
||||
break;
|
||||
case POPT_ARGFLAG_XOR:
|
||||
*((int *) opt->arg) ^= aLong;
|
||||
*arg ^= aLong;
|
||||
break;
|
||||
default:
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
@@ -655,6 +712,7 @@ static int poptSaveInt(const struct poptOption * opt, long aLong)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@-boundswrite@*/
|
||||
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
|
||||
int poptGetNextOpt(poptContext con)
|
||||
{
|
||||
@@ -714,8 +772,12 @@ int poptGetNextOpt(poptContext con)
|
||||
}
|
||||
|
||||
/* Make a copy we can hack at */
|
||||
localOptString = optString =
|
||||
strcpy(alloca(strlen(origOptString) + 1), origOptString);
|
||||
{ size_t bufsize = strlen(origOptString) + 1;
|
||||
localOptString = optString = alloca(bufsize);
|
||||
if (optString == NULL) /* XXX can't happen */
|
||||
return POPT_ERROR_BADOPT;
|
||||
strlcpy(optString, origOptString, bufsize);
|
||||
}
|
||||
|
||||
if (optString[0] == '\0')
|
||||
return POPT_ERROR_BADOPT;
|
||||
@@ -800,11 +862,11 @@ int poptGetNextOpt(poptContext con)
|
||||
|
||||
if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */
|
||||
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
|
||||
if (poptSaveInt(opt, 1L))
|
||||
if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L))
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
|
||||
if (opt->arg) {
|
||||
if (poptSaveInt(opt, (long)opt->val))
|
||||
if (poptSaveInt((int *)opt->arg, opt->argInfo, (long)opt->val))
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
}
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
|
||||
@@ -873,12 +935,12 @@ int poptGetNextOpt(poptContext con)
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
|
||||
if (aLong == LONG_MIN || aLong == LONG_MAX)
|
||||
return POPT_ERROR_OVERFLOW;
|
||||
if (poptSaveLong(opt, aLong))
|
||||
if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong))
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
} else {
|
||||
if (aLong > INT_MAX || aLong < INT_MIN)
|
||||
return POPT_ERROR_OVERFLOW;
|
||||
if (poptSaveInt(opt, aLong))
|
||||
if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong))
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
}
|
||||
} /*@switchbreak@*/ break;
|
||||
@@ -904,9 +966,6 @@ int poptGetNextOpt(poptContext con)
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) {
|
||||
*((double *) opt->arg) = aDouble;
|
||||
} else {
|
||||
#ifndef DBL_EPSILON
|
||||
#define DBL_EPSILON 2.2204460492503131e-16
|
||||
#endif
|
||||
#define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
|
||||
if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
|
||||
return POPT_ERROR_OVERFLOW;
|
||||
@@ -939,14 +998,15 @@ int poptGetNextOpt(poptContext con)
|
||||
}
|
||||
|
||||
if (con->finalArgv != NULL)
|
||||
{ char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
|
||||
{ ssize_t bufsize = (opt->longName ? strlen(opt->longName) : 0) + 3;
|
||||
char *s = malloc(bufsize);
|
||||
if (s != NULL) { /* XXX can't happen */
|
||||
if (opt->longName)
|
||||
sprintf(s, "%s%s",
|
||||
snprintf(s, bufsize, "%s%s",
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
else
|
||||
sprintf(s, "-%c", opt->shortName);
|
||||
snprintf(s, bufsize, "-%c", opt->shortName);
|
||||
con->finalArgv[con->finalArgvCount++] = s;
|
||||
} else
|
||||
con->finalArgv[con->finalArgvCount++] = NULL;
|
||||
@@ -967,6 +1027,7 @@ int poptGetNextOpt(poptContext con)
|
||||
|
||||
return (opt ? opt->val : -1); /* XXX can't happen */
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
const char * poptGetOptArg(poptContext con)
|
||||
{
|
||||
@@ -996,6 +1057,7 @@ const char * poptPeekArg(poptContext con)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*@-boundswrite@*/
|
||||
const char ** poptGetArgs(poptContext con)
|
||||
{
|
||||
if (con == NULL ||
|
||||
@@ -1009,6 +1071,7 @@ const char ** poptGetArgs(poptContext con)
|
||||
return (con->leftovers + con->nextLeftover);
|
||||
/*@=nullret =nullstate @*/
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
poptContext poptFreeContext(poptContext con)
|
||||
{
|
||||
@@ -1071,6 +1134,7 @@ int poptAddAlias(poptContext con, struct poptAlias alias,
|
||||
return poptAddItem(con, item, 0);
|
||||
}
|
||||
|
||||
/*@-boundswrite@*/
|
||||
/*@-mustmod@*/ /* LCL: con not modified? */
|
||||
int poptAddItem(poptContext con, poptItem newItem, int flags)
|
||||
{
|
||||
@@ -1115,6 +1179,7 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
|
||||
return 0;
|
||||
}
|
||||
/*@=mustmod@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
const char * poptBadOption(poptContext con, int flags)
|
||||
{
|
||||
@@ -1184,6 +1249,7 @@ const char * poptGetInvocationName(poptContext con)
|
||||
return (con->os->argv ? con->os->argv[0] : "");
|
||||
}
|
||||
|
||||
/*@-boundswrite@*/
|
||||
int poptStrippedArgv(poptContext con, int argc, char ** argv)
|
||||
{
|
||||
int numargs = argc;
|
||||
@@ -1207,3 +1273,4 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
|
||||
|
||||
return numargs;
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
216
popt/popt.h
216
popt/popt.h
@@ -112,33 +112,42 @@
|
||||
/** \ingroup popt
|
||||
*/
|
||||
struct poptOption {
|
||||
/*@observer@*/ /*@null@*/ const char * longName; /*!< may be NULL */
|
||||
char shortName; /*!< may be '\0' */
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * longName; /*!< may be NULL */
|
||||
char shortName; /*!< may be NUL */
|
||||
int argInfo;
|
||||
/*@shared@*/ /*@null@*/ void * arg; /*!< depends on argInfo */
|
||||
/*@shared@*/ /*@null@*/
|
||||
void * arg; /*!< depends on argInfo */
|
||||
int val; /*!< 0 means don't return, just update flag */
|
||||
/*@observer@*/ /*@null@*/ const char * descrip; /*!< description for autohelp -- may be NULL */
|
||||
/*@observer@*/ /*@null@*/ const char * argDescrip; /*!< argument description for autohelp */
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * descrip; /*!< description for autohelp -- may be NULL */
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * argDescrip; /*!< argument description for autohelp */
|
||||
};
|
||||
|
||||
/** \ingroup popt
|
||||
* A popt alias argument for poptAddAlias().
|
||||
*/
|
||||
struct poptAlias {
|
||||
/*@owned@*/ /*@null@*/ const char * longName; /*!< may be NULL */
|
||||
char shortName; /*!< may be '\0' */
|
||||
/*@owned@*/ /*@null@*/
|
||||
const char * longName; /*!< may be NULL */
|
||||
char shortName; /*!< may be NUL */
|
||||
int argc;
|
||||
/*@owned@*/ const char ** argv; /*!< must be free()able */
|
||||
/*@owned@*/
|
||||
const char ** argv; /*!< must be free()able */
|
||||
};
|
||||
|
||||
/** \ingroup popt
|
||||
* A popt alias or exec argument for poptAddItem().
|
||||
*/
|
||||
/*@-exporttype@*/
|
||||
typedef struct poptItem_s {
|
||||
struct poptOption option; /*!< alias/exec name(s) and description. */
|
||||
int argc; /*!< (alias) no. of args. */
|
||||
/*@owned@*/ const char ** argv; /*!< (alias) args, must be free()able. */
|
||||
/*@owned@*/
|
||||
const char ** argv; /*!< (alias) args, must be free()able. */
|
||||
} * poptItem;
|
||||
/*@=exporttype@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* \name Auto-generated help/usage
|
||||
@@ -148,16 +157,26 @@ typedef struct poptItem_s {
|
||||
/**
|
||||
* Empty table marker to enable displaying popt alias/exec options.
|
||||
*/
|
||||
/*@observer@*/ /*@checked@*/
|
||||
/*@-exportvar@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
extern struct poptOption poptAliasOptions[];
|
||||
/*@=exportvar@*/
|
||||
#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \
|
||||
0, "Options implemented via popt alias/exec:", NULL },
|
||||
|
||||
/**
|
||||
* Auto help table options.
|
||||
*/
|
||||
/*@observer@*/ /*@checked@*/
|
||||
/*@-exportvar@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
extern struct poptOption poptHelpOptions[];
|
||||
/*@=exportvar@*/
|
||||
|
||||
/*@-exportvar@*/
|
||||
/*@unchecked@*/ /*@observer@*/
|
||||
extern struct poptOption * poptHelpOptionsI18N;
|
||||
/*@=exportvar@*/
|
||||
|
||||
#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
|
||||
0, "Help options:", NULL },
|
||||
|
||||
@@ -166,19 +185,25 @@ extern struct poptOption poptHelpOptions[];
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
/*@-exporttype@*/
|
||||
typedef /*@abstract@*/ struct poptContext_s * poptContext;
|
||||
/*@=exporttype@*/
|
||||
|
||||
/** \ingroup popt
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
/*@-typeuse@*/
|
||||
/*@-exporttype -typeuse@*/
|
||||
typedef struct poptOption * poptOption;
|
||||
/*@=typeuse@*/
|
||||
/*@=exporttype =typeuse@*/
|
||||
#endif
|
||||
|
||||
enum poptCallbackReason { POPT_CALLBACK_REASON_PRE,
|
||||
POPT_CALLBACK_REASON_POST,
|
||||
POPT_CALLBACK_REASON_OPTION };
|
||||
/*@-exportconst@*/
|
||||
enum poptCallbackReason {
|
||||
POPT_CALLBACK_REASON_PRE = 0,
|
||||
POPT_CALLBACK_REASON_POST = 1,
|
||||
POPT_CALLBACK_REASON_OPTION = 2
|
||||
};
|
||||
/*@=exportconst@*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -198,18 +223,20 @@ typedef void (*poptCallbackType) (poptContext con,
|
||||
/*@null@*/ const struct poptOption * opt,
|
||||
/*@null@*/ const char * arg,
|
||||
/*@null@*/ const void * data)
|
||||
/*@*/;
|
||||
/*@globals internalState @*/
|
||||
/*@modifies internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Initialize popt context.
|
||||
* @param name
|
||||
* @param name context name (usually argv[0] program name)
|
||||
* @param argc no. of arguments
|
||||
* @param argv argument array
|
||||
* @param options address of popt option table
|
||||
* @param flags or'd POPT_CONTEXT_* bits
|
||||
* @return initialized popt context
|
||||
*/
|
||||
/*@only@*/ /*@null@*/ poptContext poptGetContext(
|
||||
/*@only@*/ /*@null@*/
|
||||
poptContext poptGetContext(
|
||||
/*@dependent@*/ /*@keep@*/ const char * name,
|
||||
int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
|
||||
/*@dependent@*/ /*@keep@*/ const struct poptOption * options,
|
||||
@@ -220,6 +247,7 @@ typedef void (*poptCallbackType) (poptContext con,
|
||||
* Reinitialize popt context.
|
||||
* @param con context
|
||||
*/
|
||||
/*@unused@*/
|
||||
void poptResetContext(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
@@ -229,57 +257,62 @@ void poptResetContext(/*@null@*/poptContext con)
|
||||
* @return next option val, -1 on last item, POPT_ERROR_* on error
|
||||
*/
|
||||
int poptGetNextOpt(/*@null@*/poptContext con)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies con, fileSystem @*/;
|
||||
/*@globals fileSystem, internalState @*/
|
||||
/*@modifies con, fileSystem, internalState @*/;
|
||||
|
||||
/*@-redecl@*/
|
||||
/** \ingroup popt
|
||||
* Return next option argument (if any).
|
||||
* @param con context
|
||||
* @return option argument, NULL if no more options are available
|
||||
* @return option argument, NULL if no argument is available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char * poptGetOptArg(/*@null@*/poptContext con)
|
||||
/*@observer@*/ /*@null@*/ /*@unused@*/
|
||||
const char * poptGetOptArg(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return current option's argument.
|
||||
* Return next argument.
|
||||
* @param con context
|
||||
* @return option argument, NULL if no more options are available
|
||||
* @return next argument, NULL if no argument is available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char * poptGetArg(/*@null@*/poptContext con)
|
||||
/*@observer@*/ /*@null@*/ /*@unused@*/
|
||||
const char * poptGetArg(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Peek at current option's argument.
|
||||
* Peek at current argument.
|
||||
* @param con context
|
||||
* @return option argument
|
||||
* @return current argument, NULL if no argument is available
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char * poptPeekArg(/*@null@*/poptContext con)
|
||||
/*@observer@*/ /*@null@*/ /*@unused@*/
|
||||
const char * poptPeekArg(/*@null@*/poptContext con)
|
||||
/*@*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return remaining arguments.
|
||||
* @param con context
|
||||
* @return argument array, terminated with NULL
|
||||
* @return argument array, NULL terminated
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con)
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char ** poptGetArgs(/*@null@*/poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Return the option which caused the most recent error.
|
||||
* @param con context
|
||||
* @param flags
|
||||
* @return offending option
|
||||
*/
|
||||
/*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags)
|
||||
/*@observer@*/
|
||||
const char * poptBadOption(/*@null@*/poptContext con, int flags)
|
||||
/*@*/;
|
||||
/*@=redecl@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Destroy context.
|
||||
* @param con context
|
||||
* @return NULL always
|
||||
*/
|
||||
/*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
|
||||
/*@null@*/
|
||||
poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
|
||||
/*@modifies con @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
@@ -288,6 +321,7 @@ int poptGetNextOpt(/*@null@*/poptContext con)
|
||||
* @param argv argument array, NULL terminated
|
||||
* @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure
|
||||
*/
|
||||
/*@unused@*/
|
||||
int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
|
||||
/*@modifies con @*/;
|
||||
|
||||
@@ -307,7 +341,7 @@ int poptAddAlias(poptContext con, struct poptAlias alias, int flags)
|
||||
/** \ingroup popt
|
||||
* Add alias/exec item to context.
|
||||
* @param con context
|
||||
* @param item alias/exec item to add
|
||||
* @param newItem alias/exec item to add
|
||||
* @param flags 0 for alias, 1 for exec
|
||||
* @return 0 on success
|
||||
*/
|
||||
@@ -321,9 +355,9 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
|
||||
* @return 0 on success, POPT_ERROR_ERRNO on failure
|
||||
*/
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem,
|
||||
con->execs, con->numExecs @*/;
|
||||
/*@globals errno, fileSystem, internalState @*/
|
||||
/*@modifies con->execs, con->numExecs,
|
||||
errno, fileSystem, internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Read default configuration from /etc/popt and $HOME/.popt.
|
||||
@@ -331,10 +365,11 @@ int poptReadConfigFile(poptContext con, const char * fn)
|
||||
* @param useEnv (unused)
|
||||
* @return 0 on success, POPT_ERROR_ERRNO on failure
|
||||
*/
|
||||
/*@unused@*/
|
||||
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
|
||||
/*@globals fileSystem@*/
|
||||
/*@modifies fileSystem,
|
||||
con->execs, con->numExecs @*/;
|
||||
/*@globals fileSystem, internalState @*/
|
||||
/*@modifies con->execs, con->numExecs,
|
||||
fileSystem, internalState @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Duplicate an argument array.
|
||||
@@ -363,19 +398,70 @@ int poptDupArgv(int argc, /*@null@*/ const char **argv,
|
||||
* @retval argcPtr address of returned no. of arguments
|
||||
* @retval argvPtr address of returned argument array
|
||||
*/
|
||||
int poptParseArgvString(const unsigned char * s,
|
||||
int poptParseArgvString(const char * s,
|
||||
/*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr)
|
||||
/*@modifies *argcPtr, *argvPtr @*/;
|
||||
|
||||
/** \ingroup popt
|
||||
* Parses an input configuration file and returns an string that is a
|
||||
* command line. For use with popt. You must free the return value when done.
|
||||
*
|
||||
* Given the file:
|
||||
\verbatim
|
||||
# this line is ignored
|
||||
# this one too
|
||||
aaa
|
||||
bbb
|
||||
ccc
|
||||
bla=bla
|
||||
|
||||
this_is = fdsafdas
|
||||
bad_line=
|
||||
reall bad line
|
||||
reall bad line = again
|
||||
5555= 55555
|
||||
test = with lots of spaces
|
||||
\endverbatim
|
||||
*
|
||||
* The result is:
|
||||
\verbatim
|
||||
--aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces"
|
||||
\endverbatim
|
||||
*
|
||||
* Passing this to poptParseArgvString() yields an argv of:
|
||||
\verbatim
|
||||
'--aaa'
|
||||
'--bbb'
|
||||
'--ccc'
|
||||
'--bla=bla'
|
||||
'--this_is=fdsafdas'
|
||||
'--5555=55555'
|
||||
'--test=with lots of spaces'
|
||||
\endverbatim
|
||||
*
|
||||
* @bug NULL is returned if file line is too long.
|
||||
* @bug Silently ignores invalid lines.
|
||||
*
|
||||
* @param fp file handle to read
|
||||
* @param *argstrp return string of options (malloc'd)
|
||||
* @param flags unused
|
||||
* @return 0 on success
|
||||
* @see poptParseArgvString
|
||||
*/
|
||||
/*@-fcnuse@*/
|
||||
int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, *argstrp, fileSystem @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Return formatted error string for popt failure.
|
||||
* @param error popt error
|
||||
* @return error string
|
||||
*/
|
||||
/*@-redecl@*/
|
||||
/*@observer@*/ const char * poptStrerror(const int error)
|
||||
/*@observer@*/
|
||||
const char * poptStrerror(const int error)
|
||||
/*@*/;
|
||||
/*@=redecl@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Limit search for executables.
|
||||
@@ -383,6 +469,7 @@ int poptParseArgvString(const unsigned char * s,
|
||||
* @param path single path to search for executables
|
||||
* @param allowAbsolute absolute paths only?
|
||||
*/
|
||||
/*@unused@*/
|
||||
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
|
||||
/*@modifies con @*/;
|
||||
|
||||
@@ -421,10 +508,11 @@ void poptSetOtherOptionHelp(poptContext con, const char * text)
|
||||
* @param con context
|
||||
* @return argv[0]
|
||||
*/
|
||||
/*@-redecl -fcnuse@*/
|
||||
/*@observer@*/ const char * poptGetInvocationName(poptContext con)
|
||||
/*@-fcnuse@*/
|
||||
/*@observer@*/
|
||||
const char * poptGetInvocationName(poptContext con)
|
||||
/*@*/;
|
||||
/*@=redecl =fcnuse@*/
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/** \ingroup popt
|
||||
* Shuffle argv pointers to remove stripped args, returns new argc.
|
||||
@@ -438,6 +526,36 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
|
||||
/*@modifies *argv @*/;
|
||||
/*@=fcnuse@*/
|
||||
|
||||
/**
|
||||
* Save a long, performing logical operation with value.
|
||||
* @warning Alignment check may be too strict on certain platorms.
|
||||
* @param arg integer pointer, aligned on int boundary.
|
||||
* @param argInfo logical operation (see POPT_ARGFLAG_*)
|
||||
* @param aLong value to use
|
||||
* @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
|
||||
*/
|
||||
/*@-incondefs@*/
|
||||
/*@unused@*/
|
||||
int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
|
||||
/*@modifies *arg @*/
|
||||
/*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
|
||||
/*@=incondefs@*/
|
||||
|
||||
/**
|
||||
* Save an integer, performing logical operation with value.
|
||||
* @warning Alignment check may be too strict on certain platorms.
|
||||
* @param arg integer pointer, aligned on int boundary.
|
||||
* @param argInfo logical operation (see POPT_ARGFLAG_*)
|
||||
* @param aLong value to use
|
||||
* @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
|
||||
*/
|
||||
/*@-incondefs@*/
|
||||
/*@unused@*/
|
||||
int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
|
||||
/*@modifies *arg @*/
|
||||
/*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
|
||||
/*@=incondefs@*/
|
||||
|
||||
/*@=type@*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -2,46 +2,48 @@
|
||||
* \file popt/poptconfig.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
#include "poptint.h"
|
||||
/*@access poptContext @*/
|
||||
|
||||
/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
|
||||
static void configLine(poptContext con, unsigned char * line)
|
||||
static void configLine(poptContext con, char * line)
|
||||
/*@modifies con @*/
|
||||
{
|
||||
/*@-type@*/
|
||||
int nameLength = strlen(con->appName);
|
||||
/*@=type@*/
|
||||
size_t nameLength;
|
||||
const char * entryType;
|
||||
const char * opt;
|
||||
poptItem item = (poptItem) alloca(sizeof(*item));
|
||||
int i, j;
|
||||
|
||||
if (con->appName == NULL)
|
||||
return;
|
||||
nameLength = strlen(con->appName);
|
||||
|
||||
/*@-boundswrite@*/
|
||||
memset(item, 0, sizeof(*item));
|
||||
|
||||
/*@-type@*/
|
||||
if (strncmp(line, con->appName, nameLength)) return;
|
||||
/*@=type@*/
|
||||
|
||||
line += nameLength;
|
||||
if (*line == '\0' || !isspace(*line)) return;
|
||||
if (*line == '\0' || !isSpace(line)) return;
|
||||
|
||||
while (*line != '\0' && isspace(*line)) line++;
|
||||
while (*line != '\0' && isSpace(line)) line++;
|
||||
entryType = line;
|
||||
while (*line == '\0' || !isspace(*line)) line++;
|
||||
while (*line == '\0' || !isSpace(line)) line++;
|
||||
*line++ = '\0';
|
||||
|
||||
while (*line != '\0' && isspace(*line)) line++;
|
||||
while (*line != '\0' && isSpace(line)) line++;
|
||||
if (*line == '\0') return;
|
||||
opt = line;
|
||||
while (*line == '\0' || !isspace(*line)) line++;
|
||||
while (*line == '\0' || !isSpace(line)) line++;
|
||||
*line++ = '\0';
|
||||
|
||||
while (*line != '\0' && isspace(*line)) line++;
|
||||
while (*line != '\0' && isSpace(line)) line++;
|
||||
if (*line == '\0') return;
|
||||
|
||||
/*@-temptrans@*/ /* FIX: line alias is saved */
|
||||
@@ -80,6 +82,7 @@ static void configLine(poptContext con, unsigned char * line)
|
||||
item->argc = j;
|
||||
}
|
||||
/*@=modobserver@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
/*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
|
||||
if (!strcmp(entryType, "alias"))
|
||||
@@ -92,9 +95,9 @@ static void configLine(poptContext con, unsigned char * line)
|
||||
|
||||
int poptReadConfigFile(poptContext con, const char * fn)
|
||||
{
|
||||
const unsigned char * file, * chptr, * end;
|
||||
unsigned char * buf;
|
||||
/*@dependent@*/ unsigned char * dst;
|
||||
const char * file, * chptr, * end;
|
||||
char * buf;
|
||||
/*@dependent@*/ char * dst;
|
||||
int fd, rc;
|
||||
off_t fileLength;
|
||||
|
||||
@@ -106,9 +109,7 @@ int poptReadConfigFile(poptContext con, const char * fn)
|
||||
if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
|
||||
rc = errno;
|
||||
(void) close(fd);
|
||||
/*@-mods@*/
|
||||
errno = rc;
|
||||
/*@=mods@*/
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
|
||||
@@ -116,14 +117,13 @@ int poptReadConfigFile(poptContext con, const char * fn)
|
||||
if (read(fd, (char *)file, fileLength) != fileLength) {
|
||||
rc = errno;
|
||||
(void) close(fd);
|
||||
/*@-mods@*/
|
||||
errno = rc;
|
||||
/*@=mods@*/
|
||||
return POPT_ERROR_ERRNO;
|
||||
}
|
||||
if (close(fd) == -1)
|
||||
return POPT_ERROR_ERRNO;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
dst = buf = alloca(fileLength + 1);
|
||||
|
||||
chptr = file;
|
||||
@@ -134,7 +134,7 @@ int poptReadConfigFile(poptContext con, const char * fn)
|
||||
case '\n':
|
||||
*dst = '\0';
|
||||
dst = buf;
|
||||
while (*dst && isspace(*dst)) dst++;
|
||||
while (*dst && isSpace(dst)) dst++;
|
||||
if (*dst && *dst != '#')
|
||||
configLine(con, dst);
|
||||
chptr++;
|
||||
@@ -155,6 +155,7 @@ int poptReadConfigFile(poptContext con, const char * fn)
|
||||
}
|
||||
}
|
||||
/*@=infloops@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -164,18 +165,16 @@ int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
|
||||
char * fn, * home;
|
||||
int rc;
|
||||
|
||||
/*@-type@*/
|
||||
if (!con->appName) return 0;
|
||||
/*@=type@*/
|
||||
if (con->appName == NULL) return 0;
|
||||
|
||||
rc = poptReadConfigFile(con, "/etc/popt");
|
||||
if (rc) return rc;
|
||||
if (getuid() != geteuid()) return 0;
|
||||
|
||||
if ((home = getenv("HOME"))) {
|
||||
fn = alloca(strlen(home) + 20);
|
||||
strcpy(fn, home);
|
||||
strcat(fn, "/.popt");
|
||||
size_t bufsize = strlen(home) + 20;
|
||||
fn = alloca(bufsize);
|
||||
if (fn == NULL) return 0;
|
||||
snprintf(fn, bufsize, "%s/.popt", home);
|
||||
rc = poptReadConfigFile(con, fn);
|
||||
if (rc) return rc;
|
||||
}
|
||||
|
||||
384
popt/popthelp.c
384
popt/popthelp.c
@@ -1,20 +1,31 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
|
||||
/*@-type@*/
|
||||
/** \ingroup popt
|
||||
* \file popt/popthelp.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
/*#define POPT_WCHAR_HACK*/
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
#include <wchar.h> /* for mbsrtowcs */
|
||||
/*@access mbstate_t @*/
|
||||
#endif
|
||||
#include "poptint.h"
|
||||
|
||||
/*@access poptContext@*/
|
||||
|
||||
/**
|
||||
* Display arguments.
|
||||
* @param con context
|
||||
* @param foo (unused)
|
||||
* @param key option(s)
|
||||
* @param arg (unused)
|
||||
* @param data (unused)
|
||||
*/
|
||||
static void displayArgs(poptContext con,
|
||||
/*@unused@*/ UNUSED(enum poptCallbackReason foo),
|
||||
@@ -49,6 +60,17 @@ struct poptOption poptAliasOptions[] = {
|
||||
/*@-castfcnptr@*/
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
struct poptOption poptHelpOptions[] = {
|
||||
{ NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
|
||||
{ "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
|
||||
{ "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
|
||||
POPT_TABLEEND
|
||||
} ;
|
||||
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
static struct poptOption poptHelpOptions2[] = {
|
||||
/*@-readonlytrans@*/
|
||||
{ NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
|
||||
/*@=readonlytrans@*/
|
||||
{ NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
|
||||
{ "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
|
||||
{ "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
|
||||
@@ -58,6 +80,9 @@ struct poptOption poptHelpOptions[] = {
|
||||
#endif
|
||||
POPT_TABLEEND
|
||||
} ;
|
||||
|
||||
/*@observer@*/ /*@unchecked@*/
|
||||
struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
|
||||
/*@=castfcnptr@*/
|
||||
|
||||
/**
|
||||
@@ -83,7 +108,7 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getArgDescrip(const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: wazzup? */
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
@@ -97,7 +122,11 @@ getArgDescrip(const struct poptOption * opt,
|
||||
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_NONE: return POPT_("NONE");
|
||||
#ifdef DYING
|
||||
case POPT_ARG_VAL: return POPT_("VAL");
|
||||
#else
|
||||
case POPT_ARG_VAL: return NULL;
|
||||
#endif
|
||||
case POPT_ARG_INT: return POPT_("INT");
|
||||
case POPT_ARG_LONG: return POPT_("LONG");
|
||||
case POPT_ARG_STRING: return POPT_("STRING");
|
||||
@@ -108,61 +137,65 @@ getArgDescrip(const struct poptOption * opt,
|
||||
}
|
||||
|
||||
/**
|
||||
* Display default value for an option.
|
||||
* @param lineLength display positions remaining
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
* @return
|
||||
*/
|
||||
static /*@only@*/ /*@null@*/ char *
|
||||
singleOptionDefaultValue(int lineLength,
|
||||
singleOptionDefaultValue(size_t lineLength,
|
||||
const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
const char * defstr = D_(translation_domain, "default");
|
||||
char * le = malloc(4*lineLength + 1);
|
||||
size_t limit, bufsize = 4*lineLength + 1;
|
||||
char * le = malloc(bufsize);
|
||||
char * l = le;
|
||||
|
||||
if (le == NULL) return NULL; /* XXX can't happen */
|
||||
*le = '\0';
|
||||
/*@-boundswrite@*/
|
||||
*le++ = '(';
|
||||
strcpy(le, defstr); le += strlen(le);
|
||||
le += strlcpy(le, defstr, bufsize - 3);
|
||||
*le++ = ':';
|
||||
*le++ = ' ';
|
||||
limit = bufsize - (le - l) - 1; /* -1 for closing paren */
|
||||
if (opt->arg) /* XXX programmer error */
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_VAL:
|
||||
case POPT_ARG_INT:
|
||||
{ long aLong = *((int *)opt->arg);
|
||||
sprintf(le, "%ld", aLong);
|
||||
le += strlen(le);
|
||||
le += snprintf(le, limit, "%ld", aLong);
|
||||
} break;
|
||||
case POPT_ARG_LONG:
|
||||
{ long aLong = *((long *)opt->arg);
|
||||
sprintf(le, "%ld", aLong);
|
||||
le += strlen(le);
|
||||
le += snprintf(le, limit, "%ld", aLong);
|
||||
} break;
|
||||
case POPT_ARG_FLOAT:
|
||||
{ double aDouble = *((float *)opt->arg);
|
||||
sprintf(le, "%g", aDouble);
|
||||
le += strlen(le);
|
||||
le += snprintf(le, limit, "%g", aDouble);
|
||||
} break;
|
||||
case POPT_ARG_DOUBLE:
|
||||
{ double aDouble = *((double *)opt->arg);
|
||||
sprintf(le, "%g", aDouble);
|
||||
le += strlen(le);
|
||||
le += snprintf(le, limit, "%g", aDouble);
|
||||
} break;
|
||||
case POPT_ARG_STRING:
|
||||
{ const char * s = *(const char **)opt->arg;
|
||||
if (s == NULL) {
|
||||
strcpy(le, "null"); le += strlen(le);
|
||||
le += strlcpy(le, "null", limit);
|
||||
} else {
|
||||
size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
|
||||
size_t len;
|
||||
limit -= 2; /* make room for quotes */
|
||||
*le++ = '"';
|
||||
strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
|
||||
if (slen < strlen(s)) {
|
||||
strcpy(le, "..."); le += strlen(le);
|
||||
}
|
||||
len = strlcpy(le, s, limit);
|
||||
if (len >= limit) {
|
||||
le += limit - 3 - 1;
|
||||
*le++ = '.'; *le++ = '.'; *le++ = '.';
|
||||
} else
|
||||
le += len;
|
||||
*le++ = '"';
|
||||
}
|
||||
} break;
|
||||
@@ -174,50 +207,57 @@ singleOptionDefaultValue(int lineLength,
|
||||
}
|
||||
*le++ = ')';
|
||||
*le = '\0';
|
||||
/*@=boundswrite@*/
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display help text for an option.
|
||||
* @param fp output file handle
|
||||
* @param maxLeftCol largest argument display width
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
static void singleOptionHelp(FILE * fp, size_t maxLeftCol,
|
||||
const struct poptOption * opt,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int indentLength = maxLeftCol + 5;
|
||||
int lineLength = 79 - indentLength;
|
||||
const unsigned char * help = D_(translation_domain, opt->descrip);
|
||||
size_t indentLength = maxLeftCol + 5;
|
||||
size_t lineLength = 79 - indentLength;
|
||||
const char * help = D_(translation_domain, opt->descrip);
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
int helpLength;
|
||||
unsigned char * defs = NULL;
|
||||
unsigned char * left;
|
||||
int nb = maxLeftCol + 1;
|
||||
size_t helpLength;
|
||||
char * defs = NULL;
|
||||
char * left;
|
||||
size_t lelen, limit;
|
||||
size_t nb = maxLeftCol + 1;
|
||||
int displaypad = 0;
|
||||
|
||||
/* Make sure there's more than enough room in target buffer. */
|
||||
if (opt->longName) nb += strlen(opt->longName);
|
||||
if (argDescrip) nb += strlen(argDescrip);
|
||||
|
||||
/*@-boundswrite@*/
|
||||
left = malloc(nb);
|
||||
if (left == NULL) return; /* XXX can't happen */
|
||||
left[0] = '\0';
|
||||
left[maxLeftCol] = '\0';
|
||||
|
||||
if (opt->longName && opt->shortName)
|
||||
sprintf(left, "-%c, %s%s", opt->shortName,
|
||||
snprintf(left, nb, "-%c, %s%s", opt->shortName,
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
else if (opt->shortName != '\0')
|
||||
sprintf(left, "-%c", opt->shortName);
|
||||
snprintf(left, nb, "-%c", opt->shortName);
|
||||
else if (opt->longName)
|
||||
sprintf(left, "%s%s",
|
||||
snprintf(left, nb, "%s%s",
|
||||
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
|
||||
opt->longName);
|
||||
if (!*left) goto out;
|
||||
|
||||
if (argDescrip) {
|
||||
char * le = left + strlen(left);
|
||||
|
||||
@@ -229,16 +269,10 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
|
||||
defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
|
||||
if (defs) {
|
||||
char * t = malloc((help ? strlen(help) : 0) +
|
||||
strlen(defs) + sizeof(" "));
|
||||
size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs);
|
||||
char * t = malloc(bufsize);
|
||||
if (t) {
|
||||
char * te = t;
|
||||
*te = '\0';
|
||||
if (help) {
|
||||
strcpy(te, help); te += strlen(te);
|
||||
}
|
||||
*te++ = ' ';
|
||||
strcpy(te, defs);
|
||||
snprintf(t, bufsize, "%s %s", help ? help : "", defs);
|
||||
defs = _free(defs);
|
||||
}
|
||||
defs = t;
|
||||
@@ -251,6 +285,7 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
case POPT_ARG_NONE:
|
||||
break;
|
||||
case POPT_ARG_VAL:
|
||||
#ifdef NOTNOW /* XXX pug ugly nerdy output */
|
||||
{ long aLong = opt->val;
|
||||
int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
|
||||
int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
|
||||
@@ -272,65 +307,94 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
|
||||
default:
|
||||
/*@innerbreak@*/ break;
|
||||
}
|
||||
*le++ = '=';
|
||||
*le++ = (opt->longName != NULL ? '=' : ' ');
|
||||
if (negate) *le++ = '~';
|
||||
/*@-formatconst@*/
|
||||
sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
|
||||
le += strlen(le);
|
||||
limit = nb - (le - left);
|
||||
lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong);
|
||||
le += lelen >= limit ? limit - 1 : lelen;
|
||||
/*@=formatconst@*/
|
||||
*le++ = ']';
|
||||
} break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case POPT_ARG_INT:
|
||||
case POPT_ARG_LONG:
|
||||
case POPT_ARG_FLOAT:
|
||||
case POPT_ARG_DOUBLE:
|
||||
case POPT_ARG_STRING:
|
||||
*le++ = '=';
|
||||
strcpy(le, argDescrip); le += strlen(le);
|
||||
*le++ = (opt->longName != NULL ? '=' : ' ');
|
||||
limit = nb - (le - left);
|
||||
lelen = strlcpy(le, argDescrip, limit);
|
||||
le += lelen >= limit ? limit - 1 : lelen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
*le++ = '=';
|
||||
strcpy(le, argDescrip); le += strlen(le);
|
||||
limit = nb - (le - left);
|
||||
lelen = strlcpy(le, argDescrip, limit);
|
||||
if (lelen >= limit)
|
||||
lelen = limit - 1;
|
||||
le += lelen;
|
||||
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
{ const char * scopy = argDescrip;
|
||||
mbstate_t t;
|
||||
size_t n;
|
||||
|
||||
memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
|
||||
/* Determine number of characters. */
|
||||
n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
|
||||
|
||||
displaypad = (int) (lelen-n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
|
||||
*le++ = ']';
|
||||
*le = '\0';
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
if (help)
|
||||
fprintf(fp," %-*s ", maxLeftCol, left);
|
||||
fprintf(fp," %-*s ", (int)maxLeftCol+displaypad, left);
|
||||
else {
|
||||
fprintf(fp," %s\n", left);
|
||||
goto out;
|
||||
}
|
||||
|
||||
left = _free(left);
|
||||
/*@-branchstate@*/
|
||||
if (defs) {
|
||||
help = defs; defs = NULL;
|
||||
help = defs;
|
||||
defs = NULL;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
helpLength = strlen(help);
|
||||
/*@-boundsread@*/
|
||||
while (helpLength > lineLength) {
|
||||
const unsigned char * ch;
|
||||
char format[10];
|
||||
const char * ch;
|
||||
char format[16];
|
||||
|
||||
ch = help + lineLength - 1;
|
||||
while (ch > help && !isspace(*ch)) ch--;
|
||||
while (ch > help && !isSpace(ch)) ch--;
|
||||
if (ch == help) break; /* give up */
|
||||
while (ch > (help + 1) && isspace(*ch)) ch--;
|
||||
while (ch > (help + 1) && isSpace(ch)) ch--;
|
||||
ch++;
|
||||
|
||||
sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
|
||||
snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
|
||||
/*@-formatconst@*/
|
||||
fprintf(fp, format, help, " ");
|
||||
/*@=formatconst@*/
|
||||
help = ch;
|
||||
while (isspace(*help) && *help) help++;
|
||||
while (isSpace(help) && *help) help++;
|
||||
helpLength = strlen(help);
|
||||
}
|
||||
/*@=boundsread@*/
|
||||
|
||||
if (helpLength) fprintf(fp, "%s\n", help);
|
||||
|
||||
@@ -342,15 +406,17 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
* Find display width for longest argument string.
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
* @return display width
|
||||
*/
|
||||
static int maxArgWidth(const struct poptOption * opt,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
static size_t maxArgWidth(const struct poptOption * opt,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@*/
|
||||
{
|
||||
int max = 0;
|
||||
int len = 0;
|
||||
size_t max = 0;
|
||||
size_t len = 0;
|
||||
const char * s;
|
||||
|
||||
if (opt != NULL)
|
||||
@@ -370,8 +436,26 @@ static int maxArgWidth(const struct poptOption * opt,
|
||||
}
|
||||
|
||||
s = getArgDescrip(opt, translation_domain);
|
||||
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
/* XXX Calculate no. of display characters. */
|
||||
if (s) {
|
||||
const char * scopy = s;
|
||||
mbstate_t t;
|
||||
size_t n;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
|
||||
/*@=boundswrite@*/
|
||||
/* Determine number of characters. */
|
||||
n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
|
||||
len += sizeof("=")-1 + n;
|
||||
}
|
||||
#else
|
||||
if (s)
|
||||
len += sizeof("=")-1 + strlen(s);
|
||||
#endif
|
||||
|
||||
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
|
||||
if (len > max) max = len;
|
||||
}
|
||||
@@ -387,11 +471,12 @@ static int maxArgWidth(const struct poptOption * opt,
|
||||
* @param fp output file handle
|
||||
* @param items alias/exec array
|
||||
* @param nitems no. of alias/exec entries
|
||||
* @param left largest argument display width
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void itemHelp(FILE * fp,
|
||||
/*@null@*/ poptItem items, int nitems, int left,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@null@*/ poptItem items, int nitems, size_t left,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
@@ -409,13 +494,16 @@ static void itemHelp(FILE * fp,
|
||||
}
|
||||
|
||||
/**
|
||||
* Display help text for a table of options.
|
||||
* @param con context
|
||||
* @param fp output file handle
|
||||
* @param table option(s)
|
||||
* @param left largest argument display width
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static void singleTableHelp(poptContext con, FILE * fp,
|
||||
/*@null@*/ const struct poptOption * table, int left,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@null@*/ const struct poptOption * table, size_t left,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
@@ -463,9 +551,11 @@ static int showHelpIntro(poptContext con, FILE * fp)
|
||||
|
||||
fprintf(fp, POPT_("Usage:"));
|
||||
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
|
||||
/*@-nullderef@*/ /* LCL: wazzup? */
|
||||
/*@-boundsread@*/
|
||||
/*@-nullderef -type@*/ /* LCL: wazzup? */
|
||||
fn = con->optionStack->argv[0];
|
||||
/*@=nullderef@*/
|
||||
/*@=nullderef =type@*/
|
||||
/*@=boundsread@*/
|
||||
if (fn == NULL) return len;
|
||||
if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
|
||||
fprintf(fp, " %s", fn);
|
||||
@@ -477,7 +567,7 @@ static int showHelpIntro(poptContext con, FILE * fp)
|
||||
|
||||
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
int leftColWidth;
|
||||
size_t leftColWidth;
|
||||
|
||||
(void) showHelpIntro(con, fp);
|
||||
if (con->otherHelp)
|
||||
@@ -490,47 +580,76 @@ void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
}
|
||||
|
||||
/**
|
||||
* Display usage text for an option.
|
||||
* @param fp output file handle
|
||||
* @param cursor current display position
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static int singleOptionUsage(FILE * fp, int cursor,
|
||||
static size_t singleOptionUsage(FILE * fp, size_t cursor,
|
||||
const struct poptOption * opt,
|
||||
/*@null@*/ const char *translation_domain)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
int len = 3;
|
||||
size_t len = 4;
|
||||
char shortStr[2] = { '\0', '\0' };
|
||||
const char * item = shortStr;
|
||||
const char * argDescrip = getArgDescrip(opt, translation_domain);
|
||||
|
||||
if (opt->shortName!= '\0' ) {
|
||||
if (!(opt->argInfo & POPT_ARG_MASK))
|
||||
return cursor; /* we did these already */
|
||||
if (opt->shortName != '\0' && opt->longName != NULL) {
|
||||
len += 2;
|
||||
if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
|
||||
len += strlen(opt->longName);
|
||||
} else if (opt->shortName != '\0') {
|
||||
len++;
|
||||
shortStr[0] = opt->shortName;
|
||||
shortStr[1] = '\0';
|
||||
} else if (opt->longName) {
|
||||
len += 1 + strlen(opt->longName);
|
||||
len += strlen(opt->longName);
|
||||
if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
|
||||
item = opt->longName;
|
||||
}
|
||||
|
||||
if (len == 3) return cursor;
|
||||
if (len == 4) return cursor;
|
||||
|
||||
#ifdef POPT_WCHAR_HACK
|
||||
/* XXX Calculate no. of display characters. */
|
||||
if (argDescrip) {
|
||||
const char * scopy = argDescrip;
|
||||
mbstate_t t;
|
||||
size_t n;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */
|
||||
/*@=boundswrite@*/
|
||||
/* Determine number of characters. */
|
||||
n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
|
||||
len += sizeof("=")-1 + n;
|
||||
}
|
||||
#else
|
||||
if (argDescrip)
|
||||
len += strlen(argDescrip) + 1;
|
||||
len += sizeof("=")-1 + strlen(argDescrip);
|
||||
#endif
|
||||
|
||||
if ((cursor + len) > 79) {
|
||||
fprintf(fp, "\n ");
|
||||
cursor = 7;
|
||||
}
|
||||
|
||||
fprintf(fp, " [-%s%s%s%s]",
|
||||
((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
|
||||
item,
|
||||
(argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
|
||||
(argDescrip ? argDescrip : ""));
|
||||
if (opt->longName && opt->shortName) {
|
||||
fprintf(fp, " [-%c|-%s%s%s%s]",
|
||||
opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
|
||||
opt->longName,
|
||||
(argDescrip ? " " : ""),
|
||||
(argDescrip ? argDescrip : ""));
|
||||
} else {
|
||||
fprintf(fp, " [-%s%s%s%s]",
|
||||
((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
|
||||
item,
|
||||
(argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
|
||||
(argDescrip ? argDescrip : ""));
|
||||
}
|
||||
|
||||
return cursor + len + 1;
|
||||
}
|
||||
@@ -538,12 +657,14 @@ static int singleOptionUsage(FILE * fp, int cursor,
|
||||
/**
|
||||
* Display popt alias and exec usage.
|
||||
* @param fp output file handle
|
||||
* @param cursor current display position
|
||||
* @param item alias/exec array
|
||||
* @param nitems no. of ara/exec entries
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
static size_t itemUsage(FILE * fp, size_t cursor,
|
||||
/*@null@*/ poptItem item, int nitems,
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
{
|
||||
@@ -567,15 +688,30 @@ static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of option tables already processed.
|
||||
*/
|
||||
typedef struct poptDone_s {
|
||||
int nopts;
|
||||
int maxopts;
|
||||
const void ** opts;
|
||||
} * poptDone;
|
||||
|
||||
/**
|
||||
* Display usage text for a table of options.
|
||||
* @param con context
|
||||
* @param fp output file handle
|
||||
* @param cursor current display position
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
* @param done tables already processed
|
||||
* @return
|
||||
*/
|
||||
static int singleTableUsage(poptContext con, FILE * fp,
|
||||
int cursor, const struct poptOption * opt,
|
||||
/*@null@*/ const char * translation_domain)
|
||||
static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
|
||||
/*@null@*/ const struct poptOption * opt,
|
||||
/*@null@*/ UNUSED(const char * translation_domain),
|
||||
/*@null@*/ poptDone done)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *fp, fileSystem @*/
|
||||
/*@modifies *fp, done, fileSystem @*/
|
||||
{
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (opt != NULL)
|
||||
@@ -583,9 +719,26 @@ static int singleTableUsage(poptContext con, FILE * fp,
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
|
||||
translation_domain = (const char *)opt->arg;
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
|
||||
if (opt->arg) /* XXX program error */
|
||||
if (done) {
|
||||
int i = 0;
|
||||
for (i = 0; i < done->nopts; i++) {
|
||||
/*@-boundsread@*/
|
||||
const void * that = done->opts[i];
|
||||
/*@=boundsread@*/
|
||||
if (that == NULL || that != opt->arg)
|
||||
/*@innercontinue@*/ continue;
|
||||
/*@innerbreak@*/ break;
|
||||
}
|
||||
/* Skip if this table has already been processed. */
|
||||
if (opt->arg == NULL || i < done->nopts)
|
||||
continue;
|
||||
/*@-boundswrite@*/
|
||||
if (done->nopts < done->maxopts)
|
||||
done->opts[done->nopts++] = (const void *) opt->arg;
|
||||
/*@=boundswrite@*/
|
||||
}
|
||||
cursor = singleTableUsage(con, fp, cursor, opt->arg,
|
||||
translation_domain);
|
||||
translation_domain, done);
|
||||
} else if ((opt->longName || opt->shortName) &&
|
||||
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
|
||||
cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
|
||||
@@ -598,6 +751,7 @@ static int singleTableUsage(poptContext con, FILE * fp,
|
||||
|
||||
/**
|
||||
* Return concatenated short options for display.
|
||||
* @todo Sub-tables should be recursed.
|
||||
* @param opt option(s)
|
||||
* @param fp output file handle
|
||||
* @retval str concatenation of short options
|
||||
@@ -607,42 +761,51 @@ static int showShortOptions(const struct poptOption * opt, FILE * fp,
|
||||
/*@null@*/ char * str)
|
||||
/*@globals fileSystem @*/
|
||||
/*@modifies *str, *fp, fileSystem @*/
|
||||
/*@requires maxRead(str) >= 0 @*/
|
||||
{
|
||||
char * s = alloca(300); /* larger then the ascii set */
|
||||
|
||||
s[0] = '\0';
|
||||
/*@-branchstate@*/ /* FIX: W2DO? */
|
||||
if (str == NULL) {
|
||||
memset(s, 0, sizeof(s));
|
||||
str = s;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
/* bufsize larger then the ascii set, lazy alloca on top level call. */
|
||||
char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
|
||||
int len = 0;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
if (opt != NULL)
|
||||
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
|
||||
str[strlen(str)] = opt->shortName;
|
||||
s[strlen(s)] = opt->shortName;
|
||||
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
|
||||
if (opt->arg) /* XXX program error */
|
||||
(void) showShortOptions(opt->arg, fp, str);
|
||||
len = showShortOptions(opt->arg, fp, s);
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
if (s != str || *s != '\0')
|
||||
return 0;
|
||||
|
||||
fprintf(fp, " [-%s]", s);
|
||||
return strlen(s) + 4;
|
||||
/* On return to top level, print the short options, return print length. */
|
||||
if (s == str && *s != '\0') {
|
||||
fprintf(fp, " [-%s]", s);
|
||||
len = strlen(s) + sizeof(" [-]")-1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
int cursor;
|
||||
poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
|
||||
size_t cursor;
|
||||
|
||||
done->nopts = 0;
|
||||
done->maxopts = 64;
|
||||
cursor = done->maxopts * sizeof(*done->opts);
|
||||
/*@-boundswrite@*/
|
||||
done->opts = memset(alloca(cursor), 0, cursor);
|
||||
/*@-keeptrans@*/
|
||||
done->opts[done->nopts++] = (const void *) con->options;
|
||||
/*@=keeptrans@*/
|
||||
/*@=boundswrite@*/
|
||||
|
||||
cursor = showHelpIntro(con, fp);
|
||||
cursor += showShortOptions(con->options, fp, NULL);
|
||||
(void) singleTableUsage(con, fp, cursor, con->options, NULL);
|
||||
(void) itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
|
||||
(void) itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
|
||||
cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
|
||||
cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
|
||||
cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
|
||||
|
||||
if (con->otherHelp) {
|
||||
cursor += strlen(con->otherHelp) + 1;
|
||||
@@ -658,4 +821,3 @@ void poptSetOtherOptionHelp(poptContext con, const char * text)
|
||||
con->otherHelp = _free(con->otherHelp);
|
||||
con->otherHelp = xstrdup(text);
|
||||
}
|
||||
/*@=type@*/
|
||||
|
||||
@@ -22,14 +22,24 @@ _free(/*@only@*/ /*@null@*/ const void * p)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
isSpace(const char *ptr)
|
||||
{
|
||||
return isspace(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
/* Bit mask macros. */
|
||||
/*@-exporttype -redef @*/
|
||||
typedef unsigned int __pbm_bits;
|
||||
/*@=exporttype =redef @*/
|
||||
#define __PBM_NBITS (8 * sizeof (__pbm_bits))
|
||||
#define __PBM_IX(d) ((d) / __PBM_NBITS)
|
||||
#define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
|
||||
/*@-exporttype -redef @*/
|
||||
typedef struct {
|
||||
__pbm_bits bits[1];
|
||||
} pbm_set;
|
||||
/*@=exporttype =redef @*/
|
||||
#define __PBM_BITS(set) ((set)->bits)
|
||||
|
||||
#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
|
||||
@@ -40,37 +50,53 @@ typedef struct {
|
||||
|
||||
struct optionStackEntry {
|
||||
int argc;
|
||||
/*@only@*/ /*@null@*/ const char ** argv;
|
||||
/*@only@*/ /*@null@*/ pbm_set * argb;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char ** argv;
|
||||
/*@only@*/ /*@null@*/
|
||||
pbm_set * argb;
|
||||
int next;
|
||||
/*@only@*/ /*@null@*/ const char * nextArg;
|
||||
/*@keep@*/ /*@null@*/ const char * nextCharArg;
|
||||
/*@dependent@*/ /*@null@*/ poptItem currAlias;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char * nextArg;
|
||||
/*@observer@*/ /*@null@*/
|
||||
const char * nextCharArg;
|
||||
/*@dependent@*/ /*@null@*/
|
||||
poptItem currAlias;
|
||||
int stuffed;
|
||||
};
|
||||
|
||||
struct poptContext_s {
|
||||
struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
|
||||
/*@dependent@*/ struct optionStackEntry * os;
|
||||
/*@owned@*/ /*@null@*/ const char ** leftovers;
|
||||
/*@dependent@*/
|
||||
struct optionStackEntry * os;
|
||||
/*@owned@*/ /*@null@*/
|
||||
const char ** leftovers;
|
||||
int numLeftovers;
|
||||
int nextLeftover;
|
||||
/*@keep@*/ const struct poptOption * options;
|
||||
/*@keep@*/
|
||||
const struct poptOption * options;
|
||||
int restLeftover;
|
||||
/*@only@*/ /*@null@*/ const char * appName;
|
||||
/*@only@*/ /*@null@*/ poptItem aliases;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char * appName;
|
||||
/*@only@*/ /*@null@*/
|
||||
poptItem aliases;
|
||||
int numAliases;
|
||||
int flags;
|
||||
/*@owned@*/ /*@null@*/ poptItem execs;
|
||||
/*@owned@*/ /*@null@*/
|
||||
poptItem execs;
|
||||
int numExecs;
|
||||
/*@only@*/ /*@null@*/ const char ** finalArgv;
|
||||
/*@only@*/ /*@null@*/
|
||||
const char ** finalArgv;
|
||||
int finalArgvCount;
|
||||
int finalArgvAlloced;
|
||||
/*@dependent@*/ /*@null@*/ poptItem doExec;
|
||||
/*@only@*/ const char * execPath;
|
||||
/*@dependent@*/ /*@null@*/
|
||||
poptItem doExec;
|
||||
/*@only@*/
|
||||
const char * execPath;
|
||||
int execAbsolute;
|
||||
/*@only@*/ const char * otherHelp;
|
||||
/*@null@*/ pbm_set * arg_strip;
|
||||
/*@only@*/ /*@relnull@*/
|
||||
const char * otherHelp;
|
||||
/*@null@*/
|
||||
pbm_set * arg_strip;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
@@ -83,7 +109,7 @@ struct poptContext_s {
|
||||
#define _(foo) foo
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DGETTEXT) && !defined(__LCLINT__)
|
||||
#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
|
||||
#define D_(dom, str) dgettext(dom, str)
|
||||
#define POPT_(foo) D_("popt", foo)
|
||||
#else
|
||||
|
||||
123
popt/poptparse.c
123
popt/poptparse.c
@@ -2,14 +2,17 @@
|
||||
* \file popt/poptparse.c
|
||||
*/
|
||||
|
||||
/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
|
||||
file accompanying popt source distributions, available from
|
||||
ftp://ftp.rpm.org/pub/rpm/dist. */
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "poptint.h"
|
||||
|
||||
#define POPT_ARGV_ARRAY_GROW_DELTA 5
|
||||
|
||||
/*@-boundswrite@*/
|
||||
int poptDupArgv(int argc, const char **argv,
|
||||
int * argcPtr, const char *** argvPtr)
|
||||
{
|
||||
@@ -35,7 +38,7 @@ int poptDupArgv(int argc, const char **argv,
|
||||
/*@-branchstate@*/
|
||||
for (i = 0; i < argc; i++) {
|
||||
argv2[i] = dst;
|
||||
dst += strlen(strcpy(dst, argv[i])) + 1;
|
||||
dst += strlcpy(dst, argv[i], nb) + 1;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
argv2[argc] = NULL;
|
||||
@@ -50,11 +53,13 @@ int poptDupArgv(int argc, const char **argv,
|
||||
*argcPtr = argc;
|
||||
return 0;
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
int poptParseArgvString(const unsigned char * s, int * argcPtr, const char *** argvPtr)
|
||||
/*@-bounds@*/
|
||||
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
|
||||
{
|
||||
const unsigned char * src;
|
||||
unsigned char quote = '\0';
|
||||
const char * src;
|
||||
char quote = '\0';
|
||||
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
|
||||
const char ** argv = malloc(sizeof(*argv) * argvAlloced);
|
||||
int argc = 0;
|
||||
@@ -78,7 +83,7 @@ int poptParseArgvString(const unsigned char * s, int * argcPtr, const char *** a
|
||||
if (*src != quote) *buf++ = '\\';
|
||||
}
|
||||
*buf++ = *src;
|
||||
} else if (isspace(*src)) {
|
||||
} else if (isSpace(src)) {
|
||||
if (*argv[argc] != '\0') {
|
||||
buf++, argc++;
|
||||
if (argc == argvAlloced) {
|
||||
@@ -116,3 +121,109 @@ exit:
|
||||
if (argv) free(argv);
|
||||
return rc;
|
||||
}
|
||||
/*@=bounds@*/
|
||||
|
||||
/* still in the dev stage.
|
||||
* return values, perhaps 1== file erro
|
||||
* 2== line to long
|
||||
* 3== umm.... more?
|
||||
*/
|
||||
int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int flags))
|
||||
{
|
||||
char line[999];
|
||||
char * argstr;
|
||||
char * p;
|
||||
char * q;
|
||||
char * x;
|
||||
int t;
|
||||
int argvlen = 0;
|
||||
size_t maxlinelen = sizeof(line);
|
||||
size_t linelen;
|
||||
int maxargvlen = 480;
|
||||
int linenum = 0;
|
||||
|
||||
*argstrp = NULL;
|
||||
|
||||
/* | this_is = our_line
|
||||
* p q x
|
||||
*/
|
||||
|
||||
if (fp == NULL)
|
||||
return POPT_ERROR_NULLARG;
|
||||
|
||||
argstr = calloc(maxargvlen, sizeof(*argstr));
|
||||
if (argstr == NULL) return POPT_ERROR_MALLOC;
|
||||
|
||||
while (fgets(line, (int)maxlinelen, fp) != NULL) {
|
||||
linenum++;
|
||||
p = line;
|
||||
|
||||
/* loop until first non-space char or EOL */
|
||||
while( *p != '\0' && isSpace(p) )
|
||||
p++;
|
||||
|
||||
linelen = strlen(p);
|
||||
if (linelen >= maxlinelen-1)
|
||||
return POPT_ERROR_OVERFLOW; /* XXX line too long */
|
||||
|
||||
if (*p == '\0' || *p == '\n') continue; /* line is empty */
|
||||
if (*p == '#') continue; /* comment line */
|
||||
|
||||
q = p;
|
||||
|
||||
while (*q != '\0' && (!isSpace(q)) && *q != '=')
|
||||
q++;
|
||||
|
||||
if (isSpace(q)) {
|
||||
/* a space after the name, find next non space */
|
||||
*q++='\0';
|
||||
while( *q != '\0' && isSpace(q) ) q++;
|
||||
}
|
||||
if (*q == '\0') {
|
||||
/* single command line option (ie, no name=val, just name) */
|
||||
q[-1] = '\0'; /* kill off newline from fgets() call */
|
||||
argvlen += (t = q - p) + (sizeof(" --")-1);
|
||||
if (argvlen >= maxargvlen) {
|
||||
maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
|
||||
argstr = realloc(argstr, maxargvlen);
|
||||
if (argstr == NULL) return POPT_ERROR_MALLOC;
|
||||
}
|
||||
strlcat(argstr, " --", maxargvlen);
|
||||
strlcat(argstr, p, maxargvlen);
|
||||
continue;
|
||||
}
|
||||
if (*q != '=')
|
||||
continue; /* XXX for now, silently ignore bogus line */
|
||||
|
||||
/* *q is an equal sign. */
|
||||
*q++ = '\0';
|
||||
|
||||
/* find next non-space letter of value */
|
||||
while (*q != '\0' && isSpace(q))
|
||||
q++;
|
||||
if (*q == '\0')
|
||||
continue; /* XXX silently ignore missing value */
|
||||
|
||||
/* now, loop and strip all ending whitespace */
|
||||
x = p + linelen;
|
||||
while (isSpace(--x))
|
||||
*x = 0; /* null out last char if space (including fgets() NL) */
|
||||
|
||||
/* rest of line accept */
|
||||
t = x - p;
|
||||
argvlen += t + (sizeof("' --='")-1);
|
||||
if (argvlen >= maxargvlen) {
|
||||
maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
|
||||
argstr = realloc(argstr, maxargvlen);
|
||||
if (argstr == NULL) return POPT_ERROR_MALLOC;
|
||||
}
|
||||
strlcat(argstr, " --", maxargvlen);
|
||||
strlcat(argstr, p, maxargvlen);
|
||||
strlcat(argstr, "=\"", maxargvlen);
|
||||
strlcat(argstr, q, maxargvlen);
|
||||
strlcat(argstr, "\"", maxargvlen);
|
||||
}
|
||||
|
||||
*argstrp = argstr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined (__GLIBC__) && defined(__LCLINT__)
|
||||
/*@-declundef@*/
|
||||
/*@unchecked@*/
|
||||
extern __const __int32_t *__ctype_tolower;
|
||||
/*@unchecked@*/
|
||||
extern __const __int32_t *__ctype_toupper;
|
||||
/*@=declundef@*/
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
@@ -12,19 +22,32 @@
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#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> */
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(x)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __NeXT
|
||||
@@ -34,11 +57,12 @@
|
||||
#endif
|
||||
|
||||
#if defined(__LCLINT__)
|
||||
/*@-declundef -incondefs -redecl@*/ /* LCL: missing annotation */
|
||||
/*@only@*/ void * alloca (size_t __size)
|
||||
/*@-declundef -incondefs @*/ /* LCL: missing annotation */
|
||||
/*@only@*/ /*@out@*/
|
||||
void * alloca (size_t __size)
|
||||
/*@ensures MaxSet(result) == (__size - 1) @*/
|
||||
/*@*/;
|
||||
/*@=declundef =incondefs =redecl@*/
|
||||
/*@=declundef =incondefs @*/
|
||||
#endif
|
||||
|
||||
/* AIX requires this to be the first thing in the file. */
|
||||
@@ -49,9 +73,9 @@
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# if HAVE_ALLOCA
|
||||
# ifdef HAVE_ALLOCA
|
||||
# ifndef alloca /* predefined by HP cc +Olibcalls */
|
||||
char *alloca ();
|
||||
char *alloca(size_t size);
|
||||
# endif
|
||||
# else
|
||||
# ifdef alloca
|
||||
@@ -65,18 +89,42 @@ char *alloca ();
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
|
||||
/*@-redecl -redef@*/
|
||||
/*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str)
|
||||
/*@*/;
|
||||
/*@=redecl =redef@*/
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *d, const char *s, size_t bufsize);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
size_t strlcat(char *d, const char *s, size_t bufsize);
|
||||
#endif
|
||||
|
||||
#if HAVE_MCHECK_H && defined(__GNUC__)
|
||||
#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
|
||||
#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
|
||||
static inline char *
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
size_t memsize = strlen(s) + 1;
|
||||
char *ptr = malloc(memsize);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "virtual memory exhausted.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strlcpy(ptr, s, memsize);
|
||||
return ptr;
|
||||
}
|
||||
#else
|
||||
#define xstrdup(_str) strdup(_str)
|
||||
#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
|
||||
|
||||
#if HAVE___SECURE_GETENV && !defined(__LCLINT__)
|
||||
#define getenv(_s) __secure_getenv(_s)
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF
|
||||
#define snprintf rsync_snprintf
|
||||
int snprintf(char *str,size_t count,const char *fmt,...);
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
|
||||
#define PACKAGE "rsync"
|
||||
|
||||
#include "popt.h"
|
||||
|
||||
@@ -18,8 +18,8 @@ man: rsync.1 rsyncd.conf.5
|
||||
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 rsync.yo
|
||||
-./tweak_manpage_dashes rsync.1
|
||||
-./tweak_manpage rsync.1
|
||||
|
||||
rsyncd.conf.5: rsyncd.conf.yo
|
||||
yodl2man -o rsyncd.conf.5 rsyncd.conf.yo
|
||||
-./tweak_manpage_dashes rsyncd.conf.5
|
||||
-./tweak_manpage rsyncd.conf.5
|
||||
|
||||
26
progress.c
26
progress.c
@@ -4,11 +4,11 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -60,12 +59,11 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
|
||||
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
int is_last)
|
||||
{
|
||||
char eol[256];
|
||||
char rembuf[64], eol[128];
|
||||
const char *units;
|
||||
int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
|
||||
unsigned long diff;
|
||||
double rate, remain;
|
||||
int remain_h, remain_m, remain_s;
|
||||
|
||||
if (is_last) {
|
||||
/* Compute stats based on the starting info. */
|
||||
@@ -94,9 +92,14 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
units = "kB/s";
|
||||
}
|
||||
|
||||
remain_s = (int) remain % 60;
|
||||
remain_m = (int) (remain / 60.0) % 60;
|
||||
remain_h = (int) (remain / 3600.0);
|
||||
if (remain < 0)
|
||||
strlcpy(rembuf, " ??:??:??", sizeof rembuf);
|
||||
else {
|
||||
snprintf(rembuf, sizeof rembuf, "%4d:%02d:%02d",
|
||||
(int) (remain / 3600.0),
|
||||
(int) (remain / 60.0) % 60,
|
||||
(int) remain % 60);
|
||||
}
|
||||
|
||||
if (is_last) {
|
||||
snprintf(eol, sizeof eol, " (xfer#%d, to-check=%d/%d)\n",
|
||||
@@ -105,9 +108,8 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
stats.num_files);
|
||||
} else
|
||||
strlcpy(eol, "\r", sizeof eol);
|
||||
rprintf(FCLIENT, "%12s %3d%% %7.2f%s %4d:%02d:%02d%s",
|
||||
human_num(ofs), pct, rate, units,
|
||||
remain_h, remain_m, remain_s, eol);
|
||||
rprintf(FCLIENT, "%12s %3d%% %7.2f%s %s%s",
|
||||
human_num(ofs), pct, rate, units, rembuf, eol);
|
||||
}
|
||||
|
||||
void end_progress(OFF_T size)
|
||||
|
||||
285
receiver.c
285
receiver.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,16 +16,17 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int inc_recurse;
|
||||
extern int log_before_transfer;
|
||||
extern int stdout_format_has_i;
|
||||
extern int logfile_format_has_i;
|
||||
@@ -37,6 +38,7 @@ extern int protocol_version;
|
||||
extern int relative_paths;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_xattrs;
|
||||
extern int basis_dir_cnt;
|
||||
extern int make_backups;
|
||||
extern int cleanup_got_literal;
|
||||
@@ -47,20 +49,19 @@ extern int keep_partial;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
extern int delay_updates;
|
||||
extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
extern char *stdout_format;
|
||||
extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[];
|
||||
extern struct file_list *the_file_list;
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
|
||||
static struct bitbag *delayed_bits = NULL;
|
||||
static int phase = 0;
|
||||
static int phase = 0, redoing = 0;
|
||||
/* We're either updating the basis file or an identical copy: */
|
||||
static int updating_basis;
|
||||
|
||||
|
||||
/*
|
||||
* get_tmpname() - create a tmp filename for a given filename
|
||||
*
|
||||
@@ -82,7 +83,7 @@ static int updating_basis;
|
||||
* As long as it's unique, rsync will work.
|
||||
*/
|
||||
|
||||
static int get_tmpname(char *fnametmp, char *fname)
|
||||
int get_tmpname(char *fnametmp, char *fname)
|
||||
{
|
||||
int maxname, added, length = 0;
|
||||
char *f;
|
||||
@@ -124,13 +125,13 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
|
||||
|
||||
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
char *fname, int fd, OFF_T total_size)
|
||||
const char *fname, int fd, OFF_T total_size)
|
||||
{
|
||||
static char file_sum1[MD4_SUM_LENGTH];
|
||||
static char file_sum2[MD4_SUM_LENGTH];
|
||||
static char file_sum1[MAX_DIGEST_LEN];
|
||||
static char file_sum2[MAX_DIGEST_LEN];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
int32 len;
|
||||
int32 len, sum_len;
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
@@ -151,25 +152,27 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (append_mode) {
|
||||
if (append_mode > 0) {
|
||||
OFF_T j;
|
||||
sum.flength = (OFF_T)sum.count * sum.blength;
|
||||
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;
|
||||
if (append_mode == 2) {
|
||||
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 = (int32)(sum.flength - offset);
|
||||
if (do_progress)
|
||||
show_progress(offset, total_size);
|
||||
sum_update(map_ptr(mapbuf, offset, len), len);
|
||||
}
|
||||
}
|
||||
offset = sum.flength;
|
||||
if (fd != -1 && (j = do_lseek(fd, offset, SEEK_SET)) != offset) {
|
||||
rsyserr(FERROR, errno, "lseek of %s returned %.0f, not %.0f",
|
||||
full_fname(fname), (double)j, (double)offset);
|
||||
@@ -258,15 +261,15 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
sum_end(file_sum1);
|
||||
sum_len = sum_end(file_sum1);
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
|
||||
read_buf(f_in, file_sum2, sum_len);
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"got file_sum\n");
|
||||
if (fd != -1 && memcmp(file_sum1, file_sum2, MD4_SUM_LENGTH) != 0)
|
||||
if (fd != -1 && memcmp(file_sum1, file_sum2, sum_len) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -277,16 +280,16 @@ static void discard_receive_data(int f_in, OFF_T length)
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
|
||||
}
|
||||
|
||||
static void handle_delayed_updates(struct file_list *flist, char *local_name)
|
||||
static void handle_delayed_updates(char *local_name)
|
||||
{
|
||||
char *fname, *partialptr, numbuf[4];
|
||||
int i;
|
||||
char *fname, *partialptr;
|
||||
int ndx;
|
||||
|
||||
for (i = -1; (i = bitbag_next_bit(delayed_bits, i)) >= 0; ) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
for (ndx = -1; (ndx = bitbag_next_bit(delayed_bits, ndx)) >= 0; ) {
|
||||
struct file_struct *file = cur_flist->files[ndx];
|
||||
fname = local_name ? local_name : f_name(file, NULL);
|
||||
if ((partialptr = partial_dir_fname(fname)) != NULL) {
|
||||
if (make_backups && !make_backup(fname))
|
||||
if (make_backups > 0 && !make_backup(fname))
|
||||
continue;
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "renaming %s to %s\n",
|
||||
@@ -300,111 +303,118 @@ static void handle_delayed_updates(struct file_list *flist, char *local_name)
|
||||
full_fname(fname), partialptr);
|
||||
} else {
|
||||
if (remove_source_files
|
||||
|| (preserve_hard_links
|
||||
&& file->link_u.links)) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_SUCCESS,numbuf,4);
|
||||
}
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i)
|
||||
static int get_next_gen_ndx(int fd, int next_gen_ndx, int desired_ndx)
|
||||
{
|
||||
while (next_gen_i < desired_i) {
|
||||
if (next_gen_i >= 0) {
|
||||
while (next_gen_ndx < desired_ndx) {
|
||||
if (next_gen_ndx >= 0) {
|
||||
rprintf(FINFO,
|
||||
"(No batched update for%s \"%s\")\n",
|
||||
phase ? " resend of" : "",
|
||||
f_name(the_file_list->files[next_gen_i], NULL));
|
||||
redoing ? " resend of" : "",
|
||||
f_name(cur_flist->files[next_gen_ndx], NULL));
|
||||
}
|
||||
next_gen_ndx = read_int(fd);
|
||||
if (next_gen_ndx == -1) {
|
||||
if (inc_recurse)
|
||||
next_gen_ndx = first_flist->prev->used + first_flist->prev->ndx_start;
|
||||
else
|
||||
next_gen_ndx = cur_flist->used;
|
||||
}
|
||||
next_gen_i = read_int(batch_gen_fd);
|
||||
if (next_gen_i == -1)
|
||||
next_gen_i = the_file_list->count;
|
||||
}
|
||||
return next_gen_i;
|
||||
return next_gen_ndx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* main routine for receiver process.
|
||||
*
|
||||
* Receiver process runs on the same host as the generator process. */
|
||||
int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
int recv_files(int f_in, char *local_name)
|
||||
{
|
||||
int next_gen_i = -1;
|
||||
int next_gen_ndx = -1;
|
||||
int fd1,fd2;
|
||||
STRUCT_STAT st;
|
||||
int iflags, xlen;
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char xname[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnamecmp, *partialptr, numbuf[4];
|
||||
char *fnamecmp, *partialptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
uchar fnamecmp_type;
|
||||
struct file_struct *file;
|
||||
struct stats initial_stats;
|
||||
int save_make_backups = make_backups;
|
||||
int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
|
||||
enum logcode log_code = log_before_transfer ? FLOG : FINFO;
|
||||
int max_phase = protocol_version >= 29 ? 2 : 1;
|
||||
int i, recv_ok;
|
||||
int dflt_perms = (ACCESSPERMS & ~orig_umask);
|
||||
#ifdef SUPPORT_ACLS
|
||||
const char *parent_dirname = "";
|
||||
#endif
|
||||
int ndx, recv_ok;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
|
||||
|
||||
if (flist->hlink_pool) {
|
||||
pool_destroy(flist->hlink_pool);
|
||||
flist->hlink_pool = NULL;
|
||||
}
|
||||
rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
|
||||
|
||||
if (delay_updates)
|
||||
delayed_bits = bitbag_create(flist->count);
|
||||
delayed_bits = bitbag_create(cur_flist->used + 1);
|
||||
|
||||
updating_basis = inplace;
|
||||
|
||||
while (1) {
|
||||
cleanup_disable();
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
if (read_batch) {
|
||||
get_next_gen_i(batch_gen_fd, next_gen_i,
|
||||
flist->count);
|
||||
next_gen_i = -1;
|
||||
/* This call also sets cur_flist. */
|
||||
ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (ndx == NDX_DONE) {
|
||||
if (inc_recurse && first_flist) {
|
||||
flist_free(first_flist);
|
||||
if (first_flist)
|
||||
continue;
|
||||
}
|
||||
if (read_batch && cur_flist) {
|
||||
int high = inc_recurse
|
||||
? first_flist->prev->used + first_flist->prev->ndx_start
|
||||
: cur_flist->used;
|
||||
get_next_gen_ndx(batch_gen_fd, next_gen_ndx, high);
|
||||
next_gen_ndx = -1;
|
||||
}
|
||||
if (++phase > max_phase)
|
||||
break;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files phase=%d\n", phase);
|
||||
if (phase == 2 && delay_updates)
|
||||
handle_delayed_updates(flist, local_name);
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = 0; /* prevents double backup */
|
||||
if (append_mode) {
|
||||
append_mode = 0;
|
||||
sparse_files = 0;
|
||||
}
|
||||
handle_delayed_updates(local_name);
|
||||
send_msg(MSG_DONE, "", 0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
iflags = read_item_attrs(f_in, -1, i, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (iflags == ITEM_IS_NEW) /* no-op packet */
|
||||
continue;
|
||||
|
||||
file = flist->files[i];
|
||||
if (ndx - cur_flist->ndx_start >= 0)
|
||||
file = cur_flist->files[ndx - cur_flist->ndx_start];
|
||||
else
|
||||
file = dir_flist->files[cur_flist->parent_ndx];
|
||||
fname = local_name ? local_name : f_name(file, fbuf);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files(%s)\n", fname);
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
recv_xattr_request(file, f_in);
|
||||
#endif
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
set_file_attrs(fname, file, NULL, fname, 0);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (phase == 2) {
|
||||
@@ -414,9 +424,31 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
stats.current_file_index = i;
|
||||
if (file->flags & FLAG_FILE_SENT) {
|
||||
if (csum_length == SHORT_SUM_LENGTH) {
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = -make_backups; /* prevents double backup */
|
||||
if (append_mode)
|
||||
sparse_files = -sparse_files;
|
||||
append_mode = -append_mode;
|
||||
csum_length = SUM_LENGTH;
|
||||
redoing = 1;
|
||||
}
|
||||
} else {
|
||||
if (csum_length != SHORT_SUM_LENGTH) {
|
||||
if (keep_partial && !partial_dir)
|
||||
make_backups = -make_backups;
|
||||
if (append_mode)
|
||||
sparse_files = -sparse_files;
|
||||
append_mode = -append_mode;
|
||||
csum_length = SHORT_SUM_LENGTH;
|
||||
redoing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
stats.current_file_index = ndx;
|
||||
stats.num_transferred_files++;
|
||||
stats.total_transferred_size += file->length;
|
||||
stats.total_transferred_size += F_LENGTH(file);
|
||||
cleanup_got_literal = 0;
|
||||
|
||||
if (server_filter_list.head
|
||||
@@ -428,26 +460,28 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
log_item(FCLIENT, file, &stats, iflags, NULL);
|
||||
if (read_batch)
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
continue;
|
||||
}
|
||||
if (write_batch < 0) {
|
||||
log_item(FINFO, file, &stats, iflags, NULL);
|
||||
if (!am_server)
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
next_gen_i = get_next_gen_i(batch_gen_fd, next_gen_i, i);
|
||||
if (i < next_gen_i) {
|
||||
next_gen_ndx = get_next_gen_ndx(batch_gen_fd, next_gen_ndx, ndx);
|
||||
if (ndx < next_gen_ndx) {
|
||||
rprintf(FINFO,
|
||||
"(Skipping batched update for \"%s\")\n",
|
||||
fname);
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
next_gen_i = -1;
|
||||
next_gen_ndx = -1;
|
||||
}
|
||||
|
||||
partialptr = partial_dir ? partial_dir_fname(fname) : fname;
|
||||
@@ -491,7 +525,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
} else {
|
||||
/* Reminder: --inplace && --partial-dir are never
|
||||
* enabled at the same time. */
|
||||
if (inplace && make_backups) {
|
||||
if (inplace && make_backups > 0) {
|
||||
if (!(fnamecmp = get_backup_name(fname)))
|
||||
fnamecmp = fname;
|
||||
} else if (partial_dir && partialptr)
|
||||
@@ -526,8 +560,10 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
} else if (do_fstat(fd1,&st) != 0) {
|
||||
rsyserr(FERROR, errno, "fstat %s failed",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -539,8 +575,10 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
*/
|
||||
rprintf(FERROR,"recv_files: %s is a directory\n",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -553,7 +591,16 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
* 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);
|
||||
#ifdef SUPPORT_ACLS
|
||||
const char *dn = file->dirname ? file->dirname : ".";
|
||||
if (parent_dirname != dn
|
||||
&& strcmp(parent_dirname, dn) != 0) {
|
||||
dflt_perms = default_perms_for_dir(dn);
|
||||
parent_dirname = dn;
|
||||
}
|
||||
#endif
|
||||
file->mode = dest_mode(file->mode, st.st_mode,
|
||||
dflt_perms, exists);
|
||||
}
|
||||
|
||||
/* We now check to see if we are writing the file "inplace" */
|
||||
@@ -562,16 +609,20 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "open %s failed",
|
||||
full_fname(fname));
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -595,9 +646,11 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "mkstemp %s failed",
|
||||
full_fname(fnametmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -612,7 +665,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
fname, fd2, file->length);
|
||||
fname, fd2, F_LENGTH(file));
|
||||
|
||||
log_item(log_code, file, &initial_stats, iflags, NULL);
|
||||
|
||||
@@ -632,18 +685,18 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
temp_copy_name = NULL;
|
||||
else
|
||||
temp_copy_name = partialptr;
|
||||
finish_transfer(fname, fnametmp, temp_copy_name,
|
||||
file, recv_ok, 1);
|
||||
finish_transfer(fname, fnametmp, fnamecmp,
|
||||
temp_copy_name, 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, NULL,
|
||||
finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
|
||||
file, recv_ok, !partial_dir);
|
||||
if (delay_updates && recv_ok) {
|
||||
bitbag_set_bit(delayed_bits, i);
|
||||
bitbag_set_bit(delayed_bits, ndx);
|
||||
recv_ok = -1;
|
||||
}
|
||||
} else {
|
||||
@@ -654,13 +707,11 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
cleanup_disable();
|
||||
|
||||
if (recv_ok > 0) {
|
||||
if (remove_source_files
|
||||
|| (preserve_hard_links && file->link_u.links)) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_SUCCESS, numbuf, 4);
|
||||
}
|
||||
if (remove_source_files || inc_recurse
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
} else if (!recv_ok) {
|
||||
int msgtype = phase || read_batch ? FERROR : FINFO;
|
||||
enum logcode msgtype = redoing || read_batch ? FERROR : FINFO;
|
||||
if (msgtype == FERROR || verbose) {
|
||||
char *errstr, *redostr, *keptstr;
|
||||
if (!(keep_partial && partialptr) && !inplace)
|
||||
@@ -680,16 +731,18 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
"%s: %s failed verification -- update %s%s.\n",
|
||||
errstr, fname, keptstr, redostr);
|
||||
}
|
||||
if (!phase) {
|
||||
SIVAL(numbuf, 0, i);
|
||||
send_msg(MSG_REDO, numbuf, 4);
|
||||
}
|
||||
if (!redoing) {
|
||||
send_msg_int(MSG_REDO, ndx);
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
} else if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
}
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
if (make_backups < 0)
|
||||
make_backups = -make_backups;
|
||||
|
||||
if (phase == 2 && delay_updates) /* for protocol_version < 29 */
|
||||
handle_delayed_updates(flist, local_name);
|
||||
handle_delayed_updates(local_name);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files finished\n");
|
||||
|
||||
404
rsync.c
404
rsync.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,14 +16,11 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#include "ifuncs.h"
|
||||
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
#include <libcharset.h>
|
||||
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
@@ -32,43 +29,57 @@
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_executability;
|
||||
extern int preserve_times;
|
||||
extern int omit_dir_times;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int am_starting_up;
|
||||
extern int allow_8bit_chars;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int protocol_version;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int inc_recurse;
|
||||
extern int inplace;
|
||||
extern int flist_eof;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern struct chmod_mode_struct *daemon_chmod_modes;
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#ifdef ICONV_CONST
|
||||
iconv_t ic_chck = (iconv_t)-1;
|
||||
# ifdef ICONV_OPTION
|
||||
iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
|
||||
# endif
|
||||
|
||||
static const char *default_charset(void)
|
||||
{
|
||||
#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
# if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
return locale_charset();
|
||||
#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
# elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
|
||||
return nl_langinfo(CODESET);
|
||||
#else
|
||||
# else
|
||||
return ""; /* Works with (at the very least) gnu iconv... */
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
|
||||
void setup_iconv()
|
||||
void setup_iconv(void)
|
||||
{
|
||||
const char *defset = default_charset();
|
||||
# ifdef ICONV_OPTION
|
||||
const char *charset;
|
||||
char *cp;
|
||||
# endif
|
||||
|
||||
if (!am_server && !allow_8bit_chars) {
|
||||
const char *defset = default_charset();
|
||||
|
||||
/* It's OK if this fails... */
|
||||
ic_chck = iconv_open(defset, defset);
|
||||
@@ -86,9 +97,210 @@ void setup_iconv()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef ICONV_OPTION
|
||||
if (!iconv_opt)
|
||||
return;
|
||||
|
||||
if ((cp = strchr(iconv_opt, ',')) != NULL) {
|
||||
if (am_server) /* A local transfer needs this. */
|
||||
iconv_opt = cp + 1;
|
||||
else
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if (!*iconv_opt || (*iconv_opt == '.' && iconv_opt[1] == '\0'))
|
||||
charset = defset;
|
||||
else
|
||||
charset = iconv_opt;
|
||||
|
||||
if ((ic_send = iconv_open(UTF8_CHARSET, charset)) == (iconv_t)-1) {
|
||||
rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n",
|
||||
UTF8_CHARSET, charset);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if ((ic_recv = iconv_open(charset, UTF8_CHARSET)) == (iconv_t)-1) {
|
||||
rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n",
|
||||
charset, UTF8_CHARSET);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "%s charset: %s\n",
|
||||
am_server ? "server" : "client",
|
||||
*charset ? charset : "[LOCALE]");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef ICONV_OPTION
|
||||
|
||||
/* This function converts the characters in the "in" xbuf into characters
|
||||
* in the "out" xbuf. The "len" of the "in" xbuf is used starting from its
|
||||
* "pos". The "size" of the "out" xbuf restricts how many characters can be
|
||||
* stored, starting at its "pos+len" position. Note that the last byte of
|
||||
* the buffer is never used, which reserves space for a terminating '\0'.
|
||||
* We return a 0 on success or a -1 on error. An error also sets errno to
|
||||
* E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0.
|
||||
* The "in" xbuf is altered to update "pos" and "len". The "out" xbuf has
|
||||
* data appended, and its "len" incremented. If ICB_EXPAND_OUT is set in
|
||||
* "flags", the "out" xbuf will also be allocated if empty, and expanded if
|
||||
* too small (so E2BIG will not be returned). If ICB_INCLUDE_BAD is set in
|
||||
* "flags", any badly-encoded chars are included verbatim in the "out" xbuf,
|
||||
* so EILSEQ will not be returned. Likewise for ICB_INCLUDE_INCOMPLETE with
|
||||
* respect to an incomplete multi-byte char at the end, which ensures that
|
||||
* EINVAL is not returned. Anytime "in.pos" is 0 we will reset the iconv()
|
||||
* state prior to processing the characters. */
|
||||
int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
|
||||
{
|
||||
ICONV_CONST char *ibuf;
|
||||
size_t icnt, ocnt;
|
||||
char *obuf;
|
||||
|
||||
if (!out->size && flags & ICB_EXPAND_OUT)
|
||||
alloc_xbuf(out, 1024);
|
||||
|
||||
if (!in->pos)
|
||||
iconv(ic, NULL, 0, NULL, 0);
|
||||
|
||||
ibuf = in->buf + in->pos;
|
||||
icnt = in->len;
|
||||
|
||||
obuf = out->buf + (out->pos + out->len);
|
||||
ocnt = out->size - (out->pos + out->len) - 1;
|
||||
|
||||
while (icnt) {
|
||||
while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EINVAL) {
|
||||
if (!(flags & ICB_INCLUDE_INCOMPLETE))
|
||||
goto finish;
|
||||
} else if (errno == EILSEQ) {
|
||||
if (!(flags & ICB_INCLUDE_BAD))
|
||||
goto finish;
|
||||
} else {
|
||||
size_t opos = obuf - out->buf;
|
||||
if (!(flags & ICB_EXPAND_OUT)) {
|
||||
errno = E2BIG;
|
||||
goto finish;
|
||||
}
|
||||
realloc_xbuf(out, out->size + 1024);
|
||||
obuf = out->buf + opos;
|
||||
ocnt += 1024;
|
||||
continue;
|
||||
}
|
||||
*obuf++ = *ibuf++;
|
||||
ocnt--, icnt--;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
finish:
|
||||
in->len = icnt;
|
||||
in->pos = ibuf - in->buf;
|
||||
out->len = obuf - out->buf - out->pos;
|
||||
|
||||
return errno ? -1 : 0;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
|
||||
char *buf, int *len_ptr)
|
||||
{
|
||||
int len, iflags = 0;
|
||||
struct file_list *flist;
|
||||
uchar fnamecmp_type = FNAMECMP_FNAME;
|
||||
int ndx;
|
||||
|
||||
read_loop:
|
||||
while (1) {
|
||||
ndx = read_ndx(f_in);
|
||||
|
||||
if (ndx >= 0)
|
||||
break;
|
||||
if (ndx == NDX_DONE)
|
||||
return ndx;
|
||||
if (!inc_recurse || am_sender)
|
||||
goto invalid_ndx;
|
||||
if (ndx == NDX_FLIST_EOF) {
|
||||
flist_eof = 1;
|
||||
send_msg(MSG_FLIST_EOF, "", 0, 0);
|
||||
continue;
|
||||
}
|
||||
ndx = NDX_FLIST_OFFSET - ndx;
|
||||
if (ndx < 0 || ndx >= dir_flist->used) {
|
||||
ndx = NDX_FLIST_OFFSET - ndx;
|
||||
rprintf(FERROR,
|
||||
"[%s] Invalid dir index: %d (%d - %d)\n",
|
||||
who_am_i(), ndx, NDX_FLIST_OFFSET,
|
||||
NDX_FLIST_OFFSET - dir_flist->used + 1);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
/* Send everything read from f_in to msg_fd_out. */
|
||||
send_msg_int(MSG_FLIST, ndx);
|
||||
start_flist_forward(f_in);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
|
||||
who_am_i(), ndx);
|
||||
}
|
||||
flist = recv_file_list(f_in);
|
||||
flist->parent_ndx = ndx;
|
||||
stop_flist_forward();
|
||||
}
|
||||
|
||||
iflags = protocol_version >= 29 ? read_shortint(f_in)
|
||||
: ITEM_TRANSFER | ITEM_MISSING_DATA;
|
||||
|
||||
/* Honor the old-style keep-alive indicator. */
|
||||
if (protocol_version < 30
|
||||
&& ndx == cur_flist->used && iflags == ITEM_IS_NEW) {
|
||||
if (am_sender)
|
||||
maybe_send_keepalive();
|
||||
goto read_loop;
|
||||
}
|
||||
|
||||
if (!(flist = flist_for_ndx(ndx))) {
|
||||
invalid_ndx:
|
||||
rprintf(FERROR,
|
||||
"Invalid file index: %d (%d - %d) with iflags %x [%s]\n",
|
||||
ndx, first_flist->ndx_start - 1, first_flist->prev->ndx_end,
|
||||
iflags, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
cur_flist = flist;
|
||||
|
||||
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
|
||||
fnamecmp_type = read_byte(f_in);
|
||||
*type_ptr = fnamecmp_type;
|
||||
|
||||
if (iflags & ITEM_XNAME_FOLLOWS) {
|
||||
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else {
|
||||
*buf = '\0';
|
||||
len = -1;
|
||||
}
|
||||
*len_ptr = len;
|
||||
|
||||
if (iflags & ITEM_TRANSFER) {
|
||||
int i = ndx - cur_flist->ndx_start;
|
||||
if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) {
|
||||
rprintf(FERROR,
|
||||
"received request to transfer non-regular file: %d [%s]\n",
|
||||
ndx, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
*iflag_ptr = iflags;
|
||||
return ndx;
|
||||
}
|
||||
|
||||
/*
|
||||
free a sums struct
|
||||
*/
|
||||
@@ -100,7 +312,8 @@ void free_sums(struct sum_struct *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 stat_mode, int exists)
|
||||
mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
|
||||
int exists)
|
||||
{
|
||||
int new_mode;
|
||||
/* If the file already exists, we'll return the local permissions,
|
||||
@@ -117,56 +330,78 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists)
|
||||
new_mode |= (new_mode & 0444) >> 2;
|
||||
}
|
||||
} else {
|
||||
/* Apply the umask and turn off special permissions. */
|
||||
new_mode = flist_mode & (~CHMOD_BITS | (ACCESSPERMS & ~orig_umask));
|
||||
/* Apply destination default permissions and turn
|
||||
* off special permissions. */
|
||||
new_mode = flist_mode & (~CHMOD_BITS | dflt_perms);
|
||||
}
|
||||
return new_mode;
|
||||
}
|
||||
|
||||
int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
|
||||
int flags)
|
||||
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
const char *fnamecmp, int flags)
|
||||
{
|
||||
int updated = 0;
|
||||
STRUCT_STAT st2;
|
||||
stat_x sx2;
|
||||
int change_uid, change_gid;
|
||||
mode_t new_mode = file->mode;
|
||||
int inherit;
|
||||
|
||||
if (!st) {
|
||||
if (!sxp) {
|
||||
if (dry_run)
|
||||
return 1;
|
||||
if (link_stat(fname, &st2, 0) < 0) {
|
||||
if (link_stat(fname, &sx2.st, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
st = &st2;
|
||||
if (!preserve_perms && S_ISDIR(new_mode)
|
||||
&& st->st_mode & S_ISGID) {
|
||||
/* We just created this directory and its setgid
|
||||
* bit is on, so make sure it stays on. */
|
||||
new_mode |= S_ISGID;
|
||||
}
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx2.acc_acl = sx2.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx2.xattr = NULL;
|
||||
#endif
|
||||
sxp = &sx2;
|
||||
inherit = !preserve_perms;
|
||||
} else
|
||||
inherit = !preserve_perms && file->flags & FLAG_DIR_CREATED;
|
||||
|
||||
if (inherit && S_ISDIR(new_mode) && sxp->st.st_mode & S_ISGID) {
|
||||
/* We just created this directory and its setgid
|
||||
* bit is on, so make sure it stays on. */
|
||||
new_mode |= S_ISGID;
|
||||
}
|
||||
|
||||
if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
|
||||
get_acl(fname, sxp);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && fnamecmp)
|
||||
set_xattr(fname, file, fnamecmp, sxp);
|
||||
if (am_root < 0)
|
||||
set_stat_xattr(fname, file);
|
||||
#endif
|
||||
|
||||
if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && preserve_times == 1))
|
||||
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);
|
||||
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
|
||||
int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR, errno, "failed to set times on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
}
|
||||
|
||||
change_uid = am_root && preserve_uid && st->st_uid != file->uid;
|
||||
change_gid = preserve_gid && file->gid != GID_NONE
|
||||
&& st->st_gid != file->gid;
|
||||
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
|
||||
change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
|
||||
&& sxp->st.st_gid != (gid_t)F_GROUP(file);
|
||||
#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
|
||||
if (S_ISLNK(st->st_mode))
|
||||
if (S_ISLNK(sxp->st.st_mode))
|
||||
;
|
||||
else
|
||||
#endif
|
||||
@@ -174,47 +409,59 @@ int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
|
||||
if (verbose > 2) {
|
||||
if (change_uid) {
|
||||
rprintf(FINFO,
|
||||
"set uid of %s from %ld to %ld\n",
|
||||
fname,
|
||||
(long)st->st_uid, (long)file->uid);
|
||||
"set uid of %s from %u to %u\n",
|
||||
fname, (unsigned)sxp->st.st_uid, F_OWNER(file));
|
||||
}
|
||||
if (change_gid) {
|
||||
rprintf(FINFO,
|
||||
"set gid of %s from %ld to %ld\n",
|
||||
fname,
|
||||
(long)st->st_gid, (long)file->gid);
|
||||
"set gid of %s from %u to %u\n",
|
||||
fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
|
||||
}
|
||||
}
|
||||
if (do_lchown(fname,
|
||||
change_uid ? file->uid : st->st_uid,
|
||||
change_gid ? file->gid : st->st_gid) != 0) {
|
||||
if (am_root < 0) {
|
||||
;
|
||||
} else if (do_lchown(fname,
|
||||
change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
|
||||
change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
|
||||
/* shouldn't have attempted to change uid or gid
|
||||
* unless have the privilege */
|
||||
rsyserr(FERROR, errno, "%s %s failed",
|
||||
change_uid ? "chown" : "chgrp",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
goto cleanup;
|
||||
} else
|
||||
/* a lchown had been done - we have to re-stat if the
|
||||
* destination had the setuid or setgid bits set due
|
||||
* to the side effect of the chown call */
|
||||
if (st->st_mode & (S_ISUID | S_ISGID)) {
|
||||
link_stat(fname, st,
|
||||
keep_dirlinks && S_ISDIR(st->st_mode));
|
||||
if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
|
||||
link_stat(fname, &sxp->st,
|
||||
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
|
||||
}
|
||||
updated = 1;
|
||||
}
|
||||
|
||||
if (daemon_chmod_modes && !S_ISLNK(new_mode))
|
||||
new_mode = tweak_mode(new_mode, daemon_chmod_modes);
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
/* It's OK to call set_acl() now, even for a dir, as the generator
|
||||
* will enable owner-writability using chmod, if necessary.
|
||||
*
|
||||
* If set_acl() changes permission bits in the process of setting
|
||||
* an access ACL, it changes sxp->st.st_mode so we know whether we
|
||||
* need to chmod(). */
|
||||
if (preserve_acls && !S_ISLNK(new_mode) && set_acl(fname, file, sxp) == 0)
|
||||
updated = 1;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHMOD
|
||||
if ((st->st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
|
||||
int ret = do_chmod(fname, new_mode);
|
||||
if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
|
||||
int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to set permissions on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
@@ -227,6 +474,17 @@ int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
|
||||
else
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
}
|
||||
cleanup:
|
||||
if (sxp == &sx2) {
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls)
|
||||
free_acl(&sx2);
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
free_xattr(&sx2);
|
||||
#endif
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
@@ -248,7 +506,8 @@ RETSIGTYPE sig_int(UNUSED(int val))
|
||||
* 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,
|
||||
void finish_transfer(const char *fname, const char *fnametmp,
|
||||
const char *fnamecmp, const char *partialptr,
|
||||
struct file_struct *file, int ok_to_set_time,
|
||||
int overwriting_basis)
|
||||
{
|
||||
@@ -261,11 +520,11 @@ void finish_transfer(char *fname, char *fnametmp, char *partialptr,
|
||||
goto do_set_file_attrs;
|
||||
}
|
||||
|
||||
if (make_backups && overwriting_basis && !make_backup(fname))
|
||||
if (make_backups > 0 && overwriting_basis && !make_backup(fname))
|
||||
return;
|
||||
|
||||
/* Change permissions before putting the file into place. */
|
||||
set_file_attrs(fnametmp, file, NULL,
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
|
||||
/* move tmp file over real file */
|
||||
@@ -289,7 +548,7 @@ void finish_transfer(char *fname, char *fnametmp, char *partialptr,
|
||||
fnametmp = partialptr ? partialptr : fname;
|
||||
|
||||
do_set_file_attrs:
|
||||
set_file_attrs(fnametmp, file, NULL,
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
|
||||
if (partialptr) {
|
||||
@@ -301,6 +560,25 @@ void finish_transfer(char *fname, char *fnametmp, char *partialptr,
|
||||
}
|
||||
}
|
||||
|
||||
struct file_list *flist_for_ndx(int ndx)
|
||||
{
|
||||
struct file_list *flist = cur_flist;
|
||||
|
||||
if (!flist && !(flist = first_flist))
|
||||
return NULL;
|
||||
|
||||
while (ndx < flist->ndx_start-1) {
|
||||
if (flist == first_flist)
|
||||
return NULL;
|
||||
flist = flist->prev;
|
||||
}
|
||||
while (ndx > flist->ndx_end) {
|
||||
if (!(flist = flist->next))
|
||||
return NULL;
|
||||
}
|
||||
return flist;
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
{
|
||||
if (am_starting_up)
|
||||
|
||||
419
rsync.h
419
rsync.h
@@ -2,11 +2,11 @@
|
||||
* Copyright (C) 1996, 2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#define False 0
|
||||
@@ -43,31 +42,55 @@
|
||||
|
||||
#define XMIT_TOP_DIR (1<<0)
|
||||
#define XMIT_SAME_MODE (1<<1)
|
||||
#define XMIT_EXTENDED_FLAGS (1<<2)
|
||||
#define XMIT_SAME_RDEV_pre28 XMIT_EXTENDED_FLAGS /* Only in protocols < 28 */
|
||||
#define XMIT_SAME_RDEV_pre28 (1<<2) /* protocols 20 - 27 */
|
||||
#define XMIT_EXTENDED_FLAGS (1<<2) /* protocols 28 - now */
|
||||
#define XMIT_SAME_UID (1<<3)
|
||||
#define XMIT_SAME_GID (1<<4)
|
||||
#define XMIT_SAME_NAME (1<<5)
|
||||
#define XMIT_LONG_NAME (1<<6)
|
||||
#define XMIT_SAME_TIME (1<<7)
|
||||
#define XMIT_SAME_RDEV_MAJOR (1<<8)
|
||||
#define XMIT_HAS_IDEV_DATA (1<<9)
|
||||
#define XMIT_SAME_DEV (1<<10)
|
||||
#define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
|
||||
#define XMIT_SAME_RDEV_MAJOR (1<<8) /* protocols 28 - now (devices only) */
|
||||
#define XMIT_NO_CONTENT_DIR (1<<8) /* protocols 30 - now (dirs only) */
|
||||
#define XMIT_HLINKED (1<<9) /* protocols 28 - now */
|
||||
#define XMIT_SAME_DEV_pre30 (1<<10) /* protocols 28 - 29 */
|
||||
#define XMIT_USER_NAME_FOLLOWS (1<<10) /* protocols 30 - now */
|
||||
#define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
|
||||
#define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
|
||||
#define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
|
||||
|
||||
/* 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/generator */
|
||||
#define FLAG_DEL_HERE (1<<3) /* receiver/generator */
|
||||
#define FLAG_HLINK_TOL (1<<4) /* receiver/generator */
|
||||
#define FLAG_NO_FUZZY (1<<5) /* generator */
|
||||
#define FLAG_MISSING (1<<6) /* generator */
|
||||
#define FLAG_TOP_DIR (1<<0) /* sender/receiver/generator */
|
||||
#define FLAG_FILE_SENT (1<<1) /* sender/receiver/generator */
|
||||
#define FLAG_DIR_CREATED (1<<1) /* generator */
|
||||
#define FLAG_CONTENT_DIR (1<<2) /* sender/receiver/generator */
|
||||
#define FLAG_MOUNT_DIR (1<<3) /* sender/generator */
|
||||
#define FLAG_DUPLICATE (1<<4) /* sender */
|
||||
#define FLAG_MISSING_DIR (1<<4) /* generator */
|
||||
#define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */
|
||||
#define FLAG_HLINK_FIRST (1<<6) /* receiver/generator (w/FLAG_HLINKED) */
|
||||
#define FLAG_IMPLIED_DIR (1<<6) /* sender/receiver/generator (dirs only) */
|
||||
#define FLAG_HLINK_LAST (1<<7) /* receiver/generator */
|
||||
#define FLAG_HLINK_DONE (1<<8) /* receiver/generator (checked on all types) */
|
||||
#define FLAG_LENGTH64 (1<<9) /* sender/receiver/generator */
|
||||
#define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */
|
||||
|
||||
/* These flags are passed to functions but not stored. */
|
||||
|
||||
#define FLAG_DIVERT_DIRS (1<<16)/* sender */
|
||||
|
||||
#define BITS_SET(val,bits) (((val) & (bits)) == (bits))
|
||||
#define BITS_SETnUNSET(val,onbits,offbits) (((val) & ((onbits)|(offbits))) == (onbits))
|
||||
#define BITS_EQUAL(b1,b2,mask) (((unsigned)(b1) & (unsigned)(mask)) \
|
||||
== ((unsigned)(b2) & (unsigned)(mask)))
|
||||
|
||||
/* update this if you make incompatible changes */
|
||||
#define PROTOCOL_VERSION 29
|
||||
#define PROTOCOL_VERSION 30
|
||||
|
||||
/* This is used when working on a new protocol version in CVS, and should
|
||||
* be a new non-zero value for each CVS change that affects the protocol.
|
||||
* It must ALWAYS be 0 when the protocol goes final! */
|
||||
#define SUBPROTOCOL_VERSION 10
|
||||
|
||||
/* We refuse to interoperate with versions that are not in this range.
|
||||
* Note that we assume we'll work with later versions: the onus is on
|
||||
@@ -90,6 +113,8 @@
|
||||
#define OLD_PROTOCOL_VERSION 25
|
||||
#define MAX_PROTOCOL_VERSION 40
|
||||
|
||||
#define FILECNT_LOOKAHEAD 1000
|
||||
|
||||
#define RSYNC_PORT 873
|
||||
|
||||
#define SPARSE_WRITE_SIZE (1024)
|
||||
@@ -153,6 +178,7 @@
|
||||
/* These are outside the range of the transmitted flags. */
|
||||
#define ITEM_MISSING_DATA (1<<16) /* used by log_formatted() */
|
||||
#define ITEM_DELETED (1<<17) /* used by log_formatted() */
|
||||
#define ITEM_MATCHED (1<<18) /* used by itemize() */
|
||||
|
||||
#define SIGNIFICANT_ITEM_FLAGS (~(\
|
||||
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
|
||||
@@ -168,13 +194,22 @@ enum logcode { FNONE=0, FERROR=1, FINFO=2, FLOG=3, FCLIENT=4, FSOCKERR=5 };
|
||||
enum msgcode {
|
||||
MSG_DATA=0, /* raw data on the multiplexed stream */
|
||||
MSG_ERROR=FERROR, MSG_INFO=FINFO, /* remote logging */
|
||||
MSG_LOG=FLOG, MSG_SOCKERR=FSOCKERR, /* sibling logging */
|
||||
MSG_LOG=FLOG, MSG_CLIENT=FCLIENT, MSG_SOCKERR=FSOCKERR, /* sibling logging */
|
||||
MSG_REDO=9, /* reprocess indicated flist index */
|
||||
MSG_FLIST=20, /* extra file list over sibling socket */
|
||||
MSG_FLIST_EOF=21,/* we've transmitted all the file lists */
|
||||
MSG_IO_ERROR=22,/* the sending side had an I/O error */
|
||||
MSG_NOOP=42, /* a do-nothing message */
|
||||
MSG_SUCCESS=100,/* successfully updated indicated flist index */
|
||||
MSG_DELETED=101,/* successfully deleted a file on receiving side */
|
||||
MSG_NO_SEND=102,/* sender failed to open a file we wanted */
|
||||
MSG_DONE=86 /* current phase is done */
|
||||
};
|
||||
|
||||
#define NDX_DONE -1
|
||||
#define NDX_FLIST_EOF -2
|
||||
#define NDX_FLIST_OFFSET -101
|
||||
|
||||
#include "errcode.h"
|
||||
|
||||
#include "config.h"
|
||||
@@ -205,6 +240,12 @@ enum msgcode {
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
@@ -328,6 +369,24 @@ enum msgcode {
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#ifndef ICONV_CONST
|
||||
#define ICONV_CONST
|
||||
#endif
|
||||
#else
|
||||
#ifdef ICONV_CONST
|
||||
#undef ICONV_CONST
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
#undef ICONV_OPTION
|
||||
#endif
|
||||
#ifdef iconv_t
|
||||
#undef iconv_t
|
||||
#endif
|
||||
#define iconv_t int
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "lib/pool_alloc.h"
|
||||
@@ -344,11 +403,30 @@ enum msgcode {
|
||||
#define schar char
|
||||
#endif
|
||||
|
||||
#ifndef int16
|
||||
#if SIZEOF_INT16_T == 2
|
||||
# define int16 int16_t
|
||||
#else
|
||||
# define int16 short
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef uint16
|
||||
#if SIZEOF_UINT16_T == 2
|
||||
# define uint16 uint16_t
|
||||
#else
|
||||
# define uint16 unsigned int16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Find a variable that is either exactly 32-bits or longer.
|
||||
* If some code depends on 32-bit truncation, it will need to
|
||||
* take special action in a "#if SIZEOF_INT32 > 4" section. */
|
||||
#ifndef int32
|
||||
#if SIZEOF_INT == 4
|
||||
#if SIZEOF_INT32_T == 4
|
||||
# define int32 int32_t
|
||||
# define SIZEOF_INT32 4
|
||||
#elif SIZEOF_INT == 4
|
||||
# define int32 int
|
||||
# define SIZEOF_INT32 4
|
||||
#elif SIZEOF_LONG == 4
|
||||
@@ -371,7 +449,11 @@ enum msgcode {
|
||||
#endif
|
||||
|
||||
#ifndef uint32
|
||||
#define uint32 unsigned int32
|
||||
#if SIZEOF_UINT32_T == 4
|
||||
# define uint32 uint32_t
|
||||
#else
|
||||
# define uint32 unsigned int32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SIZEOF_OFF_T == 8 || !SIZEOF_OFF64_T || !defined HAVE_STRUCT_STAT64
|
||||
@@ -389,7 +471,10 @@ enum msgcode {
|
||||
* to ensure that any code that really requires a 64-bit integer has
|
||||
* it (e.g. the checksum code uses two 32-bit integers for its 64-bit
|
||||
* counter). */
|
||||
#if SIZEOF_LONG == 8
|
||||
#if SIZEOF_INT64_T == 8
|
||||
# define int64 int64_t
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_LONG == 8
|
||||
# define int64 long
|
||||
# define SIZEOF_INT64 8
|
||||
#elif SIZEOF_INT == 8
|
||||
@@ -419,37 +504,26 @@ enum msgcode {
|
||||
# define SIZEOF_INT64 SIZEOF_OFF_T
|
||||
#endif
|
||||
|
||||
/* Starting from protocol version 26, we always use 64-bit
|
||||
* ino_t and dev_t internally, even if this platform does not
|
||||
* allow files to have 64-bit inums. That's because the
|
||||
* receiver needs to find duplicate (dev,ino) tuples to detect
|
||||
* hardlinks, and it might have files coming from a platform
|
||||
* that has 64-bit inums.
|
||||
*
|
||||
* The only exception is if we're on a platform with no 64-bit type at
|
||||
* all.
|
||||
*
|
||||
* Because we use read_longint() to get these off the wire, if you
|
||||
* transfer devices or hardlinks with dev or inum > 2**32 to a machine
|
||||
* with no 64-bit types then you will get an overflow error. Probably
|
||||
* not many people have that combination of machines, and you can
|
||||
* avoid it by not preserving hardlinks or not transferring device
|
||||
* nodes. It's not clear that any other behaviour is better.
|
||||
*
|
||||
* Note that if you transfer devices from a 64-bit-devt machine (say,
|
||||
* Solaris) to a 32-bit-devt machine (say, Linux-2.2/x86) then the
|
||||
* device numbers will be truncated. But it's a kind of silly thing
|
||||
* to do anyhow.
|
||||
*
|
||||
* FIXME: I don't think the code in flist.c has ever worked on a system
|
||||
* where dev_t is a struct.
|
||||
*/
|
||||
|
||||
struct idev {
|
||||
int64 inode;
|
||||
int64 dev;
|
||||
struct hashtable {
|
||||
void *nodes;
|
||||
int32 size, entries;
|
||||
uint32 node_size;
|
||||
};
|
||||
|
||||
struct ht_int32_node {
|
||||
void *data;
|
||||
int32 key;
|
||||
};
|
||||
|
||||
struct ht_int64_node {
|
||||
void *data;
|
||||
int64 key;
|
||||
};
|
||||
|
||||
#define HT_NODE(tbl, bkts, i) ((void*)((char*)(bkts) + (i)*(tbl)->node_size))
|
||||
#define HT_KEY(node, k64) ((k64)? ((struct ht_int64_node*)(node))->key \
|
||||
: (int64)((struct ht_int32_node*)(node))->key)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
@@ -462,8 +536,6 @@ struct idev {
|
||||
#define MAXHOSTNAMELEN 256
|
||||
#endif
|
||||
|
||||
/* the length of the md4 checksum */
|
||||
#define MD4_SUM_LENGTH 16
|
||||
#define SUM_LENGTH 16
|
||||
#define SHORT_SUM_LENGTH 2
|
||||
#define BLOCKSUM_BIAS 10
|
||||
@@ -492,47 +564,104 @@ struct idev {
|
||||
#define IN_LOOPBACKNET 127
|
||||
#endif
|
||||
|
||||
#define GID_NONE ((gid_t)-1)
|
||||
#if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS
|
||||
#define ACLS_NEED_MASK 1
|
||||
#endif
|
||||
|
||||
#define HL_CHECK_MASTER 0
|
||||
#define HL_SKIP 1
|
||||
|
||||
struct hlink {
|
||||
int32 next;
|
||||
int32 hlindex;
|
||||
unsigned short link_dest_used;
|
||||
union file_extras {
|
||||
int32 num;
|
||||
uint32 unum;
|
||||
};
|
||||
|
||||
#define F_DEV link_u.idev->dev
|
||||
#define F_INODE link_u.idev->inode
|
||||
|
||||
#define F_HLINDEX link_u.links->hlindex
|
||||
#define F_NEXT link_u.links->next
|
||||
|
||||
struct file_struct {
|
||||
union {
|
||||
dev_t rdev; /* The device number, if this is a device */
|
||||
char *sum; /* Only a normal file can have a checksum */
|
||||
char *link; /* Points to symlink string, if a symlink */
|
||||
} u;
|
||||
OFF_T length;
|
||||
char *basename; /* The current item's name (AKA filename) */
|
||||
char *dirname; /* The directory info inside the transfer */
|
||||
union {
|
||||
char *root; /* Sender-side dir info outside transfer */
|
||||
int depth; /* Receiver-side directory depth info */
|
||||
} dir;
|
||||
union {
|
||||
struct idev *idev;
|
||||
struct hlink *links;
|
||||
} link_u;
|
||||
time_t modtime;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
uchar flags; /* this item MUST remain last */
|
||||
const char *dirname; /* The dir info inside the transfer */
|
||||
time_t modtime; /* When the item was last modified */
|
||||
uint32 len32; /* Lowest 32 bits of the file's length */
|
||||
uint16 mode; /* The item's type and permissions */
|
||||
uint16 flags; /* The FLAG_* bits for this item */
|
||||
const char basename[1]; /* The basename (AKA filename) follows */
|
||||
};
|
||||
|
||||
extern int file_extra_cnt;
|
||||
extern int inc_recurse;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int acls_ndx;
|
||||
extern int xattrs_ndx;
|
||||
|
||||
#define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
|
||||
#define EXTRA_LEN (sizeof (union file_extras))
|
||||
#define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
#define DEV_EXTRA_CNT 2
|
||||
#define DIRNODE_EXTRA_CNT 3
|
||||
#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
|
||||
#define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx))
|
||||
#define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
|
||||
|
||||
#define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0)
|
||||
#define HLINK_BUMP(f) ((f)->flags & (FLAG_HLINKED|FLAG_HLINK_DONE) ? inc_recurse+1 : 0)
|
||||
#define ACL_BUMP(f) (acls_ndx ? 1 : 0)
|
||||
|
||||
/* The length applies to all items. */
|
||||
#if SIZEOF_INT64 < 8
|
||||
#define F_LENGTH(f) ((int64)(f)->len32)
|
||||
#else
|
||||
#define F_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 \
|
||||
? (int64)OPT_EXTRA(f, 0)->unum << 32 : 0))
|
||||
#endif
|
||||
|
||||
/* If there is a symlink string, it is always right after the basename */
|
||||
#define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1)
|
||||
|
||||
/* The sending side always has this available: */
|
||||
#define F_PATHNAME(f) (*(const char**)REQ_EXTRA(f, PTR_EXTRA_CNT))
|
||||
|
||||
/* The receiving side always has this available: */
|
||||
#define F_DEPTH(f) REQ_EXTRA(f, 1)->num
|
||||
|
||||
/* When the associated option is on, all entries will have these present: */
|
||||
#define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
|
||||
#define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum
|
||||
#define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
|
||||
#define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
|
||||
#define F_NDX(f) REQ_EXTRA(f, ic_ndx)->num
|
||||
|
||||
/* These items are per-entry optional: */
|
||||
#define F_HL_GNUM(f) OPT_EXTRA(f, LEN64_BUMP(f))->num /* non-dirs */
|
||||
#define F_HL_PREV(f) OPT_EXTRA(f, LEN64_BUMP(f)+inc_recurse)->num /* non-dirs */
|
||||
#define F_DIR_NODE_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) \
|
||||
+ DIRNODE_EXTRA_CNT - 1)->num) /* sender dirs */
|
||||
#define F_DIR_RELNAMES_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) + DIRNODE_EXTRA_CNT \
|
||||
+ PTR_EXTRA_CNT - 1)->num) /* sender dirs */
|
||||
#define F_DIR_DEFACL(f) OPT_EXTRA(f, LEN64_BUMP(f))->unum /* receiver dirs */
|
||||
#define F_DIR_DEV_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) + ACL_BUMP(f) \
|
||||
+ DEV_EXTRA_CNT - 1)->unum) /* receiver dirs */
|
||||
|
||||
/* This optional item might follow an F_HL_*() item.
|
||||
* (Note: a device doesn't need to check LEN64_BUMP(f).) */
|
||||
#define F_RDEV_P(f) (&OPT_EXTRA(f, HLINK_BUMP(f) + 2 - 1)->unum)
|
||||
|
||||
/* The sum is only present on regular files. */
|
||||
#define F_SUM(f) ((char*)OPT_EXTRA(f, LEN64_BUMP(f) + HLINK_BUMP(f) \
|
||||
+ SUM_EXTRA_CNT - 1))
|
||||
|
||||
/* Some utility defines: */
|
||||
#define F_IS_ACTIVE(f) (f)->basename[0]
|
||||
#define F_IS_HLINKED(f) ((f)->flags & FLAG_HLINKED)
|
||||
|
||||
#define F_HLINK_NOT_FIRST(f) BITS_SETnUNSET((f)->flags, FLAG_HLINKED, FLAG_HLINK_FIRST)
|
||||
#define F_HLINK_NOT_LAST(f) BITS_SETnUNSET((f)->flags, FLAG_HLINKED, FLAG_HLINK_LAST)
|
||||
|
||||
/* These access the F_DIR_DEV_P() and F_RDEV_P() values: */
|
||||
#define DEV_MAJOR(a) (a)[0]
|
||||
#define DEV_MINOR(a) (a)[1]
|
||||
|
||||
/* These access the F_DIRS_NODE_P() values: */
|
||||
#define DIR_PARENT(a) (a)[0]
|
||||
#define DIR_FIRST_CHILD(a) (a)[1]
|
||||
#define DIR_NEXT_SIBLING(a) (a)[2]
|
||||
|
||||
/*
|
||||
* Start the flist array at FLIST_START entries and grow it
|
||||
* by doubling until FLIST_LINEAR then grow by FLIST_LINEAR
|
||||
@@ -541,27 +670,30 @@ struct file_struct {
|
||||
#define FLIST_LINEAR (FLIST_START * 512)
|
||||
|
||||
/*
|
||||
* Extent size for allocation pools A minimum size of 128KB
|
||||
* Extent size for allocation pools: A minimum size of 128KB
|
||||
* is needed to mmap them so that freeing will release the
|
||||
* space to the OS.
|
||||
*
|
||||
* Larger sizes reduce leftover fragments and speed free calls
|
||||
* (when they happen) Smaller sizes increase the chance of
|
||||
* (when they happen). Smaller sizes increase the chance of
|
||||
* freed allocations freeing whole extents.
|
||||
*/
|
||||
#define FILE_EXTENT (256 * 1024)
|
||||
#define HLINK_EXTENT (128 * 1024)
|
||||
#define NORMAL_EXTENT (256 * 1024)
|
||||
#define SMALL_EXTENT (128 * 1024)
|
||||
|
||||
#define WITH_HLINK 1
|
||||
#define WITHOUT_HLINK 0
|
||||
#define FLIST_TEMP (1<<1)
|
||||
|
||||
struct file_list {
|
||||
struct file_struct **files;
|
||||
struct file_list *next, *prev;
|
||||
struct file_struct **files, **sorted;
|
||||
alloc_pool_t file_pool;
|
||||
alloc_pool_t hlink_pool;
|
||||
int count;
|
||||
int malloced;
|
||||
int low, high;
|
||||
void *pool_boundary;
|
||||
int used, malloced;
|
||||
int low, high; /* 0-relative index values excluding empties */
|
||||
int ndx_start; /* the start offset for inc_recurse mode */
|
||||
int ndx_end; /* the end offset for inc_recurse mode */
|
||||
int parent_ndx; /* dir_flist index of parent directory */
|
||||
int in_progress, to_redo;
|
||||
};
|
||||
|
||||
#define SUMFLG_SAME_OFFSET (1<<0)
|
||||
@@ -615,10 +747,12 @@ struct map_struct {
|
||||
#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 MATCHFLG_PERISHABLE (1<<19)/* perishable if parent dir goes away */
|
||||
|
||||
#define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \
|
||||
| MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \
|
||||
| MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE)
|
||||
| MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE \
|
||||
| MATCHFLG_PERISHABLE)
|
||||
|
||||
struct filter_struct {
|
||||
struct filter_struct *next;
|
||||
@@ -645,7 +779,7 @@ struct stats {
|
||||
int64 matched_data;
|
||||
int64 flist_buildtime;
|
||||
int64 flist_xfertime;
|
||||
int flist_size;
|
||||
int64 flist_size;
|
||||
int num_files;
|
||||
int num_transferred_files;
|
||||
int current_file_index;
|
||||
@@ -653,24 +787,85 @@ struct stats {
|
||||
|
||||
struct chmod_mode_struct;
|
||||
|
||||
#define EMPTY_ITEM_LIST {NULL, 0, 0}
|
||||
|
||||
typedef struct {
|
||||
void *items;
|
||||
size_t count;
|
||||
size_t malloced;
|
||||
} item_list;
|
||||
|
||||
#define EXPAND_ITEM_LIST(lp, type, incr) \
|
||||
(type*)expand_item_list(lp, sizeof (type), #type, incr)
|
||||
|
||||
#define EMPTY_XBUF {NULL, 0, 0, 0}
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
size_t pos; /* pos = read pos in the buf */
|
||||
size_t len; /* len = chars following pos */
|
||||
size_t size; /* size = total space in buf */
|
||||
} xbuf;
|
||||
|
||||
#define INIT_XBUF(xb, str, ln, sz) (xb).buf = (str), (xb).len = (ln), (xb).size = (sz), (xb).pos = 0
|
||||
#define INIT_XBUF_STRLEN(xb, str) (xb).buf = (str), (xb).len = strlen((xb).buf), (xb).size = (-1), (xb).pos = 0
|
||||
/* This one is used to make an output xbuf based on a char[] buffer: */
|
||||
#define INIT_CONST_XBUF(xb, bf) (xb).buf = (bf), (xb).size = sizeof (bf), (xb).len = (xb).pos = 0
|
||||
|
||||
#define ICB_EXPAND_OUT (1<<0)
|
||||
#define ICB_INCLUDE_BAD (1<<1)
|
||||
#define ICB_INCLUDE_INCOMPLETE (1<<2)
|
||||
|
||||
#define RL_EOL_NULLS (1<<0)
|
||||
#define RL_DUMP_COMMENTS (1<<1)
|
||||
#define RL_CONVERT (1<<2)
|
||||
|
||||
typedef struct {
|
||||
char is_dot_dir;
|
||||
char fname[1]; /* has variable size */
|
||||
} relnamecache;
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "lib/mdfour.h"
|
||||
#include "lib/mdigest.h"
|
||||
#include "lib/wildmatch.h"
|
||||
#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> */
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(x)
|
||||
#else
|
||||
# if __GNUC__ <= 2
|
||||
# define NORETURN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) x __attribute__((__unused__))
|
||||
#ifndef NORETURN
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
STRUCT_STAT st;
|
||||
#ifdef SUPPORT_ACLS
|
||||
struct rsync_acl *acc_acl; /* access ACL */
|
||||
struct rsync_acl *def_acl; /* default ACL */
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
item_list *xattr;
|
||||
#endif
|
||||
} stat_x;
|
||||
|
||||
#define ACL_READY(sx) ((sx).acc_acl != NULL)
|
||||
#define XATTR_READY(sx) ((sx).xattr != NULL)
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#ifndef SUPPORT_XATTRS
|
||||
#define x_stat(fn,fst,xst) do_stat(fn,fst)
|
||||
#define x_lstat(fn,fst,xst) do_lstat(fn,fst)
|
||||
#define x_fstat(fd,fst,xst) do_fstat(fd,fst)
|
||||
#endif
|
||||
|
||||
/* We have replacement versions of these if they're missing. */
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **ptr, const char *format, ...);
|
||||
@@ -687,7 +882,7 @@ int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
|
||||
|
||||
#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF
|
||||
#define snprintf rsync_snprintf
|
||||
int snprintf(char *str,size_t count,const char *fmt,...);
|
||||
int snprintf(char *str, size_t count, const char *fmt,...);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -826,9 +1021,11 @@ extern int errno;
|
||||
#define NS(s) ((s)?(s):"<NULL>")
|
||||
|
||||
/* Convenient wrappers for malloc and realloc. Use them. */
|
||||
#define new(type) ((type *)malloc(sizeof(type)))
|
||||
#define new_array(type, num) ((type *)_new_array(sizeof(type), (num)))
|
||||
#define realloc_array(ptr, type, num) ((type *)_realloc_array((ptr), sizeof(type), (num)))
|
||||
#define new(type) ((type*)malloc(sizeof (type)))
|
||||
#define new0(type) ((type*)calloc(1, sizeof (type)))
|
||||
#define new_array(type, num) ((type*)_new_array((num), sizeof (type), 0))
|
||||
#define new_array0(type, num) ((type*)_new_array((num), sizeof (type), 1))
|
||||
#define realloc_array(ptr, type, num) ((type*)_realloc_array((ptr), sizeof(type), (num)))
|
||||
|
||||
/* use magic gcc attributes to catch format errors */
|
||||
void rprintf(enum logcode , const char *, ...)
|
||||
|
||||
525
rsync.yo
525
rsync.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsync)(1)(6 Nov 2006)()()
|
||||
manpage(rsync)(1)(11 Oct 2007)()()
|
||||
manpagename(rsync)(faster, flexible replacement for rcp)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -21,7 +21,7 @@ rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
|
||||
|
||||
manpagedescription()
|
||||
|
||||
rsync is a program that behaves in much the same way that rcp does,
|
||||
Rsync is a program that behaves in much the same way that rcp does,
|
||||
but has many more options and uses the rsync remote-update protocol to
|
||||
greatly speed up file transfers when the destination file is being
|
||||
updated.
|
||||
@@ -31,6 +31,12 @@ differences between two sets of files across the network connection, using
|
||||
an efficient checksum-search algorithm described in the technical
|
||||
report that accompanies this package.
|
||||
|
||||
Rsync finds files that need to be transferred using a "quick check" algorithm
|
||||
that looks for files that have changed in size or in last-modified time (by
|
||||
default). Any changes in the other preserved attributes (as requested by
|
||||
options) are made on the destination file directly when the quick check
|
||||
indicates that the file's data does not need to be updated.
|
||||
|
||||
Some of the additional features of rsync are:
|
||||
|
||||
itemization(
|
||||
@@ -143,33 +149,29 @@ See the following section for more details.
|
||||
|
||||
manpagesection(ADVANCED USAGE)
|
||||
|
||||
The syntax for requesting multiple files from a remote host involves using
|
||||
quoted spaces in the SRC. Some examples:
|
||||
The syntax for requesting multiple files from a remote host is done by
|
||||
specifying additional remote-host args in the same style as the first,
|
||||
or with the hostname omitted. For instance, all these work:
|
||||
|
||||
quote(tt(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest))
|
||||
quote(tt(rsync -av host:file1 :file2 host:file{3,4} /dest/)nl()
|
||||
tt(rsync -av host::modname/file{1,2} host::modname/file3 /dest/)nl()
|
||||
tt(rsync -av host::modname/file1 ::modname/file{3,4}))
|
||||
|
||||
This would copy file1 and file2 into /dest from an rsync daemon. Each
|
||||
additional arg must include the same "modname/" prefix as the first one,
|
||||
and must be preceded by a single space. All other spaces are assumed
|
||||
to be a part of the filenames.
|
||||
Older versions of rsync required using quoted spaces in the SRC, like these
|
||||
examples:
|
||||
|
||||
quote(tt(rsync -av host:'dir1/file1 dir2/file2' /dest))
|
||||
quote(tt(rsync -av host:'dir1/file1 dir2/file2' /dest)nl()
|
||||
tt(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest))
|
||||
|
||||
This would copy file1 and file2 into /dest using a remote shell. This
|
||||
word-splitting is done by the remote shell, so if it doesn't work it means
|
||||
that the remote shell isn't configured to split its args based on
|
||||
whitespace (a very rare setting, but not unknown). If you need to transfer
|
||||
a filename that contains whitespace, you'll need to either escape the
|
||||
whitespace in a way that the remote shell will understand, or use wildcards
|
||||
in place of the spaces. Two examples of this are:
|
||||
This word-splitting still works (by default) in the latest rsync, but is
|
||||
not as easy to use as the first method.
|
||||
|
||||
quote(
|
||||
tt(rsync -av host:'file\ name\ with\ spaces' /dest)nl()
|
||||
tt(rsync -av host:file?name?with?spaces /dest)nl()
|
||||
)
|
||||
If you need to transfer a filename that contains whitespace, you can either
|
||||
specify the bf(--protect-args) (bf(-s)) option, or you'll need to escape
|
||||
the whitespace in a way that the remote shell will understand. For
|
||||
instance:
|
||||
|
||||
This latter example assumes that your shell passes through unmatched
|
||||
wildcards. If it complains about "no match", put the name in quotes.
|
||||
quote(tt(rsync -av host:'file\ name\ with\ spaces' /dest))
|
||||
|
||||
manpagesection(CONNECTING TO AN RSYNC DAEMON)
|
||||
|
||||
@@ -213,6 +215,21 @@ environment variable RSYNC_PROXY to a hostname:port pair pointing to
|
||||
your web proxy. Note that your web proxy's configuration must support
|
||||
proxy connections to port 873.
|
||||
|
||||
You may also establish a daemon connection using a program as a proxy by
|
||||
setting the environment variable RSYNC_CONNECT_PROG to the commands you
|
||||
wish to run in place of making a direct socket connection. The string may
|
||||
contain the escape "%H" to represent the hostname specified in the rsync
|
||||
command (so use "%%" if you need a single "%" in your string). For
|
||||
example:
|
||||
|
||||
verb( export RSYNC_CONNECT_PROG='ssh proxyhost nc %H 873'
|
||||
rsync -av targethost1::module/src/ /dest/
|
||||
rsync -av rsync:://targethost2/module/src/ /dest/ )
|
||||
|
||||
The command specifed above uses ssh to run nc (netcat) on a proxyhost,
|
||||
which forwards all data to port 873 (the rsync daemon) on the targethost
|
||||
(%H).
|
||||
|
||||
manpagesection(USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION)
|
||||
|
||||
It is sometimes useful to use various features of an rsync daemon (such as
|
||||
@@ -301,7 +318,7 @@ to the detailed description below for a complete description. verb(
|
||||
-q, --quiet suppress non-error messages
|
||||
--no-motd suppress daemon-mode MOTD (see caveat)
|
||||
-c, --checksum skip based on checksum, not mod-time & size
|
||||
-a, --archive archive mode; same as -rlptgoD (no -H)
|
||||
-a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)
|
||||
--no-OPTION turn off an implied OPTION (e.g. --no-D)
|
||||
-r, --recursive recurse into directories
|
||||
-R, --relative use relative path names
|
||||
@@ -312,6 +329,7 @@ to the detailed description below for a complete description. verb(
|
||||
-u, --update skip files that are newer on the receiver
|
||||
--inplace update destination files in-place
|
||||
--append append data onto shorter files
|
||||
--append-verify --append w/old data in file cheksum
|
||||
-d, --dirs transfer directories without recursing
|
||||
-l, --links copy symlinks as symlinks
|
||||
-L, --copy-links transform symlink into referent file/dir
|
||||
@@ -323,14 +341,17 @@ to the detailed description below for a complete description. verb(
|
||||
-p, --perms preserve permissions
|
||||
-E, --executability preserve executability
|
||||
--chmod=CHMOD affect file and/or directory permissions
|
||||
-A, --acls preserve ACLs (implies -p)
|
||||
-X, --xattrs preserve extended attributes
|
||||
-o, --owner preserve owner (super-user only)
|
||||
-g, --group preserve group
|
||||
--devices preserve device files (super-user only)
|
||||
--specials preserve special files
|
||||
-D same as --devices --specials
|
||||
-t, --times preserve times
|
||||
-O, --omit-dir-times omit directories when preserving times
|
||||
-t, --times preserve modification times
|
||||
-O, --omit-dir-times omit directories from --times
|
||||
--super receiver attempts super-user activities
|
||||
--fake-super store/recover privileged attrs using xattrs
|
||||
-S, --sparse handle sparse files efficiently
|
||||
-n, --dry-run show what would have been transferred
|
||||
-W, --whole-file copy files whole (without rsync algorithm)
|
||||
@@ -345,6 +366,7 @@ to the detailed description below for a complete description. verb(
|
||||
--delete delete extraneous files from dest dirs
|
||||
--delete-before receiver deletes before transfer (default)
|
||||
--delete-during receiver deletes during xfer, not before
|
||||
--delete-delay find deletions during, delete after
|
||||
--delete-after receiver deletes after transfer, not before
|
||||
--delete-excluded also delete excluded files from dest dirs
|
||||
--ignore-errors delete even if there are I/O errors
|
||||
@@ -368,6 +390,7 @@ to the detailed description below for a complete description. verb(
|
||||
--link-dest=DIR hardlink to files in DIR when unchanged
|
||||
-z, --compress compress file data during the transfer
|
||||
--compress-level=NUM explicitly set compression level
|
||||
--skip-compress=LIST skip compressing files with suffix in LIST
|
||||
-C, --cvs-exclude auto-ignore files in the same way CVS does
|
||||
-f, --filter=RULE add a file-filtering RULE
|
||||
-F same as --filter='dir-merge /.rsync-filter'
|
||||
@@ -378,6 +401,7 @@ to the detailed description below for a complete description. verb(
|
||||
--include-from=FILE read include patterns from FILE
|
||||
--files-from=FILE read list of source-file names from FILE
|
||||
-0, --from0 all *from/filter files are delimited by 0s
|
||||
-s, --protect-args no space-splitting; wildcard chars only
|
||||
--address=ADDRESS bind address for outgoing socket to daemon
|
||||
--port=PORT specify double-colon alternate port number
|
||||
--sockopts=OPTIONS specify custom TCP options
|
||||
@@ -391,13 +415,14 @@ to the detailed description below for a complete description. verb(
|
||||
--out-format=FORMAT output updates using the specified FORMAT
|
||||
--log-file=FILE log what we're doing to the specified FILE
|
||||
--log-file-format=FMT log updates using the specified FMT
|
||||
--password-file=FILE read password from FILE
|
||||
--password-file=FILE read daemon-access password from FILE
|
||||
--list-only list the files instead of copying them
|
||||
--bwlimit=KBPS limit I/O bandwidth; KBytes per second
|
||||
--write-batch=FILE write a batched update to FILE
|
||||
--only-write-batch=FILE like --write-batch but w/o updating dest
|
||||
--read-batch=FILE read a batched update from FILE
|
||||
--protocol=NUM force an older protocol version to be used
|
||||
--iconv=CONVERT_SPEC request charset conversion of filesnames
|
||||
--checksum-seed=NUM set block/file checksum seed (advanced)
|
||||
-4, --ipv4 prefer IPv4
|
||||
-6, --ipv6 prefer IPv6
|
||||
@@ -463,19 +488,19 @@ by the client at the start of a daemon transfer. This suppresses the
|
||||
message-of-the-day (MOTD) text, but it also affects the list of modules
|
||||
that the daemon sends in response to the "rsync host::" request (due to
|
||||
a limitation in the rsync protocol), so omit this option if you want to
|
||||
request the list of modules from the deamon.
|
||||
request the list of modules from the daemon.
|
||||
|
||||
dit(bf(-I, --ignore-times)) Normally rsync will skip any files that are
|
||||
already the same size and have the same modification time-stamp.
|
||||
already the same size and have the same modification timestamp.
|
||||
This option turns off this "quick check" behavior, causing all files to
|
||||
be updated.
|
||||
|
||||
dit(bf(--size-only)) Normally rsync will not transfer any files that are
|
||||
already the same size and have the same modification time-stamp. With the
|
||||
bf(--size-only) option, files will not be transferred if they have the same size,
|
||||
regardless of timestamp. This is useful when starting to use rsync
|
||||
after using another mirroring system which may not preserve timestamps
|
||||
exactly.
|
||||
dit(bf(--size-only)) This modifies rsync's "quick check" algorithm for
|
||||
finding files that need to be transferred, changing it from the default of
|
||||
transferring files with either a changed size or a changed last-modified
|
||||
time to just looking for files that have changed in size. This is useful
|
||||
when starting to use rsync after using another mirroring system which may
|
||||
not preserve timestamps exactly.
|
||||
|
||||
dit(bf(--modify-window)) When comparing two timestamps, rsync treats the
|
||||
timestamps as being equal if they differ by no more than the modify-window
|
||||
@@ -485,20 +510,26 @@ transferring to or from an MS Windows FAT filesystem (which represents
|
||||
times with a 2-second resolution), bf(--modify-window=1) is useful
|
||||
(allowing times to differ by up to 1 second).
|
||||
|
||||
dit(bf(-c, --checksum)) This forces the sender to checksum em(every)
|
||||
regular file using a 128-bit MD4 checksum. It does this during the initial
|
||||
file-system scan as it builds the list of all available files. The receiver
|
||||
then checksums its version of each file (if it exists and it has the same
|
||||
size as its sender-side counterpart) in order to decide which files need to
|
||||
be updated: files with either a changed size or a changed checksum are
|
||||
selected for transfer. Since this whole-file checksumming of all files on
|
||||
both sides of the connection occurs in addition to the automatic checksum
|
||||
verifications that occur during a file's transfer, this option can be quite
|
||||
slow.
|
||||
dit(bf(-c, --checksum)) This changes the way rsync checks if the files have
|
||||
been changed and are in need of a transfer. Without this option, rsync
|
||||
uses a "quick check" that (by default) checks if each file's size and time
|
||||
of last modification match between the sender and receiver. This option
|
||||
changes this to compare a 128-bit MD4 checksum for each file that has a
|
||||
matching size. Generating the checksums means that both sides will expend
|
||||
a lot of disk I/O reading all the data in the files in the transfer (and
|
||||
this is prior to any reading that will be done to transfer changed files),
|
||||
so this can slow things down significantly.
|
||||
|
||||
Note that rsync always verifies that each em(transferred) file was correctly
|
||||
reconstructed on the receiving side by checking its whole-file checksum, but
|
||||
that automatic after-the-transfer verification has nothing to do with this
|
||||
The sending side generates its checksums while it is doing the file-system
|
||||
scan that builds the list of the available files. The receiver generates
|
||||
its checksums when it is scanning for changed files, and will checksum any
|
||||
file that has the same size as the corresponding sender's file: files with
|
||||
either a changed size or a changed checksum are selected for transfer.
|
||||
|
||||
Note that rsync always verifies that each em(transferred) file was
|
||||
correctly reconstructed on the receiving side by checking a whole-file
|
||||
checksum that is generated when as the file is transferred, but that
|
||||
automatic after-the-transfer verification has nothing to do with this
|
||||
option's before-the-transfer "Does this file need to be updated?" check.
|
||||
|
||||
dit(bf(-a, --archive)) This is equivalent to bf(-rlptgoD). It is a quick
|
||||
@@ -533,6 +564,25 @@ details).
|
||||
dit(bf(-r, --recursive)) This tells rsync to copy directories
|
||||
recursively. See also bf(--dirs) (bf(-d)).
|
||||
|
||||
Beginning with rsync 3.0.0, the recursive algorithm used is now an
|
||||
incremental scan that uses much less memory than before and begins the
|
||||
transfer after the scanning of the first few directories have been
|
||||
completed. This incremental scan only affects our recursion algorithm, and
|
||||
does not change a non-recursive transfer. It is also only possible when
|
||||
both ends of the transfer are at least version 3.0.0.
|
||||
|
||||
Some options require rsync to know the full file list, so these options
|
||||
disable the incremental recursion mode. These include: bf(--delete-before),
|
||||
bf(--delete-after), bf(--prune-empty-dirs), and bf(--delay-updates).
|
||||
Because of this, the default delete mode when you specify bf(--delete) is now
|
||||
bf(--delete-during) when both ends of the connection are at least 3.0.0
|
||||
(use bf(--del) or bf(--delete-during) to request this improved deletion mode
|
||||
explicitly). See also the bf(--delete-delay) option that is a better choice
|
||||
than using bf(--delete-after).
|
||||
|
||||
Incremental recursion can be disabled using the bf(--no-inc-recursive)
|
||||
option or its shorter bf(--no-i-r) alias.
|
||||
|
||||
dit(bf(-R, --relative)) Use relative paths. This means that the full path
|
||||
names specified on the command line are sent to the server rather than
|
||||
just the last parts of the filenames. This is particularly useful when
|
||||
@@ -547,10 +597,23 @@ machine. If instead you used
|
||||
quote(tt( rsync -avR /foo/bar/baz.c remote:/tmp/))
|
||||
|
||||
then a file named /tmp/foo/bar/baz.c would be created on the remote
|
||||
machine -- the full path name is preserved. To limit the amount of
|
||||
path information that is sent, you have a couple options: (1) With
|
||||
a modern rsync on the sending side (beginning with 2.6.7), you can
|
||||
insert a dot and a slash into the source path, like this:
|
||||
machine, preserving its full path. These extra path elements are called
|
||||
"implied directories" (i.e. the "foo" and the "foo/bar" directories in the
|
||||
above example).
|
||||
|
||||
Beginning with rsync 3.0.0, rsync always sends these implied directories as
|
||||
real directories in the file list, even if a path element is really a
|
||||
symlink on the sending side. This prevents some really unexpected
|
||||
behaviors when copying the full path of a file that you didn't realize had
|
||||
a symlink in its path. If you want to duplicate a server-side symlink,
|
||||
include both the symlink via its path, and referent directory via its real
|
||||
path. If you're dealing with an older rsync on the sending side, you may
|
||||
need to use the bf(--no-implied-dirs) option.
|
||||
|
||||
It is also possible to limit the amount of path information that is sent as
|
||||
implied directories for each path you specify. With a modern rsync on the
|
||||
sending side (beginning with 2.6.7), you can insert a dot and a slash into
|
||||
the source path, like this:
|
||||
|
||||
quote(tt( rsync -avR /foo/./bar/baz.c remote:/tmp/))
|
||||
|
||||
@@ -563,8 +626,8 @@ quote(tt( (cd /foo; rsync -avR bar/baz.c remote:/tmp/) ))
|
||||
|
||||
(Note that the parens put the two commands into a sub-shell, so that the
|
||||
"cd" command doesn't remain in effect for future commands.)
|
||||
If you're pulling files, use this idiom (which doesn't work with an
|
||||
rsync daemon):
|
||||
If you're pulling files from an older rsync, use this idiom (but only
|
||||
for a non-daemon transfer):
|
||||
|
||||
quote(
|
||||
tt( rsync -avR --rsync-path="cd /foo; rsync" \ )nl()
|
||||
@@ -578,7 +641,7 @@ means that the corresponding path elements on the destination system are
|
||||
left unchanged if they exist, and any missing implied directories are
|
||||
created with default attributes. This even allows these implied path
|
||||
elements to have big differences, such as being a symlink to a directory on
|
||||
one side of the transfer, and a real directory on the other side.
|
||||
the receiving side.
|
||||
|
||||
For instance, if a command-line arg or a files-from entry told rsync to
|
||||
transfer the file "path/foo/file", the directories "path" and "path/foo"
|
||||
@@ -591,15 +654,9 @@ ends up being created in "path/bar". Another way to accomplish this link
|
||||
preservation is to use the bf(--keep-dirlinks) option (which will also
|
||||
affect symlinks to directories in the rest of the transfer).
|
||||
|
||||
In a similar but opposite scenario, if the transfer of "path/foo/file" is
|
||||
requested and "path/foo" is a symlink on the sending side, running without
|
||||
bf(--no-implied-dirs) would cause rsync to transform "path/foo" on the
|
||||
receiving side into an identical symlink, and then attempt to transfer
|
||||
"path/foo/file", which might fail if the duplicated symlink did not point
|
||||
to a directory on the receiving side. Another way to avoid this sending of
|
||||
a symlink as an implied directory is to use bf(--copy-unsafe-links), or
|
||||
bf(--copy-dirlinks) (both of which also affect symlinks in the rest of the
|
||||
transfer -- see their descriptions for full details).
|
||||
When pulling files from an rsync older than 3.0.0, you may need to use this
|
||||
option if the sending side has a symlink in the path you request and you
|
||||
wish the implied directories to be transferred as normal directories.
|
||||
|
||||
dit(bf(-b, --backup)) With this option, preexisting destination files are
|
||||
renamed as each file is transferred or deleted. You can control where the
|
||||
@@ -610,7 +667,7 @@ Note that if you don't specify bf(--backup-dir), (1) the
|
||||
bf(--omit-dir-times) option will be implied, and (2) if bf(--delete) is
|
||||
also in effect (without bf(--delete-excluded)), rsync will add a "protect"
|
||||
filter-rule for the backup suffix to the end of all your existing excludes
|
||||
(e.g. -f "P *~"). This will prevent previously backed-up files from being
|
||||
(e.g. bf(-f "Pp *~")). This will prevent previously backed-up files from being
|
||||
deleted. Note that if you are supplying your own filter rules, you may
|
||||
need to manually insert your own exclude/protect rule somewhere higher up
|
||||
in the list so that it has a high enough priority to be effective (e.g., if
|
||||
@@ -630,16 +687,15 @@ if no -bf(-backup-dir) was specified, otherwise it is an empty string.
|
||||
|
||||
dit(bf(-u, --update)) This forces rsync to skip any files which exist on
|
||||
the destination and have a modified time that is newer than the source
|
||||
file. (If an existing destination file has a modify time equal to the
|
||||
file. (If an existing destination file has a modification time equal to the
|
||||
source file's, it will be updated if the sizes are different.)
|
||||
|
||||
In the current implementation of bf(--update), a difference of file format
|
||||
between the sender and receiver is always
|
||||
considered to be important enough for an update, no matter what date
|
||||
is on the objects. In other words, if the source has a directory or a
|
||||
symlink where the destination has a file, the transfer would occur
|
||||
regardless of the timestamps. This might change in the future (feel
|
||||
free to comment on this on the mailing list if you have an opinion).
|
||||
Note that this does not affect the copying of symlinks or other special
|
||||
files. Also, a difference of file format between the sender and receiver
|
||||
is always considered to be important enough for an update, no matter what
|
||||
date is on the objects. In other words, if the source has a directory
|
||||
where the destination has a file, the transfer would occur regardless of
|
||||
the timestamps.
|
||||
|
||||
dit(bf(--inplace)) This causes rsync not to create a new copy of the file
|
||||
and then move it into place. Instead rsync will overwrite the existing
|
||||
@@ -667,13 +723,22 @@ receiving user.
|
||||
dit(bf(--append)) This causes rsync to update a file by appending data onto
|
||||
the end of the file, which presumes that the data that already exists on
|
||||
the receiving side is identical with the start of the file on the sending
|
||||
side. If that is not true, the file will fail the checksum test, and the
|
||||
resend will do a normal bf(--inplace) update to correct the mismatched data.
|
||||
Only files on the receiving side that are shorter than the corresponding
|
||||
file on the sending side (as well as new files) are sent.
|
||||
Implies bf(--inplace), but does not conflict with bf(--sparse) (though the
|
||||
bf(--sparse) option will be auto-disabled if a resend of the already-existing
|
||||
data is required).
|
||||
side. Any files that are the same size or shorter on the receiving size
|
||||
are skipped. Files that do not yet exist on the receiving side are also
|
||||
sent, since they are considered to have 0 length. Implies bf(--inplace),
|
||||
but does not conflict with bf(--sparse) (since it is always extending a
|
||||
file's length).
|
||||
|
||||
dit(bf(--append-verify)) This works just like the bf(--append) option, but
|
||||
the existing data on the receiving side is included in the full-file
|
||||
checksum verification step, which will cause a file to be resent if the
|
||||
final verification step fails (rsync uses a normal, non-appending
|
||||
bf(--inplace) transfer for the resend).
|
||||
|
||||
Note: prior to rsync 3.0.0, the bf(--append) option worked like
|
||||
bf(--append-verify), so if you are interacting with an older rsync (or the
|
||||
transfer is using a protocol prior to 30), specifying either append option
|
||||
will initiate an bf(--append-verify) transfer.
|
||||
|
||||
dit(bf(-d, --dirs)) Tell the sending side to include any directories that
|
||||
are encountered. Unlike bf(--recursive), a directory's contents are not copied
|
||||
@@ -706,7 +771,7 @@ which point outside the copied tree. All absolute symlinks are
|
||||
also ignored. Using this option in conjunction with bf(--relative) may
|
||||
give unexpected results.
|
||||
|
||||
dit(bf(-K, --copy-dirlinks)) This option causes the sending side to treat
|
||||
dit(bf(-k, --copy-dirlinks)) This option causes the sending side to treat
|
||||
a symlink to a directory as though it were a real directory. This is
|
||||
useful if you don't want symlinks to non-directories to be affected, as
|
||||
they would be using bf(--copy-links).
|
||||
@@ -741,6 +806,12 @@ as though they were separate files.
|
||||
Note that rsync can only detect hard links if both parts of the link
|
||||
are in the list of files being sent.
|
||||
|
||||
If incremental recursion is active (see bf(--recursive)), rsync may transfer
|
||||
a missing hard-linked file before it finds that another link for the file
|
||||
exists elsewhere in the hierarchy. This does not affect the accuracy of
|
||||
the transfer, just its efficiency. One way to avoid this is to disable
|
||||
incremental recursion using the bf(--no-inc-recursive) option.
|
||||
|
||||
dit(bf(-p, --perms)) This option causes the receiving rsync to set the
|
||||
destination permissions to be the same as the source permissions. (See
|
||||
also the bf(--chmod) option for a way to modify what rsync considers to
|
||||
@@ -753,7 +824,9 @@ quote(itemization(
|
||||
permissions, though the bf(--executability) option might change just
|
||||
the execute permission for the file.
|
||||
it() New files get their "normal" permission bits set to the source
|
||||
file's permissions masked with the receiving end's umask setting, and
|
||||
file's permissions masked with the receiving directory's default
|
||||
permissions (either the receiving process's umask, or the permissions
|
||||
specified via the destination directory's default ACL), and
|
||||
their special permission bits disabled except in the case where a new
|
||||
directory inherits a setgid bit from its parent directory.
|
||||
))
|
||||
@@ -784,9 +857,11 @@ The preservation of the destination's setgid bit on newly-created
|
||||
directories when bf(--perms) is off was added in rsync 2.6.7. Older rsync
|
||||
versions erroneously preserved the three special permission bits for
|
||||
newly-created files when bf(--perms) was off, while overriding the
|
||||
destination's setgid bit setting on a newly-created directory. (Keep in
|
||||
mind that it is the version of the receiving rsync that affects this
|
||||
behavior.)
|
||||
destination's setgid bit setting on a newly-created directory. Default ACL
|
||||
observance was added to the ACL patch for rsync 2.6.7, so older (or
|
||||
non-ACL-enabled) rsyncs use the umask even if default ACLs are present.
|
||||
(Keep in mind that it is the version of the receiving rsync that affects
|
||||
these behaviors.)
|
||||
|
||||
dit(bf(-E, --executability)) This option causes rsync to preserve the
|
||||
executability (or non-executability) of regular files when bf(--perms) is
|
||||
@@ -804,6 +879,22 @@ quote(itemization(
|
||||
|
||||
If bf(--perms) is enabled, this option is ignored.
|
||||
|
||||
dit(bf(-A, --acls)) This option causes rsync to update the destination
|
||||
ACLs to be the same as the source ACLs.
|
||||
The option also implies bf(--perms).
|
||||
|
||||
The source and destination systems must have compatible ACL entries for this
|
||||
option to work properly. See the bf(--fake-super) option for a way to backup
|
||||
and restore ACLs that are not compatible.
|
||||
|
||||
dit(bf(-X, --xattrs)) This option causes rsync to update the remote
|
||||
extended attributes to be the same as the local ones.
|
||||
|
||||
For systems that support extended-attribute namespaces, a copy being done by a
|
||||
super-user copies all namespaces except system.*. A normal user only copies
|
||||
the user.* namespace. To be able to backup and restore non-user namespaces as
|
||||
a normal user, see the bf(--fake-super) option.
|
||||
|
||||
dit(bf(--chmod)) This option tells rsync to apply one or more
|
||||
comma-separated "chmod" strings to the permission of the files in the
|
||||
transfer. The resulting value is treated as though it was the permissions
|
||||
@@ -826,9 +917,9 @@ permission value can be applied to the files in the transfer.
|
||||
dit(bf(-o, --owner)) This option causes rsync to set the owner of the
|
||||
destination file to be the same as the source file, but only if the
|
||||
receiving rsync is being run as the super-user (see also the bf(--super)
|
||||
option to force rsync to attempt super-user activities).
|
||||
Without this option, the owner is set to the invoking user on the
|
||||
receiving side.
|
||||
and bf(--fake-super) options).
|
||||
Without this option, the owner of new and/or transferred files are set to
|
||||
the invoking user on the receiving side.
|
||||
|
||||
The preservation of ownership will associate matching names by default, but
|
||||
may fall back to using the ID number in some circumstances (see also the
|
||||
@@ -849,7 +940,7 @@ default, but may fall back to using the ID number in some circumstances
|
||||
dit(bf(--devices)) This option causes rsync to transfer character and
|
||||
block device files to the remote system to recreate these devices.
|
||||
This option has no effect if the receiving rsync is not run as the
|
||||
super-user and bf(--super) is not specified.
|
||||
super-user (see also the bf(--super) and bf(--fake-super) options).
|
||||
|
||||
dit(bf(--specials)) This option causes rsync to transfer special files
|
||||
such as named sockets and fifos.
|
||||
@@ -879,6 +970,37 @@ also for ensuring that you will get errors if the receiving side isn't
|
||||
being running as the super-user. To turn off super-user activities, the
|
||||
super-user can use bf(--no-super).
|
||||
|
||||
dit(bf(--fake-super)) When this option is enabled, rsync simulates
|
||||
super-user activities by saving/restoring the privileged attributes via
|
||||
special extended attributes that are attached to each file (as needed). This
|
||||
includes the file's owner and group (if it is not the default), the file's
|
||||
device info (device & special files are created as empty text files), and
|
||||
any permission bits that we won't allow to be set on the real file (e.g.
|
||||
the real file gets u-s,g-s,o-t for safety) or that would limit the owner's
|
||||
access (since the real super-user can always access/change a file, the
|
||||
files we create can always be accessed/changed by the creating user).
|
||||
This option also handles ACLs (if bf(--acls) was specified) and non-user
|
||||
extended attributes (if bf(--xattrs) was specified).
|
||||
|
||||
This is a good way to backup data withou using a super-user, and to store
|
||||
ACLs from incompatible systems.
|
||||
|
||||
The bf(--fake-super) option only affects the side where the option is used.
|
||||
To affect the remote side of a remote-shell connection, specify an rsync
|
||||
path:
|
||||
|
||||
quote(tt( rsync -av --rsync-path="rsync --fake-super" /src/ host:/dest/))
|
||||
|
||||
Since there is only one "side" in a local copy, this option affects both
|
||||
the sending and recieving of files. You'll need to specify a copy using
|
||||
"localhost" if you need to avoid this, possibly using the "lsh" shell
|
||||
script (from the support directory) as a substitute for an actual remote
|
||||
shell (see bf(--rsh)).
|
||||
|
||||
This option is overridden by both bf(--super) and bf(--no-super).
|
||||
|
||||
See also the "fake super" setting in the daemon's rsyncd.conf file.
|
||||
|
||||
dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take
|
||||
up less space on the destination. Conflicts with bf(--inplace) because it's
|
||||
not possible to overwrite data in a sparse fashion.
|
||||
@@ -890,7 +1012,7 @@ correctly and ends up corrupting the files.
|
||||
dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
|
||||
instead it will just report the actions it would have taken.
|
||||
|
||||
dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm
|
||||
dit(bf(-W, --whole-file)) With this option the delta transfer algorithm
|
||||
is not used and the whole file is sent as-is instead. The transfer may be
|
||||
faster if this option is used when the bandwidth between the source and
|
||||
destination machines is higher than the bandwidth to disk (especially when the
|
||||
@@ -919,11 +1041,19 @@ dit(bf(--existing, --ignore-non-existing)) This tells rsync to skip
|
||||
creating files (including directories) that do not exist
|
||||
yet on the destination. If this option is
|
||||
combined with the bf(--ignore-existing) option, no files will be updated
|
||||
(which can be useful if all you want to do is to delete extraneous files).
|
||||
(which can be useful if all you want to do is delete extraneous files).
|
||||
|
||||
dit(bf(--ignore-existing)) This tells rsync to skip updating files that
|
||||
already exist on the destination (this does em(not) ignore existing
|
||||
directores, or nothing would get done). See also bf(--existing).
|
||||
directories, or nothing would get done). See also bf(--existing).
|
||||
|
||||
This option can be useful for those doing backups using the bf(--link-dest)
|
||||
option when they need to continue a backup run that got interrupted. Since
|
||||
a bf(--link-dest) run is copied into a new directory hierarchy (when it is
|
||||
used properly), using bf(--ignore existing) will ensure that the
|
||||
already-handled files don't get tweaked (which avoids a change in
|
||||
permissions on the hard-linked files). This does mean that this option
|
||||
is only looking at the existing files in the destination hierarchy itself.
|
||||
|
||||
dit(bf(--remove-source-files)) This tells rsync to remove from the sending
|
||||
side the files (meaning non-directories) that are a part of the transfer
|
||||
@@ -941,8 +1071,8 @@ option or mark the rules as only matching on the sending side (see the
|
||||
include/exclude modifiers in the FILTER RULES section).
|
||||
|
||||
Prior to rsync 2.6.7, this option would have no effect unless bf(--recursive)
|
||||
was in effect. Beginning with 2.6.7, deletions will also occur when bf(--dirs)
|
||||
(bf(-d)) is in effect, but only for directories whose contents are being copied.
|
||||
was enabled. Beginning with 2.6.7, deletions will also occur when bf(--dirs)
|
||||
(bf(-d)) is enabled, but only for directories whose contents are being copied.
|
||||
|
||||
This option can be dangerous if used incorrectly! It is a very good idea
|
||||
to run first using the bf(--dry-run) option (bf(-n)) to see what files would be
|
||||
@@ -956,20 +1086,22 @@ destination. You can override this with the bf(--ignore-errors) option.
|
||||
|
||||
The bf(--delete) option may be combined with one of the --delete-WHEN options
|
||||
without conflict, as well as bf(--delete-excluded). However, if none of the
|
||||
--delete-WHEN options are specified, rsync will currently choose the
|
||||
bf(--delete-before) algorithm. A future version may change this to choose the
|
||||
bf(--delete-during) algorithm. See also bf(--delete-after).
|
||||
--delete-WHEN options are specified, rsync will choose the
|
||||
bf(--delete-during) algorithm when talking to an rsync 3.0.0 or newer, and
|
||||
the bf(--delete-before) algorithm when talking to an older rsync. See also
|
||||
bf(--delete-delay) and bf(--delete-after).
|
||||
|
||||
dit(bf(--delete-before)) Request that the file-deletions on the receiving
|
||||
side be done before the transfer starts. This is the default if bf(--delete)
|
||||
or bf(--delete-excluded) is specified without one of the --delete-WHEN options.
|
||||
side be done before the transfer starts.
|
||||
See bf(--delete) (which is implied) for more details on file-deletion.
|
||||
|
||||
Deleting before the transfer is helpful if the filesystem is tight for space
|
||||
and removing extraneous files would help to make the transfer possible.
|
||||
However, it does introduce a delay before the start of the transfer,
|
||||
and this delay might cause the transfer to timeout (if bf(--timeout) was
|
||||
specified).
|
||||
specified). It also forces rsync to use the old, non-incremental recursion
|
||||
algorithm that requires rsync to scan all the files in the transfer into
|
||||
memory at once (see bf(--recursive)).
|
||||
|
||||
dit(bf(--delete-during, --del)) Request that the file-deletions on the
|
||||
receiving side be done incrementally as the transfer happens. This is
|
||||
@@ -977,11 +1109,22 @@ a faster method than choosing the before- or after-transfer algorithm,
|
||||
but it is only supported beginning with rsync version 2.6.4.
|
||||
See bf(--delete) (which is implied) for more details on file-deletion.
|
||||
|
||||
dit(bf(--delete-delay)) Request that the file-deletions on the receiving
|
||||
side be computed during the transfer, and then removed after the transfer
|
||||
completes. If the number of removed files overflows an internal buffer, a
|
||||
temporary file will be created on the receiving side to hold the names (it
|
||||
is removed while open, so you shouldn't see it during the transfer). If
|
||||
the creation of the temporary file fails, rsync will try to fall back to
|
||||
using bf(--delete-after) (which it cannot do if bf(--recursive) is doing an
|
||||
incremental scan).
|
||||
|
||||
dit(bf(--delete-after)) Request that the file-deletions on the receiving
|
||||
side be done after the transfer has completed. This is useful if you
|
||||
are sending new per-directory merge files as a part of the transfer and
|
||||
you want their exclusions to take effect for the delete phase of the
|
||||
current transfer.
|
||||
current transfer. It also forces rsync to use the old, non-incremental
|
||||
recursion algorithm that requires rsync to scan all the files in the
|
||||
transfer into memory at once (see bf(--recursive)).
|
||||
See bf(--delete) (which is implied) for more details on file-deletion.
|
||||
|
||||
dit(bf(--delete-excluded)) In addition to deleting the files on the
|
||||
@@ -1004,8 +1147,15 @@ using bf(--delete-after), and it used to be non-functional unless the
|
||||
bf(--recursive) option was also enabled.
|
||||
|
||||
dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM
|
||||
files or directories (NUM must be non-zero).
|
||||
This is useful when mirroring very large trees to prevent disasters.
|
||||
files or directories. If that limit is exceeded, a warning is output
|
||||
and rsync exits with an error code of 25 (new for 3.0.0).
|
||||
|
||||
Also new for version 3.0.0, you may specify bf(--max-delete=0) to be warned
|
||||
about any extraneous files in the destination without removing any of them.
|
||||
Older clients interpreted this as "unlimited", so if you don't know what
|
||||
version the client is, you can use the less obvious bf(--max-delete=-1) as
|
||||
a backward-compatible way to specify that no deletions be allowed (though
|
||||
older versions didn't warn when the limit was exceeded).
|
||||
|
||||
dit(bf(--max-size=SIZE)) This tells rsync to avoid transferring any
|
||||
file that is larger than the specified SIZE. The SIZE value can be
|
||||
@@ -1077,20 +1227,21 @@ communicate.
|
||||
One tricky example is to set a different default directory on the remote
|
||||
machine for use with the bf(--relative) option. For instance:
|
||||
|
||||
quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" hst:c/d /e/))
|
||||
quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/))
|
||||
|
||||
dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a
|
||||
broad range of files that you often don't want to transfer between
|
||||
systems. It uses the same algorithm that CVS uses to determine if
|
||||
systems. It uses a similar algorithm to CVS to determine if
|
||||
a file should be ignored.
|
||||
|
||||
The exclude list is initialized to:
|
||||
The exclude list is initialized to exclude the following items (these
|
||||
initial items are marked as perishable -- see the FILTER RULES section):
|
||||
|
||||
quote(quote(tt(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state
|
||||
.nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak *.BAK *.orig *.rej
|
||||
.del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/)))
|
||||
.del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/ .bzr/)))
|
||||
|
||||
then files listed in a $HOME/.cvsignore are added to the list and any
|
||||
then, files listed in a $HOME/.cvsignore are added to the list and any
|
||||
files listed in the CVSIGNORE environment variable (all cvsignore names
|
||||
are delimited by whitespace).
|
||||
|
||||
@@ -1179,7 +1330,7 @@ quote(itemization(
|
||||
bf(--files-from), as does bf(--no-R) and all other options).
|
||||
))
|
||||
|
||||
The file names that are read from the FILE are all relative to the
|
||||
The filenames that are read from the FILE are all relative to the
|
||||
source dir -- any leading slashes are removed and no ".." references are
|
||||
allowed to go higher than the source dir. For example, take this
|
||||
command:
|
||||
@@ -1217,6 +1368,21 @@ merged files specified in a bf(--filter) rule.
|
||||
It does not affect bf(--cvs-exclude) (since all names read from a .cvsignore
|
||||
file are split on whitespace).
|
||||
|
||||
If the bf(--iconv) and bf(--protect-args) options are specified and the
|
||||
bf(--files-from) filenames are being sent from one host to another, the
|
||||
filenames will be translated from the sending host's charset to the
|
||||
receiving host's charset.
|
||||
|
||||
dit(bf(-s, --protect-args)) This option sends all filenames and some options to
|
||||
the remote rsync without allowing the remote shell to interpret them. This
|
||||
means that spaces are not split in names, and any non-wildcard special
|
||||
characters are not translated (such as ~, $, ;, &, etc.). Wildcards are
|
||||
expanded on the remote host by rsync (instead of the shell doing it).
|
||||
|
||||
If you use this option with bf(--iconv), the args will also be translated
|
||||
from the local to the remote character set. The translation happens before
|
||||
wild-cards are expanded. See also the bf(--files-from) option.
|
||||
|
||||
dit(bf(-T, --temp-dir=DIR)) This option instructs rsync to use DIR as a
|
||||
scratch directory when creating temporary copies of the files transferred
|
||||
on the receiving side. The default behavior is to create each temporary
|
||||
@@ -1309,6 +1475,12 @@ and the attributes updated.
|
||||
If a match is not found, a basis file from one of the em(DIR)s will be
|
||||
selected to try to speed up the transfer.
|
||||
|
||||
This option works best when copying into an empty destination hierarchy, as
|
||||
rsync treats existing files as definitive (so it never looks in the link-dest
|
||||
dirs when a destination file already exists), and as malleable (so it might
|
||||
change the attributes of a destination file, which affects all the hard-linked
|
||||
versions).
|
||||
|
||||
Note that if you combine this option with bf(--ignore-times), rsync will not
|
||||
link any files together because it only links identical files together as a
|
||||
substitute for transferring the file, never as an additional check after the
|
||||
@@ -1331,10 +1503,40 @@ be achieved by using a compressing remote shell or a compressing transport
|
||||
because it takes advantage of the implicit information in the matching data
|
||||
blocks that are not explicitly sent over the connection.
|
||||
|
||||
See the bf(--skip-compress) option for the default list of file suffixes
|
||||
that will not be compressed.
|
||||
|
||||
dit(bf(--compress-level=NUM)) Explicitly set the compression level to use
|
||||
(see bf(--compress)) instead of letting it default. If NUM is non-zero,
|
||||
the bf(--compress) option is implied.
|
||||
|
||||
dit(bf(--skip-compress=LIST)) Override the list of file suffixes that will
|
||||
not be compressed. The bf(LIST) should be one or more file suffixes
|
||||
(without the dot) separated by slashes (/).
|
||||
|
||||
You may specify an empty string to indicate that no file should be skipped.
|
||||
|
||||
Simple character-class matching is supported: each must consist of a list
|
||||
of letters inside the square brackets (e.g. no special classes, such as
|
||||
"[:alpha:]", are supported).
|
||||
|
||||
The characters asterisk (*) and question-mark (?) have no special meaning.
|
||||
|
||||
Here's an example that specifies 6 suffixes to skip (since 1 of the 5 rules
|
||||
matches 2 suffixes):
|
||||
|
||||
verb( --skip-compress=gz/jpg/mp[34]/7z/bz2)
|
||||
|
||||
The default list of suffixes that will not be compressed is this (several
|
||||
of these are newly added for 3.0.0):
|
||||
|
||||
verb( gz/zip/z/rpm/deb/iso/bz2/t[gb]z/7z/mp[34]/mov/avi/ogg/jpg/jpeg)
|
||||
|
||||
This list will be replaced by your bf(--skip-compress) list in all but one
|
||||
situation: a copy from a daemon rsync will add your skipped suffixes to
|
||||
its list of non-compressing files (and its list may be configured to a
|
||||
different default).
|
||||
|
||||
dit(bf(--numeric-ids)) With this option rsync will transfer numeric group
|
||||
and user IDs rather than using user and group names and mapping them
|
||||
at both ends.
|
||||
@@ -1389,8 +1591,8 @@ if the receiving rsync is at least version 2.6.7 (you can use bf(-vv)
|
||||
with older versions of rsync, but that also turns on the output of other
|
||||
verbose messages).
|
||||
|
||||
The "%i" escape has a cryptic output that is 9 letters long. The general
|
||||
format is like the string bf(YXcstpogz), where bf(Y) is replaced by the
|
||||
The "%i" escape has a cryptic output that is 11 letters long. The general
|
||||
format is like the string bf(YXcstpoguax), where bf(Y) is replaced by the
|
||||
type of update being done, bf(X) is replaced by the file-type, and the
|
||||
other letters represent attributes that may be output if they are being
|
||||
modified.
|
||||
@@ -1430,16 +1632,20 @@ quote(itemization(
|
||||
by the file transfer.
|
||||
it() A bf(t) means the modification time is different and is being updated
|
||||
to the sender's value (requires bf(--times)). An alternate value of bf(T)
|
||||
means that the time will be set to the transfer time, which happens
|
||||
anytime a symlink is transferred, or when a file or device is transferred
|
||||
without bf(--times).
|
||||
means that the modification time will be set to the transfer time, which happens
|
||||
anytime a symlink is transferred, or when a regular file or device is
|
||||
transferred without bf(--times).
|
||||
it() A bf(p) means the permissions are different and are being updated to
|
||||
the sender's value (requires bf(--perms)).
|
||||
it() An bf(o) means the owner is different and is being updated to the
|
||||
sender's value (requires bf(--owner) and super-user privileges).
|
||||
it() A bf(g) means the group is different and is being updated to the
|
||||
sender's value (requires bf(--group) and the authority to set the group).
|
||||
it() The bf(z) slot is reserved for future use.
|
||||
it() The bf(u) slot is reserved for reporting update (access) time changes
|
||||
(a feature that is not yet released).
|
||||
it() The bf(a) means that the ACL information changed.
|
||||
it() The bf(x) slot is reserved for reporting extended attribute changes
|
||||
(a feature that is not yet released).
|
||||
))
|
||||
|
||||
One other output is possible: when deleting files, the "%i" will output
|
||||
@@ -1563,7 +1769,7 @@ after it has served its purpose.
|
||||
Note that if bf(--whole-file) is specified (or implied), any partial-dir
|
||||
file that is found for a file that is being updated will simply be removed
|
||||
(since
|
||||
rsync is sending files without using the incremental rsync algorithm).
|
||||
rsync is sending files without using the delta transfer algorithm).
|
||||
|
||||
Rsync will create the em(DIR) if it is missing (just the last dir -- not
|
||||
the whole path). This makes it easy to use a relative path (such as
|
||||
@@ -1576,7 +1782,7 @@ rule at the end of all your existing excludes. This will prevent the
|
||||
sending of any partial-dir files that may exist on the sending side, and
|
||||
will also prevent the untimely deletion of partial-dir items on the
|
||||
receiving side. An example: the above bf(--partial-dir) option would add
|
||||
the equivalent of "bf(--exclude=.rsync-partial/)" at the end of any other
|
||||
the equivalent of "bf(-f '-p .rsync-partial/')" at the end of any other
|
||||
filter rules.
|
||||
|
||||
If you are supplying your own exclude rules, you may need to add your own
|
||||
@@ -1618,7 +1824,7 @@ each file's destination directory, but if you've specified the
|
||||
bf(--partial-dir) option, that directory will be used instead. See the
|
||||
comments in the bf(--partial-dir) section for a discussion of how this
|
||||
".~tmp~" dir will be excluded from the transfer, and what you can do if
|
||||
you wnat rsync to cleanup old ".~tmp~" dirs that might be lying around.
|
||||
you want rsync to cleanup old ".~tmp~" dirs that might be lying around.
|
||||
Conflicts with bf(--inplace) and bf(--append).
|
||||
|
||||
This option uses more memory on the receiving side (one bit per file
|
||||
@@ -1663,7 +1869,7 @@ that any superfluous files and directories in the destination are removed
|
||||
quote( rsync -avm --del --include='*.pdf' -f 'hide,! */' src/ dest)
|
||||
|
||||
If you didn't want to remove superfluous destination files, the more
|
||||
time-honored options of "--include='*/' --exclude='*'" would work fine
|
||||
time-honored options of "bf(--include='*/' --exclude='*')" would work fine
|
||||
in place of the hide-filter (if that is more natural to you).
|
||||
|
||||
dit(bf(--progress)) This option tells rsync to print information
|
||||
@@ -1681,7 +1887,7 @@ sender's file, which is being reconstructed at a rate of 110.64 kilobytes
|
||||
per second, and the transfer will finish in 4 seconds if the current rate
|
||||
is maintained until the end.
|
||||
|
||||
These statistics can be misleading if the incremental transfer algorithm is
|
||||
These statistics can be misleading if the delta transfer algorithm is
|
||||
in use. For example, if the sender's file consists of the basis file
|
||||
followed by additional data, the reported rate will probably drop
|
||||
dramatically when the receiver gets to the literal data, and the transfer
|
||||
@@ -1704,12 +1910,14 @@ dit(bf(-P)) The bf(-P) option is equivalent to bf(--partial) bf(--progress). It
|
||||
purpose is to make it much easier to specify these two options for a long
|
||||
transfer that may be interrupted.
|
||||
|
||||
dit(bf(--password-file)) This option allows you to provide a password
|
||||
in a file for accessing a remote rsync daemon. Note that this option
|
||||
is only useful when accessing an rsync daemon using the built in
|
||||
transport, not when using a remote shell as the transport. The file
|
||||
must not be world readable. It should contain just the password as a
|
||||
single line.
|
||||
dit(bf(--password-file)) This option allows you to provide a password in a
|
||||
file for accessing an rsync daemon. The file must not be world readable.
|
||||
It should contain just the password as a single line.
|
||||
|
||||
When accessing an rsync daemon using a remote shell as the transport, this
|
||||
option only comes into effect after the remote shell finishes its
|
||||
authentication (i.e. if you have also specified a password in the daemon's
|
||||
config file).
|
||||
|
||||
dit(bf(--list-only)) This option will cause the source files to be listed
|
||||
instead of transferred. This option is inferred if there is a single source
|
||||
@@ -1767,11 +1975,34 @@ bf(--read-batch) option, you should use "--protocol=28" when creating the
|
||||
batch file to force the older protocol version to be used in the batch
|
||||
file (assuming you can't upgrade the rsync on the reading system).
|
||||
|
||||
dit(bf(--iconv=CONVERT_SPEC)) Rsync can convert filenames between character
|
||||
sets using this option. Using a CONVERT_SPEC of "." tells rsync to look up
|
||||
the default character-set via the locale setting. Alternately, you can
|
||||
fully specify what conversion to do by giving a local and a remote charset
|
||||
separated by a comma (local first), e.g. bf(--iconv=utf8,iso88591).
|
||||
Finally, you can specify a CONVERT_SPEC of "-" to turn off any conversion.
|
||||
The default setting of this option is site-specific, and can also be
|
||||
affected via the RSYNC_ICONV environment variable.
|
||||
|
||||
If you specify the bf(--protect-args) option (bf(-s)), rsync will translate
|
||||
the filenames you specify on the command-line that are being sent to the
|
||||
remote host. See also the bf(--files-from) option.
|
||||
|
||||
Note that rsync does not do any conversion of names in filter files
|
||||
(including include/exclude files). It is up to you to ensure that you're
|
||||
specifying matching rules that can match on both sides of the transfer.
|
||||
For instance, you can specify extra include/exclude rules if there are
|
||||
filename differences on the two sides that need to be accounted for.
|
||||
|
||||
dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6
|
||||
when creating sockets. This only affects sockets that rsync has direct
|
||||
control over, such as the outgoing socket when directly contacting an
|
||||
rsync daemon. See also these options in the bf(--daemon) mode section.
|
||||
|
||||
If rsync was complied without support for IPv6, the bf(--ipv6) option
|
||||
will have no effect. The bf(--version) output will tell you if this
|
||||
is the case.
|
||||
|
||||
dit(bf(--checksum-seed=NUM)) Set the MD4 checksum seed to the integer
|
||||
NUM. This 4 byte checksum seed is included in each block and file
|
||||
MD4 checksum calculation. By default the checksum seed is generated
|
||||
@@ -1854,6 +2085,10 @@ versions of Linux to work around an IPv6 bug in the kernel (if you see
|
||||
an "address already in use" error when nothing else is using the port,
|
||||
try specifying bf(--ipv6) or bf(--ipv4) when starting the daemon).
|
||||
|
||||
If rsync was complied without support for IPv6, the bf(--ipv6) option
|
||||
will have no effect. The bf(--version) output will tell you if this
|
||||
is the case.
|
||||
|
||||
dit(bf(-h, --help)) When specified after bf(--daemon), print a short help
|
||||
page describing the options available for starting an rsync daemon.
|
||||
enddit()
|
||||
@@ -1930,20 +2165,19 @@ itemization(
|
||||
particular spot in the hierarchy of files, otherwise it is matched
|
||||
against the end of the pathname. This is similar to a leading ^ in
|
||||
regular expressions.
|
||||
Thus "/foo" would match a file named "foo" at either the "root of the
|
||||
Thus "/foo" would match a name of "foo" at either the "root of the
|
||||
transfer" (for a global rule) or in the merge-file's directory (for a
|
||||
per-directory rule).
|
||||
An unqualified "foo" would match any file or directory named "foo"
|
||||
anywhere in the tree because the algorithm is applied recursively from
|
||||
the
|
||||
An unqualified "foo" would match a name of "foo" anywhere in the
|
||||
tree because the algorithm is applied recursively from the
|
||||
top down; it behaves as if each path component gets a turn at being the
|
||||
end of the file name. Even the unanchored "sub/foo" would match at
|
||||
end of the filename. Even the unanchored "sub/foo" would match at
|
||||
any point in the hierarchy where a "foo" was found within a directory
|
||||
named "sub". See the section on ANCHORING INCLUDE/EXCLUDE PATTERNS for
|
||||
a full discussion of how to specify a pattern that matches at the root
|
||||
of the transfer.
|
||||
it() if the pattern ends with a / then it will only match a
|
||||
directory, not a file, link, or device.
|
||||
directory, not a regular file, symlink, or device.
|
||||
it() rsync chooses between doing a simple string match and wildcard
|
||||
matching by checking if the pattern contains one of these three wildcard
|
||||
characters: '*', '?', and '[' .
|
||||
@@ -1961,9 +2195,9 @@ itemization(
|
||||
can actually be any portion of a path from the starting directory on
|
||||
down.)
|
||||
it() a trailing "dir_name/***" will match both the directory (as if
|
||||
"dir_name/" had been specified) and all the files in the directory
|
||||
(as if "dir_name/**" had been specified). (This behavior is new for
|
||||
version 2.6.7.)
|
||||
"dir_name/" had been specified) and everything in the directory
|
||||
(as if "dir_name/**" had been specified). This behavior was added in
|
||||
version 2.6.7.
|
||||
)
|
||||
|
||||
Note that, when using the bf(--recursive) (bf(-r)) option (which is implied by
|
||||
@@ -2004,7 +2238,7 @@ tt(- *)nl()
|
||||
Here are some examples of exclude/include matching:
|
||||
|
||||
itemization(
|
||||
it() "- *.o" would exclude all filenames matching *.o
|
||||
it() "- *.o" would exclude all names matching *.o
|
||||
it() "- /foo" would exclude a file (or directory) named foo in the
|
||||
transfer-root directory
|
||||
it() "- foo/" would exclude any directory named foo
|
||||
@@ -2078,13 +2312,13 @@ itemization(
|
||||
The following modifiers are accepted after a "+" or "-":
|
||||
|
||||
itemization(
|
||||
it() A "/" specifies that the include/exclude rule should be matched
|
||||
it() A bf(/) specifies that the include/exclude rule should be matched
|
||||
against the absolute pathname of the current item. For example,
|
||||
"-/ /etc/passwd" would exclude the passwd file any time the transfer
|
||||
was sending files from the "/etc" directory, and "-/ subdir/foo"
|
||||
would always exclude "foo" when it is in a dir named "subdir", even
|
||||
if "foo" is at the root of the current transfer.
|
||||
it() A "!" specifies that the include/exclude should take effect if
|
||||
it() A bf(!) specifies that the include/exclude should take effect if
|
||||
the pattern fails to match. For instance, "-! */" would exclude all
|
||||
non-directories.
|
||||
it() A bf(C) is used to indicate that all the global CVS-exclude rules
|
||||
@@ -2101,6 +2335,11 @@ itemization(
|
||||
being deleted. See the bf(s) modifier for more info. See also the
|
||||
protect (P) and risk (R) rules, which are an alternate way to
|
||||
specify receiver-side includes/excludes.
|
||||
it() A bf(p) indicates that a rule is perishable, meaning that it is
|
||||
ignored in directories that are being deleted. For instance, the bf(-C)
|
||||
option's default rules that exclude things like "CVS" and "*.o" are
|
||||
marked as perishable, and will not prevent a directory that was removed
|
||||
on the source from being deleted on the destination.
|
||||
)
|
||||
|
||||
Per-directory rules are inherited in all subdirectories of the directory
|
||||
@@ -2188,7 +2427,7 @@ that follow the :C instead of being subservient to all your rules. To
|
||||
affect the other CVS exclude rules (i.e. the default list of exclusions,
|
||||
the contents of $HOME/.cvsignore, and the value of $CVSIGNORE) you should
|
||||
omit the bf(-C) command-line option and instead insert a "-C" rule into
|
||||
your filter rules; e.g. "--filter=-C".
|
||||
your filter rules; e.g. "bf(--filter=-C)".
|
||||
|
||||
manpagesection(LIST-CLEARING FILTER RULE)
|
||||
|
||||
@@ -2434,7 +2673,7 @@ unsafe links to be omitted altogether. (Note that you must specify
|
||||
bf(--links) for bf(--safe-links) to have any effect.)
|
||||
|
||||
Symbolic links are considered unsafe if they are absolute symlinks
|
||||
(start with bf(/)), empty, or if they contain enough bf("..")
|
||||
(start with bf(/)), empty, or if they contain enough ".."
|
||||
components to ascend from the directory being copied.
|
||||
|
||||
Here's a summary of how the symlink options are interpreted. The list is
|
||||
@@ -2513,6 +2752,8 @@ startdit()
|
||||
dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any
|
||||
ignore patterns in .cvsignore files. See the bf(--cvs-exclude) option for
|
||||
more details.
|
||||
dit(bf(RSYNC_ICONV)) Specify a default bf(--iconv) setting using this
|
||||
environment variable.
|
||||
dit(bf(RSYNC_RSH)) The RSYNC_RSH environment variable allows you to
|
||||
override the default shell used as the transport for rsync. Command line
|
||||
options are permitted after the command name, just as in the bf(-e) option.
|
||||
@@ -2551,12 +2792,12 @@ values
|
||||
|
||||
see also the comments on the bf(--delete) option
|
||||
|
||||
Please report bugs! See the website at
|
||||
Please report bugs! See the web site at
|
||||
url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 2.6.9 of rsync.
|
||||
This man page is current for version 3.0.0pre2 of rsync.
|
||||
|
||||
manpagesection(INTERNAL OPTIONS)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(6 Nov 2006)()()
|
||||
manpage(rsyncd.conf)(5)(11 Oct 2007)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -17,7 +17,7 @@ manpagesection(FILE FORMAT)
|
||||
|
||||
The file consists of modules and parameters. A module begins with the
|
||||
name of the module in square brackets and continues until the next
|
||||
module begins. Modules contain parameters of the form 'name = value'.
|
||||
module begins. Modules contain parameters of the form "name = value".
|
||||
|
||||
The file is line-based -- that is, each newline-terminated line represents
|
||||
either a comment, a module name or a parameter.
|
||||
@@ -85,7 +85,8 @@ usually contains site information and any legal notices. The default
|
||||
is no motd file.
|
||||
|
||||
dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
|
||||
its process ID to that file.
|
||||
its process ID to that file. If the file already exists, the rsync
|
||||
daemon will abort rather than overwrite the file.
|
||||
|
||||
dit(bf(port)) You can override the default port the daemon will listen on
|
||||
by specifying this value (defaults to 873). This is ignored if the daemon
|
||||
@@ -149,7 +150,7 @@ 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 rsyncd.conf file
|
||||
(e.g. "exclude = /etc/**"). Note that having the exclusion affect uploads
|
||||
(e.g. "bf(exclude = /etc/**)"). Note that having the exclusion affect uploads
|
||||
is a relatively new feature in rsync, so make sure your daemon is
|
||||
at least 2.6.3 to effect this. Also note that it is safest to exclude a
|
||||
directory and all its contents combining the rule "/some/dir/" with the
|
||||
@@ -161,7 +162,8 @@ sure).
|
||||
dit(bf(max connections)) The "max connections" option allows you to
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
Any clients connecting when the maximum has been reached will receive a
|
||||
message telling them to try later. The default is 0 which means no limit.
|
||||
message telling them to try later. The default is 0, which means no limit.
|
||||
A negative value disables the module.
|
||||
See also the "lock file" option.
|
||||
|
||||
dit(bf(log file)) When the "log file" option is set to a non-empty
|
||||
@@ -226,6 +228,11 @@ file transfers to and from that module should take place as when the daemon
|
||||
was run as root. This complements the "uid" option. The default is gid -2,
|
||||
which is normally the group "nobody".
|
||||
|
||||
dit(bf(fake super)) Setting "fake super = yes" for a module causes the
|
||||
daemon side to behave as if the bf(--fake-user) command-line option had
|
||||
been specified. This allows the full attributes of a file to be stored
|
||||
without having to have the daemon actually running as root.
|
||||
|
||||
dit(bf(filter)) The "filter" option allows you to specify a space-separated
|
||||
list of filter rules that the daemon will not allow to be read or written.
|
||||
This is only superficially equivalent to the client specifying these
|
||||
@@ -402,7 +409,7 @@ format used for logging file transfers when transfer logging is enabled.
|
||||
The format is a text string containing embedded single-character escape
|
||||
sequences prefixed with a percent (%) character. An optional numeric
|
||||
field width may also be specified between the percent and the escape
|
||||
letter (e.g. "%-50n %8l %07p").
|
||||
letter (e.g. "bf(%-50n %8l %07p)").
|
||||
|
||||
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
|
||||
is always prefixed when using the "log file" option.
|
||||
@@ -483,7 +490,10 @@ The "dont compress" option takes a space-separated list of
|
||||
case-insensitive wildcard patterns. Any source filename matching one
|
||||
of the patterns will not be compressed during transfer.
|
||||
|
||||
The default setting is tt(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
|
||||
See the bf(--skip-compress) option in the bf(rsync)(1) manpage for the list
|
||||
of file suffixes that are not compressed by default. Specifying a value
|
||||
for the bf(dont compress) option changes the default when the daemon is
|
||||
the sender.
|
||||
|
||||
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
|
||||
@@ -604,7 +614,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 2.6.9 of rsync.
|
||||
This man page is current for version 3.0.0pre2 of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
|
||||
25
runtests.sh
25
runtests.sh
@@ -49,8 +49,8 @@
|
||||
|
||||
# This script must be invoked from the build directory.
|
||||
|
||||
# A scratch directory, 'testtmp', is created in the build directory to
|
||||
# hold working files.
|
||||
# A scratch directory, 'testtmp', is used in the build directory to
|
||||
# hold per-test subdirectories.
|
||||
|
||||
# This script also uses the $loglevel environment variable. 1 is the
|
||||
# default value, and 10 the most verbose. You can set this from the
|
||||
@@ -181,12 +181,15 @@ else
|
||||
echo " preserve_scratch=no"
|
||||
fi
|
||||
|
||||
# Check if setfacl is around and if it supports the -k or -s option.
|
||||
if setfacl --help 2>&1 | grep ' -k,\|\[-[a-z]*k' >/dev/null; then
|
||||
# Check if setacl/setfacl is around and if it supports the -k or -s option.
|
||||
if setacl -k u::7,g::5,o:5 testsuite 2>/dev/null; then
|
||||
setfacl_nodef='setacl -k'
|
||||
elif setfacl --help 2>&1 | grep ' -k,\|\[-[a-z]*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
|
||||
# The "true" command runs successfully, but does nothing.
|
||||
setfacl_nodef=true
|
||||
fi
|
||||
|
||||
@@ -207,22 +210,26 @@ missing=0
|
||||
passed=0
|
||||
failed=0
|
||||
|
||||
# Prefix for scratch directory. We create separate directories for
|
||||
# each test case, so that they can be left behind in case of failure
|
||||
# to aid investigation.
|
||||
# Directory that holds the other test subdirs. We create separate dirs
|
||||
# inside for each test case, so that they can be left behind in case of
|
||||
# failure to aid investigation. We don't remove the testtmp subdir at
|
||||
# the end so that it can be configured as a symlink to a filesystem that
|
||||
# has ACLs and xattr support enabled (if desired).
|
||||
scratchbase="$TOOLDIR"/testtmp
|
||||
echo " scratchbase=$scratchbase"
|
||||
[ -d "$scratchbase" ] || mkdir "$scratchbase"
|
||||
|
||||
suitedir="$srcdir/testsuite"
|
||||
|
||||
export scratchdir suitedir
|
||||
|
||||
prep_scratch() {
|
||||
[ -d "$scratchdir" ] && rm -rf "$scratchdir"
|
||||
[ -d "$scratchdir" ] && chmod -R u+rwX "$scratchdir" && rm -rf "$scratchdir"
|
||||
mkdir "$scratchdir"
|
||||
# Get rid of default ACLs and dir-setgid to avoid confusing some tests.
|
||||
$setfacl_nodef "$scratchdir" || true
|
||||
chmod g-s "$scratchdir"
|
||||
ln -s "$srcdir" "$scratchdir/src"
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -238,7 +245,7 @@ fi
|
||||
for testscript in $suitedir/$whichtests
|
||||
do
|
||||
testbase=`echo $testscript | sed -e 's!.*/!!' -e 's/.test\$//'`
|
||||
scratchdir="$scratchbase.$testbase"
|
||||
scratchdir="$scratchbase/$testbase"
|
||||
|
||||
prep_scratch
|
||||
|
||||
|
||||
230
sender.c
230
sender.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,16 +16,17 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int inc_recurse;
|
||||
extern int log_before_transfer;
|
||||
extern int stdout_format_has_i;
|
||||
extern int logfile_format_has_i;
|
||||
@@ -33,6 +34,7 @@ extern int csum_length;
|
||||
extern int append_mode;
|
||||
extern int io_error;
|
||||
extern int allowed_lull;
|
||||
extern int preserve_xattrs;
|
||||
extern int protocol_version;
|
||||
extern int remove_source_files;
|
||||
extern int updating_basis_file;
|
||||
@@ -42,9 +44,7 @@ extern int inplace;
|
||||
extern int batch_fd;
|
||||
extern int write_batch;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *the_file_list;
|
||||
extern char *stdout_format;
|
||||
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
|
||||
/**
|
||||
* @file
|
||||
@@ -76,7 +76,7 @@ static struct sum_struct *receive_sums(int f)
|
||||
(double)s->count, (long)s->blength, (long)s->remainder);
|
||||
}
|
||||
|
||||
if (append_mode) {
|
||||
if (append_mode > 0) {
|
||||
s->flength = (OFF_T)s->count * s->blength;
|
||||
if (s->remainder)
|
||||
s->flength -= s->blength - s->remainder;
|
||||
@@ -122,31 +122,35 @@ void successful_send(int ndx)
|
||||
{
|
||||
char fname[MAXPATHLEN];
|
||||
struct file_struct *file;
|
||||
unsigned int offset;
|
||||
struct file_list *flist;
|
||||
|
||||
if (ndx < 0 || ndx >= the_file_list->count)
|
||||
if (!remove_source_files)
|
||||
return;
|
||||
|
||||
file = the_file_list->files[ndx];
|
||||
if (file->dir.root) {
|
||||
offset = stringjoin(fname, sizeof fname,
|
||||
file->dir.root, "/", NULL);
|
||||
} else
|
||||
offset = 0;
|
||||
f_name(file, fname + offset);
|
||||
if (remove_source_files) {
|
||||
if (do_unlink(fname) == 0) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "sender removed %s\n", fname + offset);
|
||||
} else
|
||||
rsyserr(FERROR, errno, "sender failed to remove %s", fname + offset);
|
||||
if (!(flist = flist_for_ndx(ndx))) {
|
||||
rprintf(FERROR,
|
||||
"INTERNAL ERROR: unable to find flist for item %d\n",
|
||||
ndx);
|
||||
return;
|
||||
}
|
||||
|
||||
file = flist->files[ndx - flist->ndx_start];
|
||||
if (!push_pathname(F_PATHNAME(file), -1))
|
||||
return;
|
||||
f_name(file, fname);
|
||||
|
||||
if (do_unlink(fname) == 0) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "sender removed %s\n", fname);
|
||||
} else
|
||||
rsyserr(FERROR, errno, "sender failed to remove %s", fname);
|
||||
}
|
||||
|
||||
static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
|
||||
const char *fname, struct file_struct *file,
|
||||
uchar fnamecmp_type, char *buf, int len)
|
||||
{
|
||||
write_int(f_out, ndx);
|
||||
write_ndx(f_out, ndx);
|
||||
if (protocol_version < 29)
|
||||
return;
|
||||
write_shortint(f_out, iflags);
|
||||
@@ -154,118 +158,85 @@ static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
|
||||
write_byte(f_out, fnamecmp_type);
|
||||
if (iflags & ITEM_XNAME_FOLLOWS)
|
||||
write_vstring(f_out, buf, len);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
send_xattr_request(fname, file, f_out);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This is also used by receive.c with f_out = -1. */
|
||||
int read_item_attrs(int f_in, int f_out, int ndx, uchar *type_ptr,
|
||||
char *buf, int *len_ptr)
|
||||
{
|
||||
int len;
|
||||
uchar fnamecmp_type = FNAMECMP_FNAME;
|
||||
int iflags = protocol_version >= 29 ? read_shortint(f_in)
|
||||
: ITEM_TRANSFER | ITEM_MISSING_DATA;
|
||||
|
||||
/* Handle the new keep-alive (no-op) packet. */
|
||||
if (ndx == the_file_list->count && iflags == ITEM_IS_NEW)
|
||||
;
|
||||
else if (ndx < 0 || ndx >= the_file_list->count) {
|
||||
rprintf(FERROR, "Invalid file index: %d (count=%d) [%s]\n",
|
||||
ndx, the_file_list->count, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else if (iflags == ITEM_IS_NEW) {
|
||||
rprintf(FERROR, "Invalid itemized flag word: %x [%s]\n",
|
||||
iflags, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
|
||||
fnamecmp_type = read_byte(f_in);
|
||||
*type_ptr = fnamecmp_type;
|
||||
|
||||
if (iflags & ITEM_XNAME_FOLLOWS) {
|
||||
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
} else {
|
||||
*buf = '\0';
|
||||
len = -1;
|
||||
}
|
||||
*len_ptr = len;
|
||||
|
||||
if (iflags & ITEM_TRANSFER) {
|
||||
if (!S_ISREG(the_file_list->files[ndx]->mode)) {
|
||||
rprintf(FERROR,
|
||||
"received request to transfer non-regular file: %d [%s]\n",
|
||||
ndx, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
} else if (f_out >= 0) {
|
||||
write_ndx_and_attrs(f_out, ndx, iflags,
|
||||
fnamecmp_type, buf, len);
|
||||
}
|
||||
|
||||
return iflags;
|
||||
}
|
||||
|
||||
void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
void send_files(int f_in, int f_out)
|
||||
{
|
||||
int fd = -1;
|
||||
struct sum_struct *s;
|
||||
struct map_struct *mbuf = NULL;
|
||||
STRUCT_STAT st;
|
||||
char *fname2, fname[MAXPATHLEN];
|
||||
char xname[MAXPATHLEN];
|
||||
char fname[MAXPATHLEN], xname[MAXPATHLEN];
|
||||
const char *path, *slash;
|
||||
uchar fnamecmp_type;
|
||||
int iflags, xlen;
|
||||
struct file_struct *file;
|
||||
int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1;
|
||||
struct stats initial_stats;
|
||||
int save_make_backups = make_backups;
|
||||
int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
|
||||
enum logcode log_code = log_before_transfer ? FLOG : FINFO;
|
||||
int f_xfer = write_batch < 0 ? batch_fd : f_out;
|
||||
int i, j;
|
||||
int ndx, j;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files starting\n");
|
||||
|
||||
while (1) {
|
||||
unsigned int offset;
|
||||
if (inc_recurse)
|
||||
send_extra_file_list(f_out, FILECNT_LOOKAHEAD);
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
/* This call also sets cur_flist. */
|
||||
ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (ndx == NDX_DONE) {
|
||||
if (inc_recurse && first_flist) {
|
||||
flist_free(first_flist);
|
||||
if (first_flist) {
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (++phase > max_phase)
|
||||
break;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files phase=%d\n", phase);
|
||||
write_int(f_out, -1);
|
||||
/* For inplace: redo phase turns off the backup
|
||||
* flag so that we do a regular inplace send. */
|
||||
make_backups = 0;
|
||||
append_mode = 0;
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
continue;
|
||||
}
|
||||
|
||||
iflags = read_item_attrs(f_in, f_out, i, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (iflags == ITEM_IS_NEW) /* no-op packet */
|
||||
continue;
|
||||
if (inc_recurse)
|
||||
send_extra_file_list(f_out, FILECNT_LOOKAHEAD);
|
||||
|
||||
file = flist->files[i];
|
||||
if (file->dir.root) {
|
||||
/* N.B. We're sure that this fits, so offset is OK. */
|
||||
offset = strlcpy(fname, file->dir.root, sizeof fname);
|
||||
if (!offset || fname[offset-1] != '/')
|
||||
fname[offset++] = '/';
|
||||
} else
|
||||
offset = 0;
|
||||
fname2 = f_name(file, fname + offset);
|
||||
if (ndx - cur_flist->ndx_start >= 0)
|
||||
file = cur_flist->files[ndx - cur_flist->ndx_start];
|
||||
else
|
||||
file = dir_flist->files[cur_flist->parent_ndx];
|
||||
if (F_PATHNAME(file)) {
|
||||
path = F_PATHNAME(file);
|
||||
slash = "/";
|
||||
} else {
|
||||
path = slash = "";
|
||||
}
|
||||
if (!push_pathname(F_PATHNAME(file), -1))
|
||||
continue;
|
||||
f_name(file, fname);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
|
||||
rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname);
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR)
|
||||
recv_xattr_request(file, f_in);
|
||||
#endif
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
write_ndx_and_attrs(f_out, ndx, iflags, fname, file,
|
||||
fnamecmp_type, xname, xlen);
|
||||
continue;
|
||||
}
|
||||
if (phase == 2) {
|
||||
@@ -275,17 +246,33 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
updating_basis_file = inplace && (protocol_version >= 29
|
||||
? fnamecmp_type == FNAMECMP_FNAME : !make_backups);
|
||||
if (file->flags & FLAG_FILE_SENT) {
|
||||
if (csum_length == SHORT_SUM_LENGTH) {
|
||||
/* For inplace: redo phase turns off the backup
|
||||
* flag so that we do a regular inplace send. */
|
||||
make_backups = -make_backups;
|
||||
append_mode = -append_mode;
|
||||
csum_length = SUM_LENGTH;
|
||||
}
|
||||
} else {
|
||||
if (csum_length != SHORT_SUM_LENGTH) {
|
||||
make_backups = -make_backups;
|
||||
append_mode = -append_mode;
|
||||
csum_length = SHORT_SUM_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
stats.current_file_index = i;
|
||||
updating_basis_file = inplace && (protocol_version >= 29
|
||||
? fnamecmp_type == FNAMECMP_FNAME : make_backups <= 0);
|
||||
|
||||
stats.current_file_index = ndx;
|
||||
stats.num_transferred_files++;
|
||||
stats.total_transferred_size += file->length;
|
||||
stats.total_transferred_size += F_LENGTH(file);
|
||||
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
log_item(FCLIENT, file, &stats, iflags, NULL);
|
||||
write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
|
||||
xname, xlen);
|
||||
write_ndx_and_attrs(f_out, ndx, iflags, fname, file,
|
||||
fnamecmp_type, xname, xlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -294,7 +281,7 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
if (!(s = receive_sums(f_in))) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "receive_sums failed\n");
|
||||
return;
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
@@ -313,6 +300,8 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
full_fname(fname));
|
||||
}
|
||||
free_sums(s);
|
||||
if (protocol_version >= 30)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -322,7 +311,7 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
rsyserr(FERROR, errno, "fstat failed");
|
||||
free_sums(s);
|
||||
close(fd);
|
||||
return;
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (st.st_size) {
|
||||
@@ -332,21 +321,21 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
mbuf = NULL;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
|
||||
fname, (double)st.st_size);
|
||||
rprintf(FINFO, "send_files mapped %s%s%s of size %.0f\n",
|
||||
path,slash,fname, (double)st.st_size);
|
||||
}
|
||||
|
||||
write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type,
|
||||
xname, xlen);
|
||||
write_ndx_and_attrs(f_out, ndx, iflags, fname, file,
|
||||
fnamecmp_type, xname, xlen);
|
||||
write_sum_head(f_xfer, s);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "calling match_sums %s\n", fname);
|
||||
rprintf(FINFO, "calling match_sums %s%s%s\n", path,slash,fname);
|
||||
|
||||
if (log_before_transfer)
|
||||
log_item(FCLIENT, file, &initial_stats, iflags, NULL);
|
||||
else if (!am_server && verbose && do_progress)
|
||||
rprintf(FCLIENT, "%s\n", fname2);
|
||||
rprintf(FCLIENT, "%s\n", fname);
|
||||
|
||||
set_compression(fname);
|
||||
|
||||
@@ -370,17 +359,18 @@ 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", fname);
|
||||
rprintf(FINFO, "sender finished %s%s%s\n", path,slash,fname);
|
||||
|
||||
/* Flag that we actually sent this entry. */
|
||||
file->flags |= FLAG_SENT;
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
if (make_backups < 0)
|
||||
make_backups = -make_backups;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send files finished\n");
|
||||
|
||||
match_report();
|
||||
|
||||
write_int(f_out, -1);
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
}
|
||||
|
||||
77
socket.c
77
socket.c
@@ -3,11 +3,11 @@
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This file is now converted to use the new-style getaddrinfo()
|
||||
@@ -26,6 +25,7 @@
|
||||
* emulate it using the KAME implementation. */
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
@@ -95,7 +95,7 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
buffer);
|
||||
return -1;
|
||||
}
|
||||
for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {}
|
||||
for (cp = &buffer[5]; isDigit(cp) || *cp == '.'; cp++) {}
|
||||
while (*cp == ' ')
|
||||
cp++;
|
||||
if (*cp != '2') {
|
||||
@@ -301,6 +301,42 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
|
||||
{
|
||||
char *prog = getenv("RSYNC_CONNECT_PROG");
|
||||
|
||||
if (prog && strchr(prog, '%')) {
|
||||
int hlen = strlen(host);
|
||||
int len = strlen(prog) + 1;
|
||||
char *f, *t;
|
||||
for (f = prog; *f; f++) {
|
||||
if (*f != '%')
|
||||
continue;
|
||||
/* Compute more than enough room. */
|
||||
if (f[1] == '%')
|
||||
f++;
|
||||
else
|
||||
len += hlen;
|
||||
}
|
||||
f = prog;
|
||||
if (!(prog = new_array(char, len)))
|
||||
out_of_memory("open_socket_out_wrapped");
|
||||
for (t = prog; *f; f++) {
|
||||
if (*f == '%') {
|
||||
switch (*++f) {
|
||||
case '%':
|
||||
/* Just skips the extra '%'. */
|
||||
break;
|
||||
case 'H':
|
||||
memcpy(t, host, hlen);
|
||||
t += hlen;
|
||||
continue;
|
||||
default:
|
||||
f--; /* pass % through */
|
||||
break;
|
||||
}
|
||||
}
|
||||
*t++ = *f;
|
||||
}
|
||||
*t = '\0';
|
||||
}
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
|
||||
prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
|
||||
@@ -410,7 +446,7 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
* 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]));
|
||||
rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0);
|
||||
free(errmsgs[s]);
|
||||
}
|
||||
free(errmsgs);
|
||||
@@ -667,35 +703,6 @@ void set_socket_options(int fd, char *options)
|
||||
free(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Become a daemon, discarding the controlling terminal
|
||||
**/
|
||||
void become_daemon(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (fork()) {
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* detach from the terminal */
|
||||
#ifdef HAVE_SETSID
|
||||
setsid();
|
||||
#elif defined TIOCNOTTY
|
||||
i = open("/dev/tty", O_RDWR);
|
||||
if (i >= 0) {
|
||||
ioctl(i, (int)TIOCNOTTY, (char *)0);
|
||||
close(i);
|
||||
}
|
||||
#endif
|
||||
/* make sure that stdin, stdout an stderr don't stuff things
|
||||
* up (library functions, for example) */
|
||||
for (i = 0; i < 3; i++) {
|
||||
close(i);
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is like socketpair but uses tcp. It is used by the Samba
|
||||
|
||||
@@ -42,7 +42,7 @@ print <<EOT;
|
||||
# and only in the option format that the stock rsync produces.
|
||||
|
||||
# To disable a short-named option, add its letter to this string:
|
||||
our \$short_disabled = '';
|
||||
our \$short_disabled = 's';
|
||||
|
||||
our \$short_no_arg = '$short_no_arg'; # DO NOT REMOVE ANY
|
||||
our \$short_with_num = '$short_with_num'; # DO NOT REMOVE ANY
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# use the -F option, which is easier to type.)
|
||||
#
|
||||
# The downside is that you need to remember to re-run cvs2includes whenever
|
||||
# You add a new file to the project.
|
||||
# you add a new file to the project.
|
||||
use strict;
|
||||
|
||||
open(FIND, 'find . -name CVS -type d |') or die $!;
|
||||
@@ -31,7 +31,7 @@ while (<FIND>) {
|
||||
close ENTRIES;
|
||||
if (@includes) {
|
||||
open(FILTER, ">$filter") or die "Unable to write $filter: $!\n";
|
||||
print FILTER '+ /', join("\n+ /", @includes), "\n";
|
||||
print FILTER map "+ /$_\n", @includes;
|
||||
close FILTER;
|
||||
print "Updated $filter\n";
|
||||
} elsif (-f $filter) {
|
||||
|
||||
@@ -32,15 +32,15 @@ my $detail_line = qr{
|
||||
\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
|
||||
[-r][-w][-xsS] # group-permissions
|
||||
[-r][-w][-xtT] ) \s+ # other-permissions
|
||||
\d+ \s+ # ignore number of links
|
||||
(\S+) \s+ # 5. owner
|
||||
(\S+) \s+ # 6. group
|
||||
(\S+) \s+ # 3. owner
|
||||
(\S+) \s+ # 4. 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
|
||||
([^\r\n]+) $ # 5. name
|
||||
}x;
|
||||
|
||||
while (<>) {
|
||||
|
||||
23
support/lsh
Executable file
23
support/lsh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
# This script can be used as a "remote shell" command that is only
|
||||
# capable of pretending to connect to "localhost". This is useful
|
||||
# for testing or for running a local copy where the sender and the
|
||||
# receiver needs to use different options (e.g. --fake-super). If
|
||||
# we get a -l USER option, we try to use "sudo -u USER" to run the
|
||||
# command.
|
||||
|
||||
prefix=''
|
||||
|
||||
cd # Default path is home dir, just like ssh.
|
||||
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-l) shift ; prefix="sudo -u $1"; shift ;;
|
||||
-l*) prefix=`echo $1 | sed 's/-l/sudo -u /'`; shift ;;
|
||||
-*) shift ;;
|
||||
localhost) shift; break ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
eval $prefix "${@}"
|
||||
@@ -48,9 +48,9 @@ die "$0 -ro: sending to read-only server not allowed\n" if $ro && !$am_sender;
|
||||
# and only in the option format that the stock rsync produces.
|
||||
|
||||
# To disable a short-named option, add its letter to this string:
|
||||
our $short_disabled = '';
|
||||
our $short_disabled = 's';
|
||||
|
||||
our $short_no_arg = 'CDEHIKLORSWbcdgklmnoprtuvxz'; # DO NOT REMOVE ANY
|
||||
our $short_no_arg = 'ACDEHIKLORSWXbcdgklmnoprstuvxz'; # DO NOT REMOVE ANY
|
||||
our $short_with_num = 'B'; # DO NOT REMOVE ANY
|
||||
|
||||
# To disable a long-named option, change its value to a -1. The values mean:
|
||||
@@ -70,6 +70,7 @@ our %long_opt = (
|
||||
'delete' => 0,
|
||||
'delete-after' => 0,
|
||||
'delete-before' => 0,
|
||||
'delete-delay' => 0,
|
||||
'delete-during' => 0,
|
||||
'delete-excluded' => 0,
|
||||
'existing' => 0,
|
||||
@@ -77,6 +78,7 @@ our %long_opt = (
|
||||
'force' => 0,
|
||||
'from0' => 0,
|
||||
'fuzzy' => 0,
|
||||
'iconv' => 1,
|
||||
'ignore-errors' => 0,
|
||||
'ignore-existing' => 0,
|
||||
'inplace' => 0,
|
||||
@@ -87,6 +89,7 @@ our %long_opt = (
|
||||
'max-size' => 1,
|
||||
'min-size' => 1,
|
||||
'modify-window' => 1,
|
||||
'no-i-r' => 0,
|
||||
'no-implied-dirs' => 0,
|
||||
'no-r' => 0,
|
||||
'no-relative' => 0,
|
||||
@@ -101,6 +104,7 @@ our %long_opt = (
|
||||
'sender' => 0,
|
||||
'server' => 0,
|
||||
'size-only' => 0,
|
||||
'skip-compress' => 1,
|
||||
'specials' => 0,
|
||||
'suffix' => 1,
|
||||
'super' => 0,
|
||||
@@ -135,7 +139,7 @@ while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) {
|
||||
if ($_ eq '.') {
|
||||
$in_options = 0;
|
||||
} else {
|
||||
next if /^-$short_no_arg+$/o || /^-$short_with_num\d+$/o;
|
||||
next if /^-$short_no_arg+(e\d+\.\d+)?$/o || /^-$short_with_num\d+$/o;
|
||||
|
||||
my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/;
|
||||
my $disabled;
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
|
||||
#define TIMEOUT_SECONDS 30
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
void run_program(char **command);
|
||||
|
||||
char buf[4096];
|
||||
@@ -64,7 +68,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
set_blocking(fd_file);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
SIGACTION(SIGPIPE, SIG_IGN);
|
||||
|
||||
run_program(argv + 1);
|
||||
|
||||
|
||||
28
syscall.c
28
syscall.c
@@ -4,11 +4,11 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -17,8 +17,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -28,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
extern int dry_run;
|
||||
extern int am_root;
|
||||
extern int read_only;
|
||||
extern int list_only;
|
||||
extern int preserve_perms;
|
||||
@@ -75,10 +75,19 @@ int do_lchown(const char *path, uid_t owner, gid_t group)
|
||||
return lchown(path, owner, group);
|
||||
}
|
||||
|
||||
int do_mknod(char *pathname, mode_t mode, dev_t dev)
|
||||
int do_mknod(const char *pathname, mode_t mode, dev_t dev)
|
||||
{
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
|
||||
/* For --fake-super, we create a normal file with mode 0600. */
|
||||
if (am_root < 0) {
|
||||
int fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
|
||||
if (fd < 0 || close(fd) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
|
||||
if (S_ISFIFO(mode))
|
||||
return mkfifo(pathname, mode);
|
||||
@@ -87,14 +96,15 @@ int do_mknod(char *pathname, mode_t mode, dev_t dev)
|
||||
if (S_ISSOCK(mode)) {
|
||||
int sock;
|
||||
struct sockaddr_un saddr;
|
||||
unsigned int len;
|
||||
|
||||
saddr.sun_family = AF_UNIX;
|
||||
len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
|
||||
#ifdef HAVE_SOCKADDR_UN_LEN
|
||||
unsigned int len =
|
||||
#endif
|
||||
strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
|
||||
#ifdef HAVE_SOCKADDR_UN_LEN
|
||||
saddr.sun_len = len >= sizeof saddr.sun_path
|
||||
? sizeof saddr.sun_path : len + 1;
|
||||
#endif
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0
|
||||
|| (unlink(pathname) < 0 && errno != ENOENT)
|
||||
|
||||
18
t_stub.c
18
t_stub.c
@@ -3,11 +3,11 @@
|
||||
* functions, so that module test harnesses can run standalone.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -16,8 +16,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
@@ -29,6 +28,7 @@ int human_readable = 0;
|
||||
int module_dirlen = 0;
|
||||
mode_t orig_umask = 002;
|
||||
char *partial_dir;
|
||||
char *module_dir;
|
||||
struct filter_list_struct server_filter_list;
|
||||
|
||||
void rprintf(UNUSED(enum logcode code), const char *format, ...)
|
||||
@@ -64,6 +64,11 @@ struct filter_list_struct server_filter_list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int make_bak_dir(UNUSED(const char *fullpath))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *lp_name(UNUSED(int mod))
|
||||
{
|
||||
return NULL;
|
||||
@@ -74,11 +79,6 @@ struct filter_list_struct server_filter_list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *lp_path(UNUSED(int mod))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
{
|
||||
return "tester";
|
||||
|
||||
13
t_unsafe.c
13
t_unsafe.c
@@ -2,11 +2,11 @@
|
||||
* Test harness for unsafe_symlink(). Not linked into rsync itself.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003 Wayne Davison
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
@@ -15,8 +15,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* Prints either "safe" or "unsafe" depending on the two arguments.
|
||||
@@ -24,7 +23,11 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int dry_run, read_only, list_only, verbose;
|
||||
int dry_run = 0;
|
||||
int am_root = 0;
|
||||
int read_only = 0;
|
||||
int list_only = 0;
|
||||
int verbose = 0;
|
||||
int preserve_perms = 0;
|
||||
|
||||
int
|
||||
|
||||
62
testsuite/acls.test
Normal file
62
testsuite/acls.test
Normal file
@@ -0,0 +1,62 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that rsync handles basic ACL preservation.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
|
||||
|
||||
makepath "$fromdir/foo"
|
||||
echo something >"$fromdir/file1"
|
||||
echo else >"$fromdir/file2"
|
||||
|
||||
files='foo file1 file2'
|
||||
|
||||
case "$setfacl_nodef" in
|
||||
true)
|
||||
if ! chmod --help 2>&1 | fgrep +a >/dev/null; then
|
||||
test_skipped "I don't know how to use setfacl or chmod for ACLs"
|
||||
fi
|
||||
chmod +a "root allow read,write,execute" "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled"
|
||||
chmod +a "root allow read,execute" "$fromdir/file1"
|
||||
chmod +a "admin allow read" "$fromdir/file1"
|
||||
chmod +a "daemon allow read,write" "$fromdir/file1"
|
||||
chmod +a "root allow read,execute" "$fromdir/file2"
|
||||
|
||||
see_acls() {
|
||||
ls -le "${@}"
|
||||
}
|
||||
;;
|
||||
*)
|
||||
setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled"
|
||||
setfacl -m g:1:5 "$fromdir/foo"
|
||||
setfacl -m g:2:1 "$fromdir/foo"
|
||||
setfacl -m g:0:7 "$fromdir/foo"
|
||||
setfacl -m u:2:1 "$fromdir/foo"
|
||||
setfacl -m u:1:5 "$fromdir/foo"
|
||||
|
||||
setfacl -m u:0:5 "$fromdir/file1"
|
||||
setfacl -m g:0:4 "$fromdir/file1"
|
||||
setfacl -m u:1:6 "$fromdir/file1"
|
||||
|
||||
setfacl -m u:0:5 "$fromdir/file2"
|
||||
|
||||
see_acls() {
|
||||
getfacl "${@}"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
|
||||
cd "$fromdir"
|
||||
$RSYNC -avvA $files "$todir/"
|
||||
|
||||
see_acls $files >"$scratchdir/acls.txt"
|
||||
|
||||
cd "$todir"
|
||||
see_acls $files | diff $diffopt "$scratchdir/acls.txt" -
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -11,26 +11,26 @@
|
||||
|
||||
bakdir="$tmpdir/bak"
|
||||
|
||||
mkdir "$fromdir" "$bakdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
makepath "$fromdir/deep" "$bakdir"
|
||||
name1="$fromdir/deep/name1"
|
||||
name2="$fromdir/deep/name2"
|
||||
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
cat "$srcdir"/[gr]*.[ch] > "$name1"
|
||||
cat "$srcdir"/[et]*.[ch] > "$name2"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -avv '$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
checkit "$RSYNC -avv '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir"
|
||||
cat "$srcdir"/[fgpr]*.[ch] > "$name1"
|
||||
cat "$srcdir"/[etw]*.[ch] > "$name2"
|
||||
|
||||
$RSYNC -avv --no-whole-file --backup "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
for fn in name1 name2; do
|
||||
for fn in deep/name1 deep/name2; do
|
||||
grep "backed up $fn to $fn~" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
diff $diffopt "$fromdir/$fn" "$todir" || test_fail "copy of $fn failed"
|
||||
diff $diffopt "$fromdir/$fn" "$todir/$fn" || test_fail "copy of $fn failed"
|
||||
diff $diffopt "$chkdir/$fn" "$todir/$fn~" || test_fail "backup of $fn to $fn~ failed"
|
||||
mv "$todir/$fn~" "$todir/$fn"
|
||||
done
|
||||
@@ -38,29 +38,29 @@ done
|
||||
echo deleted-file >"$todir/dname"
|
||||
cp -p "$todir/dname" "$chkdir"
|
||||
|
||||
checkit "$RSYNC -avv --no-whole-file --delete-after \
|
||||
--backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
checkit "$RSYNC -avv --no-whole-file --delete-delay \
|
||||
--backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
for fn in name1 name2; do
|
||||
for fn in deep/name1 deep/name2; do
|
||||
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
done
|
||||
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
|
||||
rm "$bakdir/dname"
|
||||
|
||||
checkit "$RSYNC -avv --del \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
checkit "$RSYNC -avv --del '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir"
|
||||
cat "$srcdir"/[efgr]*.[ch] > "$name1"
|
||||
cat "$srcdir"/[ew]*.[ch] > "$name2"
|
||||
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file --backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
for fn in name1 name2; do
|
||||
for fn in deep/name1 deep/name2; do
|
||||
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
done
|
||||
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
|
||||
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file \"$fromdir/\" \"$bakdir/\"" "$fromdir" "$bakdir"
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file '$fromdir/' '$bakdir/'" "$fromdir" "$bakdir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -16,6 +16,12 @@ cd "$tmpdir"
|
||||
# Build chkdir for the daemon tests using a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
$RSYNC -av --only-write-batch=BATCH --exclude=foobar.baz "$fromdir/" "$todir/missing/"
|
||||
test -d "$todir/missing" && test_fail "--only-write-batch should not have created destination dir"
|
||||
|
||||
runtest "--read-batch (only)" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir" BATCH*
|
||||
runtest "local --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
|
||||
@@ -24,7 +24,7 @@ do
|
||||
done
|
||||
sleep 2
|
||||
|
||||
checkit "$RSYNC -rtgpvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -rtgpvvv '$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -29,24 +29,23 @@ chmod 700 "$dir1"
|
||||
chmod 770 "$dir2"
|
||||
|
||||
# Copy the files we've created over to another directory
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
|
||||
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"
|
||||
checkit "$RSYNC -avv --chmod ug-s,a+rX,D+w '$fromdir/' '$todir/'" "$checkdir" "$todir"
|
||||
|
||||
rm -r "$fromdir" "$checkdir" "$todir"
|
||||
makepath "$todir"
|
||||
makepath "$fromdir/foo"
|
||||
makepath "$todir" "$fromdir/foo"
|
||||
touch "$fromdir/bar"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$checkdir/\"" "$fromdir" "$checkdir"
|
||||
checkit "$RSYNC -avv '$fromdir/' '$checkdir/'" "$fromdir" "$checkdir"
|
||||
chmod o+x "$fromdir"/bar
|
||||
|
||||
checkit "$RSYNC -avv --chmod=Fo-x \"$fromdir/\" \"$todir/\"" "$checkdir" "$todir"
|
||||
checkit "$RSYNC -avv --chmod=Fo-x '$fromdir/' '$todir/'" "$checkdir" "$todir"
|
||||
|
||||
# Tickle a bug in rsync 2.6.8: if you push a new directory with --perms off to
|
||||
# a daemon with an incoming chmod, the daemon pretends the directory is a file
|
||||
@@ -66,7 +65,7 @@ export RSYNC_CONNECT_PROG
|
||||
rm -r "$todir"
|
||||
makepath "$todir"
|
||||
|
||||
checkit "$RSYNC -rtvv \"$fromdir/\" localhost::test-incoming-chmod/" "$checkdir" "$todir"
|
||||
checkit "$RSYNC -avv --no-perms '$fromdir/' localhost::test-incoming-chmod/" "$checkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -13,13 +13,39 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh "$0"
|
||||
fi
|
||||
case $0 in
|
||||
*fake*)
|
||||
$RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
RSYNC="$RSYNC --fake-super"
|
||||
TLS_ARGS=--fake-super
|
||||
case "`xattr 2>&1`" in
|
||||
*--list:*)
|
||||
chown() {
|
||||
own=$1
|
||||
shift
|
||||
xattr -s 'rsync.%stat' "100644 0,0 $own" "${@}"
|
||||
}
|
||||
;;
|
||||
*)
|
||||
chown() {
|
||||
own=$1
|
||||
shift
|
||||
setfattr -n 'user.rsync.%stat' -v "100644 0,0 $own" "${@}"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
RSYNC="$RSYNC --super"
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh "$0"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -31,12 +57,11 @@ name2="$fromdir/name2"
|
||||
echo "This is the file" > "$name1"
|
||||
echo "This is the other file" > "$name2"
|
||||
|
||||
chown 5000 "$name1" || test_skipped "Can't chown (probably need root)"
|
||||
chown 5001 "$name2" || test_skipped "Can't chown (probably need root)"
|
||||
chgrp 5002 "$name1" || test_skipped "Can't chgrp (probably need root)"
|
||||
chgrp 5003 "$name2" || test_skipped "Can't chgrp (probably need root)"
|
||||
chown 5000:5002 "$name1" || test_skipped "Can't chown (probably need root)"
|
||||
chown 5001:5003 "$name2" || test_skipped "Can't chown (probably need root)"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
cd "$fromdir/.."
|
||||
checkit "$RSYNC -aHvv from/ to/" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -27,11 +27,11 @@ $RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/"
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--compare-dest=\"$alt1dir\" --compare-dest=\"$alt2dir\" \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
--compare-dest='$alt1dir' --compare-dest='$alt2dir' \
|
||||
'$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--copy-dest=\"$alt1dir\" --copy-dest=\"$alt2dir\" \
|
||||
\"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
--copy-dest='$alt1dir' --copy-dest='$alt2dir' \
|
||||
'$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -31,7 +31,7 @@ hands_setup
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avvvvz localhost::test-from/ \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avvvvz localhost::test-from/ '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -25,7 +25,7 @@ hands_setup
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avvvvz \"$fromdir/\" localhost::test-to/" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avvvvz '$fromdir/' localhost::test-to/" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
66
testsuite/default-acls.test
Normal file
66
testsuite/default-acls.test
Normal file
@@ -0,0 +1,66 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that rsync obeys default ACLs. -- Matt McCutchen
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
|
||||
|
||||
case "$setfacl_nodef" in
|
||||
true) test_skipped "I don't know how to use your setfacl command" ;;
|
||||
*-k*) opts='-dm u::7,g::5,o:5' ;;
|
||||
*) opts='-m d:u::7,d:g::5,d:o:5' ;;
|
||||
esac
|
||||
setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled"
|
||||
|
||||
# Call as: testit <dirname> <default-acl> <file-expected> <program-expected>
|
||||
testit() {
|
||||
todir="$scratchdir/$1"
|
||||
mkdir "$todir"
|
||||
$setfacl_nodef "$todir"
|
||||
if [ "$2" ]; then
|
||||
case "$setfacl_nodef" in
|
||||
*-k*) opts="-dm $2" ;;
|
||||
*) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`"
|
||||
esac
|
||||
setfacl $opts "$todir"
|
||||
fi
|
||||
# Make sure we obey ACLs 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" $4 "Target $1"
|
||||
check_perms "$todir/to/dir" $4 "Target $1"
|
||||
check_perms "$todir/to/file" $3 "Target $1"
|
||||
check_perms "$todir/to/program" $4 "Target $1"
|
||||
# Make sure get_local_name doesn't mess us up when transferring only one file
|
||||
$RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile"
|
||||
check_perms "$todir/to/anotherfile" $3 "Target $1"
|
||||
# Make sure we obey default ACLs when not transferring a regular file
|
||||
$RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/"
|
||||
check_perms "$todir/to/anotherdir" $4 "Target $1"
|
||||
}
|
||||
|
||||
mkdir "$scratchdir/dir"
|
||||
echo "File!" >"$scratchdir/file"
|
||||
echo "#!/bin/sh" >"$scratchdir/program"
|
||||
chmod 777 "$scratchdir/dir"
|
||||
chmod 666 "$scratchdir/file"
|
||||
chmod 777 "$scratchdir/program"
|
||||
|
||||
# Test some target directories
|
||||
umask 0077
|
||||
testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx
|
||||
testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x
|
||||
testit da750 u::7,g::5,o:0 rw-r----- rwxr-x---
|
||||
testit da750mask u::7,u:0:7,g::7,m:5,o:0 rw-r----- rwxr-x---
|
||||
testit noda1 '' rw------- rwx------
|
||||
umask 0000
|
||||
testit noda2 '' rw-rw-rw- rwxrwxrwx
|
||||
umask 0022
|
||||
testit noda3 '' rw-r--r-- rwxr-xr-x
|
||||
|
||||
# Hooray
|
||||
exit 0
|
||||
@@ -11,15 +11,31 @@
|
||||
|
||||
hands_setup
|
||||
|
||||
makepath "$chkdir"
|
||||
makepath "$chkdir" "$todir/extradir" "$todir/emptydir/subdir"
|
||||
|
||||
echo extra >"$todir"/remove1
|
||||
echo extra >"$todir"/remove2
|
||||
echo extra >"$todir"/extradir/remove3
|
||||
echo extra >"$todir"/emptydir/subdir/remove4
|
||||
|
||||
# Create two chk dirs, one with a copy of the source files, and one with
|
||||
# what we expect to be left behind by the copy using --remove-sent-files.
|
||||
$RSYNC -av "$fromdir/" "$chkdir/copy/"
|
||||
# what we expect to be left behind by the copy using --remove-source-files.
|
||||
# Also, make sure that --dry-run --del doesn't output anything extraneous.
|
||||
$RSYNC -av "$fromdir/" "$chkdir/copy/" >"$tmpdir/copy.out" 2>&1
|
||||
cat "$tmpdir/copy.out"
|
||||
egrep -v '^(created directory|sent|total size) ' "$tmpdir/copy.out" >"$tmpdir/copy.new"
|
||||
mv "$tmpdir/copy.new" "$tmpdir/copy.out"
|
||||
|
||||
$RSYNC -avn --del "$fromdir/" "$chkdir/copy2/" >"$tmpdir/copy2.out" 2>&1 || true
|
||||
cat "$tmpdir/copy2.out"
|
||||
egrep -v '^(created directory|sent|total size) ' "$tmpdir/copy2.out" >"$tmpdir/copy2.new"
|
||||
mv "$tmpdir/copy2.new" "$tmpdir/copy2.out"
|
||||
|
||||
diff $diffopt "$tmpdir/copy.out" "$tmpdir/copy2.out"
|
||||
|
||||
$RSYNC -av -f 'exclude,! */' "$fromdir/" "$chkdir/empty/"
|
||||
|
||||
checkit "$RSYNC -avv --remove-sent-files \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir/copy" "$todir"
|
||||
checkit "$RSYNC -avv --del --remove-source-files '$fromdir/' '$todir/'" "$chkdir/copy" "$todir"
|
||||
|
||||
diff -r "$chkdir/empty" "$fromdir"
|
||||
|
||||
@@ -33,9 +49,9 @@ touch "$todir/foo" "$todir/bar" "$todir/baz"
|
||||
|
||||
$RSYNC -r --exclude=baz --filter=': filters' --delete-excluded "$fromdir/" "$todir/"
|
||||
|
||||
test -f "$todir/foo" || test_fail "rsync deleted $todir/foo"
|
||||
test -f "$todir/bar" && test_fail "rsync did not delete $todir/bar"
|
||||
test -f "$todir/baz" && test_fail "rsync did not delete $todir/baz"
|
||||
test -f "$todir/foo" || test_fail "rsync should NOT have deleted $todir/foo"
|
||||
test -f "$todir/bar" && test_fail "rsync SHOULD have deleted $todir/bar"
|
||||
test -f "$todir/baz" && test_fail "rsync SHOULD have deleted $todir/baz"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -14,14 +14,53 @@ outfile="$scratchdir/rsync.out"
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh $RUNSHFLAGS "$0"
|
||||
fi
|
||||
test_skipped "Rsync won't copy devices unless we're root"
|
||||
case $0 in
|
||||
*fake*)
|
||||
$RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
RSYNC="$RSYNC --fake-super"
|
||||
TLS_ARGS=--fake-super
|
||||
case "`xattr 2>&1`" in
|
||||
*--list:*)
|
||||
mknod() {
|
||||
fn="$1"
|
||||
case "$2" in
|
||||
p) mode=10644 ;;
|
||||
c) mode=20644 ;;
|
||||
b) mode=60644 ;;
|
||||
esac
|
||||
maj="${3:-0}"
|
||||
min="${4:-0}"
|
||||
touch "$fn"
|
||||
xattr -s 'rsync.%stat' "$mode $maj,$min 0:0" "$fn"
|
||||
}
|
||||
;;
|
||||
*)
|
||||
mknod() {
|
||||
fn="$1"
|
||||
case "$2" in
|
||||
p) mode=10644 ;;
|
||||
c) mode=20644 ;;
|
||||
b) mode=60644 ;;
|
||||
esac
|
||||
maj="${3:-0}"
|
||||
min="${4:-0}"
|
||||
touch "$fn"
|
||||
setfattr -n 'user.rsync.%stat' -v "$mode $maj,$min 0:0" "$fn"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
echo "Let's try re-running the script under fakeroot..."
|
||||
exec /usr/bin/fakeroot /bin/sh $RUNSHFLAGS "$0"
|
||||
fi
|
||||
test_skipped "Rsync needs root/fakeroot for device tests"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -29,27 +68,27 @@ esac
|
||||
|
||||
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"
|
||||
mknod "$fromdir/char" c 41 67 || test_skipped "Can't create char device node"
|
||||
mknod "$fromdir/char2" c 42 68 || test_skipped "Can't create char device node"
|
||||
mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node"
|
||||
mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node"
|
||||
mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node"
|
||||
mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node"
|
||||
ln "$fromdir/block3" "$fromdir/block2.5" || echo "Skipping hard-linked device test..."
|
||||
mkfifo "$fromdir/fifo" || test_skipped "Can't run mkfifo"
|
||||
mkfifo "$fromdir/fifo" || mknod "$fromdir/fifo" p || test_skipped "Can't run mkfifo"
|
||||
touch -r "$fromdir/block" "$fromdir/block2"
|
||||
|
||||
$RSYNC -ai "$fromdir/block" "$todir/block2" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD+++++++ block
|
||||
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
|
||||
cD+++++++++ block2
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
|
||||
|
||||
@@ -58,7 +97,7 @@ sleep 1
|
||||
$RSYNC -Di "$fromdir/block3" "$todir/block" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD..T.... block3
|
||||
cD..T...... block3
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
@@ -66,19 +105,18 @@ $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
|
||||
.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"
|
||||
if test ! -r "$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"
|
||||
@@ -89,5 +127,23 @@ echo ""
|
||||
( cd "$todir" && rsync_ls_lR . ) > "$tmpdir/ls-to"
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to"
|
||||
|
||||
if test -b "$fromdir/block2.5"; then
|
||||
set -x
|
||||
$RSYNC -aii --link-dest="$todir" "$fromdir/" "$chkdir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cd ./
|
||||
hD block
|
||||
hD block2
|
||||
hD block2.5
|
||||
hD block3
|
||||
hD char
|
||||
hD char2
|
||||
hD char3
|
||||
hS fifo
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
|
||||
fi
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -31,7 +31,7 @@ ln -s "$name1" "$name2" || fail "can't create symlink"
|
||||
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
checkit "$RSYNC -avv '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$todir/'" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
# Make sure each file was only copied once...
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of exclude/include directives.
|
||||
# Test rsync handling of exclude/include directives.
|
||||
|
||||
# Test some of the more obscure wildcard handling of exclude/include
|
||||
# processing.
|
||||
@@ -76,7 +76,6 @@ EOF
|
||||
echo cvsin >"$fromdir/mid/for/one-in-one-out"
|
||||
echo expunged >"$fromdir/mid/for/foo/extra"
|
||||
echo retained >"$fromdir/mid/for/foo/keep"
|
||||
ln -s too "$fromdir/bar/down/to/foo/sym"
|
||||
|
||||
# Setup our test exclude/include files.
|
||||
|
||||
@@ -106,12 +105,17 @@ cat >"$scratchdir/.cvsignore" <<EOF
|
||||
home-cvs-exclude
|
||||
EOF
|
||||
|
||||
# Create the chk dir with what we expect to be excluded
|
||||
# Start with a check of --prune-empty-dirs:
|
||||
$RSYNC -av -f -_foo/too/ -f -_foo/down/ -f -_foo/and/ -f -_new/ "$fromdir/" "$chkdir/"
|
||||
checkit "$RSYNC -av --prune-empty-dirs '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
rm -rf "$todir"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
# Add a directory symlink.
|
||||
ln -s too "$fromdir/bar/down/to/foo/sym"
|
||||
|
||||
# Create chkdir with what we expect to be excluded.
|
||||
checkit "$RSYNC -avv '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir"
|
||||
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
|
||||
@@ -126,8 +130,8 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files.
|
||||
|
||||
checkit "$RSYNC -avv --exclude-from=\"$excl\" \
|
||||
--delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv --exclude-from='$excl' \
|
||||
--delete-during '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir by removing cvs-ignored files and then tweaking the dir times.
|
||||
|
||||
@@ -142,8 +146,8 @@ $RSYNC -av --existing --filter='exclude,! */' "$fromdir/" "$chkdir/"
|
||||
# Now, test if rsync excludes the same files, this time with --cvs-exclude
|
||||
# and --delete-excluded.
|
||||
|
||||
checkit "$RSYNC -avvC --filter=\"merge $excl\" --delete-excluded \
|
||||
--delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avvC --filter='merge $excl' --delete-excluded \
|
||||
--delete-during '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir for our merge-exclude test and then tweak the dir times.
|
||||
|
||||
@@ -162,9 +166,9 @@ $RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
# Now, test if rsync excludes the same files, this time with a merge-exclude
|
||||
# file.
|
||||
|
||||
checkit "sed '/!/d' \"$excl\" |
|
||||
checkit "sed '/!/d' '$excl' |
|
||||
$RSYNC -avv -f dir-merge_.filt -f merge_- \
|
||||
--delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
--delete-during '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Remove the files that will be deleted.
|
||||
|
||||
@@ -180,9 +184,9 @@ $RSYNC -av --protocol=28 --existing --include='*/' --exclude='*' "$fromdir/" "$c
|
||||
# Now, try the prior command with --delete-before and some side-specific
|
||||
# rules.
|
||||
|
||||
checkit "sed '/!/d' \"$excl\" |
|
||||
checkit "sed '/!/d' '$excl' |
|
||||
$RSYNC -avv -f :s_.filt -f .s_- -f P_nodel.deep \
|
||||
--delete-before \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
--delete-before '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Next, we'll test some rule-restricted filter files.
|
||||
|
||||
@@ -201,15 +205,15 @@ $RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --delete-excluded --exclude='*' "$fromdir/" "$todir/"
|
||||
|
||||
checkit "$RSYNC -avv -f dir-merge,-_.excl \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
'$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"
|
||||
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
|
||||
|
||||
@@ -14,10 +14,11 @@ mkdir "$todir"
|
||||
|
||||
cp -p "$srcdir"/rsync.c "$fromdir"/rsync.c
|
||||
cp -p "$fromdir"/rsync.c "$todir"/rsync2.c
|
||||
sleep 1
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avvi --no-whole-file --fuzzy --delete-after \
|
||||
\"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -avvi --no-whole-file --fuzzy --delete-delay \
|
||||
'$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user