mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-03 18:11:32 +02:00
Compare commits
1111 Commits
v2.3.3
...
v2.5.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95297e23bf | ||
|
|
13d0595296 | ||
|
|
88abf43bda | ||
|
|
de77514671 | ||
|
|
5c69130300 | ||
|
|
74e412c789 | ||
|
|
5811c74f9c | ||
|
|
57a2881906 | ||
|
|
c625d8e3b7 | ||
|
|
53f52b4cf5 | ||
|
|
293c2b4f79 | ||
|
|
29349d4b3a | ||
|
|
7790953a2c | ||
|
|
e3083d6791 | ||
|
|
8f9f2b5462 | ||
|
|
70b1deb226 | ||
|
|
2b112b8dcf | ||
|
|
9350b4458c | ||
|
|
2870715fff | ||
|
|
b0aa3a1da0 | ||
|
|
0cd2540a69 | ||
|
|
e680b3f3c8 | ||
|
|
2493cbe491 | ||
|
|
394ef439e0 | ||
|
|
309c53ca8f | ||
|
|
2638332dc6 | ||
|
|
5308fc4148 | ||
|
|
ad5fbfe05b | ||
|
|
b1224cff0c | ||
|
|
ce06c96135 | ||
|
|
1c4592339a | ||
|
|
0365653055 | ||
|
|
d8078d43fb | ||
|
|
fabc706e43 | ||
|
|
e7e8a62bb7 | ||
|
|
f396f2f41d | ||
|
|
8d14f4357a | ||
|
|
34d40e6c67 | ||
|
|
c80ee0ea48 | ||
|
|
fb71a90756 | ||
|
|
41dc87c748 | ||
|
|
8b952d3741 | ||
|
|
33b0726390 | ||
|
|
40e23d3da7 | ||
|
|
97ff3dccb8 | ||
|
|
fd18ece619 | ||
|
|
fe5e5fcb32 | ||
|
|
0f57326057 | ||
|
|
886f31456a | ||
|
|
2d7841204c | ||
|
|
5f6f5f5789 | ||
|
|
64e351c6d3 | ||
|
|
5e4aca8988 | ||
|
|
d917f52779 | ||
|
|
cca7914204 | ||
|
|
974b6a8845 | ||
|
|
52aa5754c3 | ||
|
|
2bfcd60d18 | ||
|
|
2e64b291da | ||
|
|
ce42080cc7 | ||
|
|
600a98e2e9 | ||
|
|
a547e228d3 | ||
|
|
369d833610 | ||
|
|
80e0f03f1b | ||
|
|
63935f086d | ||
|
|
905877ecc0 | ||
|
|
af4e40c3fc | ||
|
|
e9ac35b2e5 | ||
|
|
ce260909a8 | ||
|
|
d1304b2c05 | ||
|
|
6b3f9ee4c9 | ||
|
|
b7eb9b2040 | ||
|
|
0ce287d96d | ||
|
|
5e13d519d9 | ||
|
|
2c53025b0a | ||
|
|
0d51b32722 | ||
|
|
489342018f | ||
|
|
e5dd54d4f4 | ||
|
|
f470b045d7 | ||
|
|
2b7a726acf | ||
|
|
7cac493a6e | ||
|
|
ad917d038f | ||
|
|
7710b66498 | ||
|
|
0a14fce639 | ||
|
|
642ed1bb70 | ||
|
|
3f9c10e641 | ||
|
|
4327fede32 | ||
|
|
8b45fbfdab | ||
|
|
2696c520bd | ||
|
|
1ab3a9fc13 | ||
|
|
9d4ece4b3a | ||
|
|
e9db52a378 | ||
|
|
fc73cde10c | ||
|
|
44071f0892 | ||
|
|
529649254b | ||
|
|
1ec5d5b0cf | ||
|
|
7053a9c3d9 | ||
|
|
5ccf5fd9a1 | ||
|
|
6520263244 | ||
|
|
9555f8d75c | ||
|
|
073de7a8e0 | ||
|
|
397206134f | ||
|
|
a12986a952 | ||
|
|
5270b76520 | ||
|
|
f0dae03d06 | ||
|
|
4268f793fb | ||
|
|
1ef7ca1b09 | ||
|
|
dd5265a5f8 | ||
|
|
84a692435e | ||
|
|
c1fb5e6b20 | ||
|
|
e0b554ada9 | ||
|
|
1508b562ad | ||
|
|
4390bbf838 | ||
|
|
a4d049464b | ||
|
|
0073b7581f | ||
|
|
1ce3e4c27a | ||
|
|
69e5d55956 | ||
|
|
7cce30942e | ||
|
|
71db7fef77 | ||
|
|
b6f1ba38a6 | ||
|
|
f6a075ef54 | ||
|
|
c5701f635a | ||
|
|
2bf1f27c80 | ||
|
|
a5271b529b | ||
|
|
7c558394c1 | ||
|
|
d2d5439c5c | ||
|
|
c82aa10a66 | ||
|
|
38f1c5b7d2 | ||
|
|
985a657f48 | ||
|
|
9e8464e114 | ||
|
|
02b818af04 | ||
|
|
0fdfb2cba3 | ||
|
|
a9561f494b | ||
|
|
b7412a4f09 | ||
|
|
ba1309b3a4 | ||
|
|
70b4dc99dc | ||
|
|
65a2b1aa8a | ||
|
|
fb3e3edcbd | ||
|
|
c2f84d7c3e | ||
|
|
8358dabbfd | ||
|
|
8b6ae04155 | ||
|
|
87433bfe87 | ||
|
|
9bd583b0e5 | ||
|
|
01bb241e48 | ||
|
|
e2f2c9a153 | ||
|
|
a41d385607 | ||
|
|
a8b4526d65 | ||
|
|
a2191474eb | ||
|
|
cc8497916d | ||
|
|
798e60c9f6 | ||
|
|
57044c1e02 | ||
|
|
daa26d0c81 | ||
|
|
9ed937a6d3 | ||
|
|
5509cd2504 | ||
|
|
fa6ac9da23 | ||
|
|
78e80e5d46 | ||
|
|
2c18ea0a89 | ||
|
|
93d8810414 | ||
|
|
aaa00c1f30 | ||
|
|
2728c49649 | ||
|
|
1449426aee | ||
|
|
aceff1f863 | ||
|
|
113f56fdc5 | ||
|
|
bd9ec3dbee | ||
|
|
6fcff62e95 | ||
|
|
abc3667048 | ||
|
|
894686e66a | ||
|
|
db64b217b8 | ||
|
|
7e5edac9ce | ||
|
|
ca36da6037 | ||
|
|
73777beb00 | ||
|
|
eef275a1e4 | ||
|
|
1114b8ce0a | ||
|
|
716be66234 | ||
|
|
2298ecca7c | ||
|
|
0f5a43797a | ||
|
|
268eae1da6 | ||
|
|
d128608f21 | ||
|
|
cbcd3a05e7 | ||
|
|
42b254785e | ||
|
|
d6b16c3c06 | ||
|
|
55414d4c1d | ||
|
|
3bafa1ec89 | ||
|
|
dfc0545994 | ||
|
|
71de396a5d | ||
|
|
f9299826b1 | ||
|
|
e9646364a0 | ||
|
|
75241c6cd6 | ||
|
|
fc4582ddf6 | ||
|
|
02a2056543 | ||
|
|
afec3ccf6e | ||
|
|
49b1a32251 | ||
|
|
a450859789 | ||
|
|
8b1b572935 | ||
|
|
cc4149c125 | ||
|
|
073fda3d03 | ||
|
|
6f44cc3d98 | ||
|
|
9f346037ee | ||
|
|
39d909b05a | ||
|
|
28f68369be | ||
|
|
2641a6af21 | ||
|
|
d69936e065 | ||
|
|
1ac45be94e | ||
|
|
3d002468ae | ||
|
|
5e75d224ee | ||
|
|
8e7f7cfec8 | ||
|
|
31f13c8846 | ||
|
|
25deaed9e5 | ||
|
|
17342031d7 | ||
|
|
26b991c0c0 | ||
|
|
3f4d504c34 | ||
|
|
6a4486df3b | ||
|
|
9516519165 | ||
|
|
7739157bfc | ||
|
|
b34878c16d | ||
|
|
962c38583f | ||
|
|
9bd30cf003 | ||
|
|
20881cd004 | ||
|
|
e5b93c7584 | ||
|
|
24e2c809e4 | ||
|
|
75a269acb6 | ||
|
|
8357f1ea9a | ||
|
|
20bd943a87 | ||
|
|
424898603a | ||
|
|
c1592e34c7 | ||
|
|
edacaae15f | ||
|
|
29557ea550 | ||
|
|
37a93dca63 | ||
|
|
b632b7e0fa | ||
|
|
fc8e3b0914 | ||
|
|
861d777899 | ||
|
|
ff3e3ce886 | ||
|
|
d69e9ebf46 | ||
|
|
24bf1b3629 | ||
|
|
94b0c9f78e | ||
|
|
567f7eb205 | ||
|
|
a89508ba26 | ||
|
|
c3c8ab85ec | ||
|
|
0bf0f92949 | ||
|
|
04f8d0f2bc | ||
|
|
4584e5d3c5 | ||
|
|
d1c887d754 | ||
|
|
bbf1843865 | ||
|
|
b6aaa6fd2b | ||
|
|
0031e09410 | ||
|
|
0071011ebf | ||
|
|
978a129eed | ||
|
|
991f4faafb | ||
|
|
371acb296d | ||
|
|
86b30e36c2 | ||
|
|
7132e88f8e | ||
|
|
1119bcf539 | ||
|
|
d67018311f | ||
|
|
50c8ec8fd9 | ||
|
|
eaecec418e | ||
|
|
2e2ffca9e2 | ||
|
|
ab27bcacdf | ||
|
|
536a051460 | ||
|
|
427bb83f0d | ||
|
|
faec059a9b | ||
|
|
641eddfbdf | ||
|
|
61869bb65e | ||
|
|
797473ba1f | ||
|
|
f82d61ea19 | ||
|
|
ec281654ae | ||
|
|
52dfe589ba | ||
|
|
a5aebac6a7 | ||
|
|
13eb64584f | ||
|
|
259a117db5 | ||
|
|
2041f1ace8 | ||
|
|
08f402d264 | ||
|
|
d8084e2b18 | ||
|
|
7d03e47fea | ||
|
|
f5f68c0bc0 | ||
|
|
167939a8c9 | ||
|
|
41ebfb635e | ||
|
|
017b8e9de3 | ||
|
|
6453c57979 | ||
|
|
7606184b31 | ||
|
|
5ff2b5b0a3 | ||
|
|
7397565274 | ||
|
|
4a19a8d644 | ||
|
|
a01c73be19 | ||
|
|
f63737ecb0 | ||
|
|
dd87799a82 | ||
|
|
302c60fe15 | ||
|
|
22c7002d59 | ||
|
|
9968142976 | ||
|
|
75a6783a79 | ||
|
|
18afe6a395 | ||
|
|
da6b515bfc | ||
|
|
f9a03fa288 | ||
|
|
a5c66cf289 | ||
|
|
41b908e293 | ||
|
|
6ffed87b08 | ||
|
|
f6331951eb | ||
|
|
7897b386b6 | ||
|
|
bd5ea43547 | ||
|
|
159899d3ba | ||
|
|
48dd8ed6c2 | ||
|
|
8ba27cb0f1 | ||
|
|
1ab8bb62ae | ||
|
|
6f8248ebfd | ||
|
|
33306dcc38 | ||
|
|
ed2dfcf399 | ||
|
|
6fc3bfc265 | ||
|
|
129b814931 | ||
|
|
888818a9f7 | ||
|
|
aee72ae098 | ||
|
|
766f8c2006 | ||
|
|
d43439ebd9 | ||
|
|
f7caf13873 | ||
|
|
d90229242e | ||
|
|
b14ba325d5 | ||
|
|
628e310501 | ||
|
|
6c1a73b67a | ||
|
|
4a47f7e438 | ||
|
|
131647442f | ||
|
|
01b79f2ff1 | ||
|
|
73062e21a3 | ||
|
|
e7e6584cab | ||
|
|
7373c68aeb | ||
|
|
13f1122c50 | ||
|
|
ba5fb5aca7 | ||
|
|
c4543c58ea | ||
|
|
55a91926c1 | ||
|
|
b5e129aa6b | ||
|
|
9fc175231d | ||
|
|
4dd0a75cce | ||
|
|
3cfd502f7e | ||
|
|
452a99f7d3 | ||
|
|
a9d37a0784 | ||
|
|
22b19636e9 | ||
|
|
6ee3310e2b | ||
|
|
065b1eed11 | ||
|
|
7860876b54 | ||
|
|
dbc2d4a8b6 | ||
|
|
7eb2dc21af | ||
|
|
3aeeb11135 | ||
|
|
e338739d83 | ||
|
|
8fb9700869 | ||
|
|
f95e044206 | ||
|
|
795ab29514 | ||
|
|
72262b565e | ||
|
|
cedf72825b | ||
|
|
06a86033c1 | ||
|
|
e17d5defe3 | ||
|
|
959d60e957 | ||
|
|
31f516f390 | ||
|
|
b6835186a3 | ||
|
|
c32ba4aee3 | ||
|
|
e720f84005 | ||
|
|
ec26388826 | ||
|
|
f0822d648d | ||
|
|
14f60a4238 | ||
|
|
f8022bb248 | ||
|
|
48ef2e4563 | ||
|
|
a0d9fc4354 | ||
|
|
e4b2d27c65 | ||
|
|
d1aacac294 | ||
|
|
e322bd706f | ||
|
|
c846a329a8 | ||
|
|
de929eb566 | ||
|
|
c5d37dfedc | ||
|
|
eae00f9969 | ||
|
|
c1bf90ddad | ||
|
|
02988229b1 | ||
|
|
b418bf6db4 | ||
|
|
72b9beb79c | ||
|
|
883080b557 | ||
|
|
ebfac84c69 | ||
|
|
3c2622d2de | ||
|
|
982c591ec9 | ||
|
|
1782ae3c08 | ||
|
|
72363155d8 | ||
|
|
f254ee3211 | ||
|
|
59f2e0634e | ||
|
|
32bb1e6763 | ||
|
|
497b327d43 | ||
|
|
d831369f86 | ||
|
|
c1a1e55207 | ||
|
|
c3dbb20ce3 | ||
|
|
e2b89c5afe | ||
|
|
ba4712c922 | ||
|
|
a19eb59461 | ||
|
|
484ec95596 | ||
|
|
5a97ddde5a | ||
|
|
b8539eb329 | ||
|
|
b9c7aa8df3 | ||
|
|
6f5b3eb4d7 | ||
|
|
127e675838 | ||
|
|
c1b5412c16 | ||
|
|
217c6bbcaf | ||
|
|
a32b3e565b | ||
|
|
926609bd74 | ||
|
|
486ccaff56 | ||
|
|
e0cc93c047 | ||
|
|
4337e8532e | ||
|
|
a8a6f82270 | ||
|
|
4895b848c8 | ||
|
|
fe3c68b9dd | ||
|
|
24d6fda360 | ||
|
|
d4106b9a88 | ||
|
|
2a14ba5582 | ||
|
|
2a842a5745 | ||
|
|
cfe9909560 | ||
|
|
8331f04b5b | ||
|
|
d0713d018c | ||
|
|
a33fc2a0db | ||
|
|
ca200e788e | ||
|
|
7839c4d4e1 | ||
|
|
c454d626b6 | ||
|
|
969d90d15b | ||
|
|
d8a279c671 | ||
|
|
6d56f30d9b | ||
|
|
86ea5876cd | ||
|
|
bb8468c627 | ||
|
|
fc62e9e9d9 | ||
|
|
15967b1219 | ||
|
|
0656c77da8 | ||
|
|
81c20352e1 | ||
|
|
4e52ee9ebd | ||
|
|
6ee87a77cc | ||
|
|
539d6fd92e | ||
|
|
da98e2aa28 | ||
|
|
1f9763eda9 | ||
|
|
cbf470f17b | ||
|
|
1f12d6344b | ||
|
|
437d45981e | ||
|
|
3ae327ea8e | ||
|
|
1c721e9422 | ||
|
|
5d0aa5f039 | ||
|
|
41798cef18 | ||
|
|
1c11778693 | ||
|
|
3ddd4b6f16 | ||
|
|
d948ed11a1 | ||
|
|
257d8142b1 | ||
|
|
48c55b7d29 | ||
|
|
776bbbf7b1 | ||
|
|
f326bf371d | ||
|
|
4cf7ca4162 | ||
|
|
01f3b82ea5 | ||
|
|
c22e3aaa4b | ||
|
|
dbf15fb8dc | ||
|
|
a253129fd6 | ||
|
|
a8ba3ee9e1 | ||
|
|
9613f6437d | ||
|
|
9dc765142c | ||
|
|
7d70f1becb | ||
|
|
a476c5420a | ||
|
|
cdd8d10940 | ||
|
|
883deb1c5d | ||
|
|
e389fcaecb | ||
|
|
585d2b20bd | ||
|
|
9078d9cfab | ||
|
|
51b662fdfe | ||
|
|
b6d74ad753 | ||
|
|
5656323434 | ||
|
|
81baebf113 | ||
|
|
f7c884d4d1 | ||
|
|
d0e7f61db6 | ||
|
|
0f8790d993 | ||
|
|
86377aa37a | ||
|
|
3988f3ad77 | ||
|
|
7aa9af08c3 | ||
|
|
15803d1837 | ||
|
|
ab9d6285c6 | ||
|
|
c0c10fd5f1 | ||
|
|
e2d4a38639 | ||
|
|
f89676d4bb | ||
|
|
b9c167fc13 | ||
|
|
3bac06d6e5 | ||
|
|
504e11b5bb | ||
|
|
b80ba97154 | ||
|
|
e3e38f3eac | ||
|
|
6e445033c7 | ||
|
|
93c9f4316b | ||
|
|
47a7000121 | ||
|
|
6c9026e330 | ||
|
|
d59c609a73 | ||
|
|
6ee48c8f15 | ||
|
|
6af823b36a | ||
|
|
a642d99d4b | ||
|
|
8c7ea61623 | ||
|
|
067508c082 | ||
|
|
79065ba5c6 | ||
|
|
3fbd156c83 | ||
|
|
8fb191afcf | ||
|
|
ab37856a91 | ||
|
|
844e03d000 | ||
|
|
69e81e8f65 | ||
|
|
46e796303e | ||
|
|
1940c2f9bf | ||
|
|
83e94c3ec7 | ||
|
|
a7c0cfc8eb | ||
|
|
7ae8ba35de | ||
|
|
8eebc53728 | ||
|
|
ee366df58f | ||
|
|
482ee875a1 | ||
|
|
b10edfecfc | ||
|
|
3b96097cf6 | ||
|
|
298f1ab570 | ||
|
|
79dd8e9074 | ||
|
|
8d5afff0a4 | ||
|
|
4dc49ff3b0 | ||
|
|
4369853ddb | ||
|
|
d870729709 | ||
|
|
f40cceaf04 | ||
|
|
b357003a95 | ||
|
|
5cc3b526e8 | ||
|
|
1b2a8ba6b0 | ||
|
|
8a963a67f2 | ||
|
|
586fd346ea | ||
|
|
e5ed8fc90a | ||
|
|
75676f8830 | ||
|
|
530853c988 | ||
|
|
02283fc686 | ||
|
|
dcf0baa9de | ||
|
|
cd2057fc04 | ||
|
|
3e294d5339 | ||
|
|
bae00358b9 | ||
|
|
36573a5c6f | ||
|
|
9a835af7ce | ||
|
|
ca48ff793c | ||
|
|
58e8a25869 | ||
|
|
d517d92f6c | ||
|
|
71dcf7fc37 | ||
|
|
0a59faf03d | ||
|
|
7bd48b1327 | ||
|
|
8c652e061d | ||
|
|
a4816d6a8c | ||
|
|
1a503d54f6 | ||
|
|
263668b1cb | ||
|
|
3df65460f5 | ||
|
|
74672d493d | ||
|
|
f1b7d506ae | ||
|
|
fc8c88be41 | ||
|
|
4581d708ff | ||
|
|
e0a14cac5b | ||
|
|
ac844a2a45 | ||
|
|
7230fa6b4f | ||
|
|
e25af4f0dc | ||
|
|
287670c9d6 | ||
|
|
994f3bb644 | ||
|
|
e5c780ee19 | ||
|
|
1c3d5ab158 | ||
|
|
5d668eca40 | ||
|
|
7ab127ad53 | ||
|
|
dd91f4a86e | ||
|
|
3485109125 | ||
|
|
a1136e7695 | ||
|
|
32f38dc5f8 | ||
|
|
ceac18c554 | ||
|
|
99f32dcb99 | ||
|
|
79fe71db58 | ||
|
|
ac937030f0 | ||
|
|
ed5385faa3 | ||
|
|
fe234499dd | ||
|
|
67d77dd6ce | ||
|
|
755ef0119a | ||
|
|
1a1ab92ed9 | ||
|
|
b29e9b931d | ||
|
|
0479322c1d | ||
|
|
0be7b6fe1f | ||
|
|
ee98daf9ea | ||
|
|
f2beaba3e9 | ||
|
|
823c7469e1 | ||
|
|
10efe1faee | ||
|
|
e0954b0999 | ||
|
|
5ff3e448f5 | ||
|
|
58bcbba841 | ||
|
|
30e3932af8 | ||
|
|
e86937e2e2 | ||
|
|
6276d9290d | ||
|
|
cde6589af8 | ||
|
|
482d538559 | ||
|
|
6cc5ce7a66 | ||
|
|
7a80fe4939 | ||
|
|
b8444053b8 | ||
|
|
753d7addb4 | ||
|
|
c0ae96e7a8 | ||
|
|
e99d64011e | ||
|
|
72809ef5b1 | ||
|
|
7a790c88e8 | ||
|
|
01377f6ea9 | ||
|
|
8c94601ef2 | ||
|
|
f27ceb7fab | ||
|
|
60bde048c6 | ||
|
|
3b961204e1 | ||
|
|
e9907bc8ae | ||
|
|
6b9b5252de | ||
|
|
d949ec6877 | ||
|
|
96dede4e84 | ||
|
|
72783aa068 | ||
|
|
0abe7a77fb | ||
|
|
ad408c5717 | ||
|
|
658a8c0609 | ||
|
|
e7a91a1169 | ||
|
|
14a51458ab | ||
|
|
aafe7c4732 | ||
|
|
86c2e9e825 | ||
|
|
480932a58a | ||
|
|
529bcab009 | ||
|
|
9a4871abeb | ||
|
|
40665c05ac | ||
|
|
d832312acc | ||
|
|
63cf0e347b | ||
|
|
2192386d86 | ||
|
|
e694ffcd03 | ||
|
|
eff401d418 | ||
|
|
7049ccd7ab | ||
|
|
8fb2167fca | ||
|
|
d0b8528022 | ||
|
|
13d80beb83 | ||
|
|
06ce8dd8bd | ||
|
|
9a1ea67a35 | ||
|
|
e616f904b6 | ||
|
|
bff24ffd2f | ||
|
|
2cdc969cc5 | ||
|
|
b13fd786b6 | ||
|
|
89d55d0af8 | ||
|
|
d46335aba1 | ||
|
|
e417a4b159 | ||
|
|
b0f986c740 | ||
|
|
18091f99d4 | ||
|
|
3ae2071129 | ||
|
|
820ebf4b6e | ||
|
|
161f6baba6 | ||
|
|
89d7dbf2cf | ||
|
|
b1972e56fa | ||
|
|
7d10f9829e | ||
|
|
d2723bc0ac | ||
|
|
a0d43f8ba6 | ||
|
|
37c5612aee | ||
|
|
f2e73c0887 | ||
|
|
aca36cc1ac | ||
|
|
9af6e29f42 | ||
|
|
d6db77cce8 | ||
|
|
71d2e3de74 | ||
|
|
a7e07239e3 | ||
|
|
3608114ec1 | ||
|
|
c9d5a9cea2 | ||
|
|
354cdfdbc1 | ||
|
|
d903afc4bf | ||
|
|
4dbe9d4113 | ||
|
|
c743cc171a | ||
|
|
7963a8322d | ||
|
|
6ac44f05cd | ||
|
|
64a84fda38 | ||
|
|
8eec79680c | ||
|
|
0968d74dad | ||
|
|
876a1c5140 | ||
|
|
1455636169 | ||
|
|
7ea9a5ca4e | ||
|
|
05c1bfb6cf | ||
|
|
2d2ec2a576 | ||
|
|
17126de5c7 | ||
|
|
e4612ca5d4 | ||
|
|
15af5878b6 | ||
|
|
d9f6468310 | ||
|
|
10c6951438 | ||
|
|
56e38e6f80 | ||
|
|
c36043a175 | ||
|
|
ee63b36ed3 | ||
|
|
35d28294cd | ||
|
|
c6bd3ab31a | ||
|
|
9c7ee6ef85 | ||
|
|
e85a339d94 | ||
|
|
66f0ce6616 | ||
|
|
fb2d31c9ce | ||
|
|
8865405a32 | ||
|
|
f3ea375083 | ||
|
|
15b02547e8 | ||
|
|
13b1f8b33e | ||
|
|
ccd32c04a9 | ||
|
|
df19b20d07 | ||
|
|
f41c9fbb7f | ||
|
|
a0e50670de | ||
|
|
984631d807 | ||
|
|
a9761a8976 | ||
|
|
84d8624e03 | ||
|
|
9866010b4c | ||
|
|
a3c1052cae | ||
|
|
726cbc160c | ||
|
|
bf39343920 | ||
|
|
af24b4132d | ||
|
|
d339b68715 | ||
|
|
7f51803d04 | ||
|
|
eadc791795 | ||
|
|
408cf11b2b | ||
|
|
e3ba8d3209 | ||
|
|
17b1c83ae5 | ||
|
|
b2a8ffc577 | ||
|
|
e2711224ed | ||
|
|
2ac7e0200a | ||
|
|
e6b971b316 | ||
|
|
111bb485ec | ||
|
|
e10775d34f | ||
|
|
30957479a3 | ||
|
|
b4ab53dd32 | ||
|
|
a314eeb892 | ||
|
|
644ddf318c | ||
|
|
f598ac89ac | ||
|
|
3f7b3ca962 | ||
|
|
104c6edcde | ||
|
|
94b673dc8e | ||
|
|
096cd348f0 | ||
|
|
01c2ffe2ae | ||
|
|
0a4370236d | ||
|
|
fe8d2b397e | ||
|
|
92e90f9c55 | ||
|
|
3eb2642b11 | ||
|
|
99192a6dec | ||
|
|
cffc1fd1c4 | ||
|
|
b8f7c6daae | ||
|
|
cd07865da6 | ||
|
|
315e38e814 | ||
|
|
95b90271b6 | ||
|
|
90befac901 | ||
|
|
22f71ce17e | ||
|
|
0931f25747 | ||
|
|
971f2391cf | ||
|
|
43a26eb50a | ||
|
|
99d406072f | ||
|
|
3a1a56c7ad | ||
|
|
57cbba81e7 | ||
|
|
e48d55d126 | ||
|
|
1c03fa8642 | ||
|
|
670ff36024 | ||
|
|
6b3f6d9860 | ||
|
|
ac5876e94e | ||
|
|
b13f44023d | ||
|
|
2f15d8aef5 | ||
|
|
ecaa37efbe | ||
|
|
33e421473c | ||
|
|
eb1a96c164 | ||
|
|
2afcac763d | ||
|
|
28fe903aee | ||
|
|
253d197ccb | ||
|
|
0ceb806f1a | ||
|
|
800b9cf167 | ||
|
|
1da398e6c6 | ||
|
|
074cb132bb | ||
|
|
2df74fd9d7 | ||
|
|
d68b07dfc7 | ||
|
|
a52dff713b | ||
|
|
041c5e6d44 | ||
|
|
a2ce739192 | ||
|
|
ca4ad58a06 | ||
|
|
89df8fb692 | ||
|
|
9a021d2279 | ||
|
|
82e87805c3 | ||
|
|
844bfc5f25 | ||
|
|
706c68f69c | ||
|
|
13e0cc6b50 | ||
|
|
7af81f7665 | ||
|
|
278129b286 | ||
|
|
54c522c861 | ||
|
|
a034ee894c | ||
|
|
6f46764daa | ||
|
|
e1d482ea7c | ||
|
|
c34ec00d3a | ||
|
|
090abdee87 | ||
|
|
ce04a76b17 | ||
|
|
2953eed729 | ||
|
|
bf2b089c5c | ||
|
|
3107e63040 | ||
|
|
2ec8194d01 | ||
|
|
d113498c7b | ||
|
|
d8206ccbc7 | ||
|
|
fbd8de1c24 | ||
|
|
81d9f94a29 | ||
|
|
382cc444f0 | ||
|
|
0cec6f08ca | ||
|
|
2112e16cca | ||
|
|
35f80bd439 | ||
|
|
1dc44c0f62 | ||
|
|
eae3f7ce0a | ||
|
|
aa322d41aa | ||
|
|
95d23b1914 | ||
|
|
0464cdb43f | ||
|
|
35e4fe061d | ||
|
|
02924ad83e | ||
|
|
ff4213b59f | ||
|
|
c4e51247d8 | ||
|
|
1218a38f2c | ||
|
|
797f8087bc | ||
|
|
bf77ac6ba5 | ||
|
|
eafb006649 | ||
|
|
a9bf7a90ed | ||
|
|
ee7593bbe3 | ||
|
|
30843cd368 | ||
|
|
53195b064a | ||
|
|
dca2664707 | ||
|
|
e1dfc38a90 | ||
|
|
2e90e9c35b | ||
|
|
8f5110900c | ||
|
|
5e332983e2 | ||
|
|
6e240a3e9c | ||
|
|
a1f1775d15 | ||
|
|
5fbed0d1cd | ||
|
|
bd25225045 | ||
|
|
013eba0e79 | ||
|
|
78212e03d6 | ||
|
|
a8ea7b0858 | ||
|
|
0e97770c47 | ||
|
|
3d7bd7583b | ||
|
|
bfacac8683 | ||
|
|
d66c2b5fae | ||
|
|
72e44ce3d7 | ||
|
|
0806e0466c | ||
|
|
c05ca51238 | ||
|
|
1a4a5bfc57 | ||
|
|
be5d5aea6d | ||
|
|
8635b8ac84 | ||
|
|
d1b8370a4a | ||
|
|
1f57fd0407 | ||
|
|
671599c8b2 | ||
|
|
0b4fd52d63 | ||
|
|
e05f5fc50d | ||
|
|
da6250fc1f | ||
|
|
7d075cdcb7 | ||
|
|
3a55ff2119 | ||
|
|
b5b055e1ae | ||
|
|
0c99673581 | ||
|
|
709aa27031 | ||
|
|
5b01d63491 | ||
|
|
46b3d41b20 | ||
|
|
0b7ad2c804 | ||
|
|
8392d6c136 | ||
|
|
4ced7e9c80 | ||
|
|
3d120983da | ||
|
|
70aafd74a8 | ||
|
|
66415831ea | ||
|
|
2b7919fb3a | ||
|
|
09173fb727 | ||
|
|
de5de6284c | ||
|
|
de8ab35cb3 | ||
|
|
237b597e19 | ||
|
|
2d7a4bdb06 | ||
|
|
6f270a3648 | ||
|
|
8be2aaa751 | ||
|
|
5ede5ab4ce | ||
|
|
506f7c0764 | ||
|
|
4b686a4394 | ||
|
|
a18a601291 | ||
|
|
92fc50d4b0 | ||
|
|
57c812bc00 | ||
|
|
715b8c4683 | ||
|
|
b1bb7ec1a8 | ||
|
|
f6136dd036 | ||
|
|
cb49635231 | ||
|
|
e8f7adc7ca | ||
|
|
ab8061a57f | ||
|
|
f414355680 | ||
|
|
6dd043659c | ||
|
|
704ca366b3 | ||
|
|
cf15cbf0b3 | ||
|
|
de7c301654 | ||
|
|
48d2fc1599 | ||
|
|
839361594d | ||
|
|
40abe3f370 | ||
|
|
7a5a706397 | ||
|
|
59ea79d9e6 | ||
|
|
4e5898efd7 | ||
|
|
a512586140 | ||
|
|
28a0971cdf | ||
|
|
5c9827a33c | ||
|
|
f0362b2332 | ||
|
|
5bf48bc68f | ||
|
|
6e47d9a2e5 | ||
|
|
a480a318fd | ||
|
|
251f1d0047 | ||
|
|
1c3127e43b | ||
|
|
20a979173f | ||
|
|
4aad318446 | ||
|
|
13a5653c4e | ||
|
|
119ecb4259 | ||
|
|
8bd047174a | ||
|
|
416393a794 | ||
|
|
9e36cabcbf | ||
|
|
3731eba9b6 | ||
|
|
f707a43b3c | ||
|
|
7a96e8a292 | ||
|
|
90cce0ab56 | ||
|
|
41ed603abf | ||
|
|
cdce7f2044 | ||
|
|
6ae88514d8 | ||
|
|
c043840cb1 | ||
|
|
a831164d65 | ||
|
|
a41dc00160 | ||
|
|
5a1bf7d8fe | ||
|
|
075c423c62 | ||
|
|
d9813dbc90 | ||
|
|
50874eecfa | ||
|
|
3cea550d08 | ||
|
|
5e9d6f1cbd | ||
|
|
b1363d1a79 | ||
|
|
520923b5a7 | ||
|
|
2ba46e05ee | ||
|
|
90ed57f478 | ||
|
|
ab580103c7 | ||
|
|
1c6a83d0dd | ||
|
|
06f3a70f9a | ||
|
|
1fb68e8711 | ||
|
|
bd107e133f | ||
|
|
1c2d5f16c8 | ||
|
|
5738110cb6 | ||
|
|
6be122edc4 | ||
|
|
7979342edf | ||
|
|
2cdf5517cb | ||
|
|
7adcb76f68 | ||
|
|
acf65b4c23 | ||
|
|
d099c2a8db | ||
|
|
20f1257e88 | ||
|
|
fe0de111fd | ||
|
|
e7a0c1b6d0 | ||
|
|
da54b3d7e5 | ||
|
|
971abaea80 | ||
|
|
a76670f3b8 | ||
|
|
e13b618a65 | ||
|
|
cd1b89475c | ||
|
|
5d90b48790 | ||
|
|
c3cb186952 | ||
|
|
5ca743dd25 | ||
|
|
d34dbbdb0b | ||
|
|
1c9b51c330 | ||
|
|
122854af77 | ||
|
|
a5ace5e71d | ||
|
|
af4f1083b7 | ||
|
|
186f16e688 | ||
|
|
99b1f69271 | ||
|
|
e54be1c4ee | ||
|
|
411621bf03 | ||
|
|
ca2ffd4fb3 | ||
|
|
3b20684dc7 | ||
|
|
b6db9789ee | ||
|
|
7a4daf799a | ||
|
|
389499d639 | ||
|
|
7b58a82840 | ||
|
|
9d818066a7 | ||
|
|
0238a29c7c | ||
|
|
d01065b9a1 | ||
|
|
607287a9d6 | ||
|
|
ce8341ca1f | ||
|
|
9493e8f42e | ||
|
|
b1aaf055b1 | ||
|
|
34e75f80bc | ||
|
|
0db095e02a | ||
|
|
30095a0c3f | ||
|
|
946c6967e9 | ||
|
|
d1e00099dc | ||
|
|
d018d460e3 | ||
|
|
851a3128e4 | ||
|
|
bdb8a4a0cb | ||
|
|
0f70bd7913 | ||
|
|
59bbbd5e66 | ||
|
|
1e98ba27c6 | ||
|
|
2244b35a6d | ||
|
|
15ee7b39ac | ||
|
|
cb7d74a063 | ||
|
|
bfe095b065 | ||
|
|
30bcd45a14 | ||
|
|
f44d3914ef | ||
|
|
5d24a2dc0f | ||
|
|
8160963110 | ||
|
|
d50d8b86cf | ||
|
|
b28e06608c | ||
|
|
cd411e5fb1 | ||
|
|
9daef50ce6 | ||
|
|
fae178f70b | ||
|
|
744208f701 | ||
|
|
85d8ae6b93 | ||
|
|
5100a2daf1 | ||
|
|
6e57b0219e | ||
|
|
3a002a1ddf | ||
|
|
4b0d956b3d | ||
|
|
85408961ba | ||
|
|
04b6794318 | ||
|
|
3314a472c3 | ||
|
|
aeeb408c74 | ||
|
|
63c40b45e4 | ||
|
|
c17a678385 | ||
|
|
e2e56f45af | ||
|
|
05c1dcef9b | ||
|
|
cc5fe558ba | ||
|
|
3d93527a8e | ||
|
|
8a19f2ac65 | ||
|
|
b7fa50be4c | ||
|
|
42751f87d9 | ||
|
|
f88431adbf | ||
|
|
03aa7e3044 | ||
|
|
91f6cae168 | ||
|
|
ddd584077c | ||
|
|
8201f0b6ea | ||
|
|
f2b5fcd706 | ||
|
|
950439e5b8 | ||
|
|
f24cdf5a05 | ||
|
|
d3b00532b1 | ||
|
|
b7ed0fce2a | ||
|
|
57d965aeba | ||
|
|
5eaae83a01 | ||
|
|
c50136d675 | ||
|
|
494ea5c78c | ||
|
|
c8d0f788e0 | ||
|
|
ae263d60bd | ||
|
|
df3fe25702 | ||
|
|
566e6c813e | ||
|
|
ee4892e345 | ||
|
|
7fd2f292e7 | ||
|
|
b68d982619 | ||
|
|
cf058bc537 | ||
|
|
cc9680c1e8 | ||
|
|
b7553d5bdf | ||
|
|
4ad190a558 | ||
|
|
3a193655b3 | ||
|
|
e10a08f64d | ||
|
|
cc94c772cd | ||
|
|
4b6edaa01a | ||
|
|
8da7919a43 | ||
|
|
f52d66a954 | ||
|
|
4d3212b31f | ||
|
|
973dc9e1e2 | ||
|
|
881641f0b7 | ||
|
|
d1b1da3414 | ||
|
|
48a359b69e | ||
|
|
2a8f9a7c04 | ||
|
|
3da1e9a4b9 | ||
|
|
f1b42cedda | ||
|
|
2598579d84 | ||
|
|
c5b6ec209a | ||
|
|
13705999f7 | ||
|
|
fbe812b9bc | ||
|
|
4697f0274f | ||
|
|
aff8008baf | ||
|
|
c922015521 | ||
|
|
4ed9edb104 | ||
|
|
bb244d527c | ||
|
|
7f1d13dfbf | ||
|
|
3185b0940b | ||
|
|
d709a47b93 | ||
|
|
013a0e25d5 | ||
|
|
3db8d3dfb6 | ||
|
|
72a3e08907 | ||
|
|
4202387c52 | ||
|
|
cd4e647816 | ||
|
|
3a31694147 | ||
|
|
05236f0a7a | ||
|
|
a475526805 | ||
|
|
3c1a2cde33 | ||
|
|
a1f7168d2a | ||
|
|
1e1c2f8de2 | ||
|
|
76e67db04b | ||
|
|
70c3514996 | ||
|
|
9aeb587d6c | ||
|
|
51041d0f15 | ||
|
|
ada2be94f2 | ||
|
|
8cb3a77022 | ||
|
|
1ed4eb46f2 | ||
|
|
7c31da5a95 | ||
|
|
1f245b3791 | ||
|
|
554d1b88fc | ||
|
|
2841714817 | ||
|
|
35af03b2e5 | ||
|
|
ae018eab42 | ||
|
|
68f0f1b404 | ||
|
|
96f152d57c | ||
|
|
53c5f03c32 | ||
|
|
e86499d990 | ||
|
|
88e0f97798 | ||
|
|
e2cda2dc65 | ||
|
|
090d02a65f | ||
|
|
a0e88477c1 | ||
|
|
da45d99b8f | ||
|
|
f67989afea | ||
|
|
14fef4a0d3 | ||
|
|
d3439d5526 | ||
|
|
4597201560 | ||
|
|
574435687d | ||
|
|
fce194ce08 | ||
|
|
5204524691 | ||
|
|
9af7e8cff0 | ||
|
|
5e33898a08 | ||
|
|
1a98b49f1b | ||
|
|
0e8f0481d4 | ||
|
|
6580af65c1 | ||
|
|
cdf16dd905 | ||
|
|
d30ed7fb8a | ||
|
|
13df7fcee0 | ||
|
|
6e4ecd11a1 | ||
|
|
793a994ce6 | ||
|
|
19bf5e2ff1 | ||
|
|
16ad3d5c88 | ||
|
|
ff2d98596f | ||
|
|
072698d606 | ||
|
|
0b098045f1 | ||
|
|
ddb6b3b262 | ||
|
|
7f2470f1f6 | ||
|
|
488b964c52 | ||
|
|
b4d3f696bf | ||
|
|
9cc4d363b2 | ||
|
|
b646caffd0 | ||
|
|
b9bc3e36b8 | ||
|
|
24aaf7a034 | ||
|
|
80f2e40e67 | ||
|
|
e95b73dfac | ||
|
|
c00e3e8c0a | ||
|
|
2a12610a46 | ||
|
|
d466a05915 | ||
|
|
e05d6bfcdc | ||
|
|
b49dd02e3d |
63
.clang-format
Normal file
63
.clang-format
Normal file
@@ -0,0 +1,63 @@
|
||||
# Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
|
||||
#
|
||||
# You may use this file under the terms of the 3-clause BSD license.
|
||||
# See the file LICENSE from this package for details.
|
||||
|
||||
# This is the clang-format configuration style to be used by Qt,
|
||||
# based on the rules from https://wiki.qt.io/Qt_Coding_Style and
|
||||
# https://wiki.qt.io/Coding_Conventions
|
||||
|
||||
---
|
||||
# Webkit style was loosely based on the Qt style
|
||||
BasedOnStyle: WebKit
|
||||
|
||||
Standard: Cpp11
|
||||
ColumnLimit: 0
|
||||
|
||||
# Disable reflow of qdoc comments: indentation rules are different.
|
||||
# Translation comments are also excluded
|
||||
CommentPragmas: "^!|^:"
|
||||
|
||||
# We want a space between the type and the star for pointer types
|
||||
PointerBindsToType: false
|
||||
|
||||
# We want to break before the operators, but not before a '='
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
|
||||
# Braces are usually attached, but not after functions or classes declaration
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
|
||||
# The coding style does not specify the following, but this is what gives
|
||||
# results closest to the existing code.
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
|
||||
# Ideally we should also allow less short function in a single line, but
|
||||
# clang-format does not handle that
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
|
||||
# The coding style specifies some include order categories, but also tells to
|
||||
# separate categories with an empty line. It does not specify the order within
|
||||
# the categories. Since the SortInclude feature of clang-format does not
|
||||
# re-order includes separated by empty lines, the feature is not used.
|
||||
SortIncludes: false
|
||||
|
||||
# macros for which the opening brace stays attached
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]
|
||||
|
||||
# Allow two empty lines for structuring
|
||||
MaxEmptyLinesToKeep: 2
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
|
||||
92
.drone.yml
Normal file
92
.drone.yml
Normal file
@@ -0,0 +1,92 @@
|
||||
#
|
||||
# We are building GCC with make and Clang with ninja, the combinations are more
|
||||
# or less arbitrarily chosen. We just want to check that both compilers and both
|
||||
# CMake generators work. It's unlikely that a specific generator only breaks
|
||||
# with a specific compiler.
|
||||
#
|
||||
|
||||
workspace:
|
||||
base: /drone
|
||||
path: src/github.com/owncloud/client
|
||||
|
||||
branches:
|
||||
- master
|
||||
- 2.5
|
||||
- 2.4
|
||||
|
||||
clone:
|
||||
git:
|
||||
image: plugins/git
|
||||
pull: true
|
||||
tags: false
|
||||
|
||||
pipeline:
|
||||
prepare-clang:
|
||||
image: owncloudci/client:latest
|
||||
pull: true
|
||||
environment:
|
||||
- LC_ALL=C.UTF-8
|
||||
commands:
|
||||
- mkdir clang-build
|
||||
- cd clang-build
|
||||
- cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 ..
|
||||
|
||||
building-clang:
|
||||
image: owncloudci/client:latest
|
||||
pull: true
|
||||
environment:
|
||||
- LC_ALL=C.UTF-8
|
||||
commands:
|
||||
- cd clang-build
|
||||
- ninja -j4
|
||||
|
||||
testing-clang:
|
||||
image: owncloudci/client:latest
|
||||
pull: true
|
||||
environment:
|
||||
- LC_ALL=C.UTF-8
|
||||
commands:
|
||||
- cd clang-build
|
||||
- useradd -m -s /bin/bash tester
|
||||
- chown -R tester:tester .
|
||||
- su-exec tester ctest --output-on-failure
|
||||
|
||||
prepare-gcc:
|
||||
image: owncloudci/client:latest
|
||||
pull: true
|
||||
environment:
|
||||
- LC_ALL=C.UTF-8
|
||||
commands:
|
||||
- mkdir gcc-build
|
||||
- cd gcc-build
|
||||
- cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 ..
|
||||
|
||||
building-gcc:
|
||||
image: owncloudci/client:latest
|
||||
pull: true
|
||||
environment:
|
||||
- LC_ALL=C.UTF-8
|
||||
commands:
|
||||
- cd gcc-build
|
||||
- make -j4
|
||||
|
||||
testing-gcc:
|
||||
image: owncloudci/client:latest
|
||||
pull: true
|
||||
environment:
|
||||
- LC_ALL=C.UTF-8
|
||||
commands:
|
||||
- cd gcc-build
|
||||
- useradd -m -s /bin/bash tester
|
||||
- chown -R tester:tester .
|
||||
- su-exec tester ctest --output-on-failure
|
||||
|
||||
notify-slack:
|
||||
image: plugins/slack
|
||||
pull: true
|
||||
secrets: [ slack_webhook ]
|
||||
channel: desktop
|
||||
when:
|
||||
local: false
|
||||
status: [ changed, failure ]
|
||||
event: [ push ]
|
||||
1
.git-blame-ignore-revs
Normal file
1
.git-blame-ignore-revs
Normal file
@@ -0,0 +1 @@
|
||||
c8d0f788e00bdae125a26d9159ce9efdd6325cd2 # Initial application of clang-format
|
||||
119
.github/release_template.md
vendored
Normal file
119
.github/release_template.md
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<!--
|
||||
This is the template for new release issues.
|
||||
(originated from https://github.com/owncloud/client/wiki/Release%20Checklist%20Template)
|
||||
-->
|
||||
|
||||
Copy below text into a task and tick the items:
|
||||
|
||||
```
|
||||
Some weeks before the release:
|
||||
* [ ] Check if we should update the bundled sqlite3 (https://github.com/owncloud/client/tree/master/src/3rdparty/sqlite3)
|
||||
* [ ] Check if we should update Sparkle on build machine (https://github.com/sparkle-project/Sparkle/releases)
|
||||
* [ ] Ensure NSIS is up to date on the build machine
|
||||
* [ ] Ensure up-to-date dependencies (e.g. [latest Qt version](http://qt-project.org/downloads#qt-lib) is installed on the machine and picked up (cmake output)
|
||||
* [ ] Ensure the crash reporter server is up
|
||||
* [ ] Check crash reporter for bad crashes
|
||||
* [ ] Ensure Windows Overlay DLLs are rebuilt
|
||||
* [ ] Check nightly builds are up and running, that is Jenkins jobs ownCloud-client-linux, ownCloud-client-osx and ownCloud-client-win32 all green.
|
||||
* [ ] Ensure Linux nightlies are built too for all distros https://build.opensuse.org/package/show/isv:ownCloud:community:nightly/owncloud-client
|
||||
* Check if patches still apply in the linux packages
|
||||
* [ ] Build branded clients through the scripting machine and smoke test one or two branded clients (especially with predefined url)
|
||||
* [ ] Upload a nightly build of the windows version to virustotal.com
|
||||
* Contact AV vendors whom's engine reports a virus
|
||||
* [ ] Documentation should be online before the release http://doc.owncloud.org/desktop/1.X/
|
||||
* [ ] QA goes over https://github.com/owncloud/mirall/wiki/Testing-Scenarios
|
||||
* [ ] Make sure to have `client/ChangeLog` updated
|
||||
* use `git log --format=oneline v<lastrelease>...master` if your memory fails you
|
||||
* [ ] check if enterprise issues are fixed
|
||||
|
||||
For first Alpha/Beta of a Major or Minor release:
|
||||
* [ ] branch off master to new version branch (e.g. master -> 2.1, when releasing 2.1)
|
||||
* [ ] Adjust `VERSION.cmake` in master and count up (e.g. 2.2)
|
||||
* [ ] Adjust translation jobs for [client](https://ci.owncloud.org/view/translation-sync/job/translation-sync-client/) and [NSIS](https://ci.owncloud.org/view/translation-sync/job/translation-sync-client-nsis/) to point to the release branch (e.g. 2.1).
|
||||
* [ ] Make sure there is a job for the docs of the new master branch and the current release branch on rotor e.g. http://doc.owncloud.org/desktop/1.X/ exists
|
||||
|
||||
For all alphas, betas and RCs (Copy this section for each alpha/beta/rc):
|
||||
* [ ] Add last updates to Changelog in the client source repository.
|
||||
* [ ] Branch off a release branch called VERSION-rcX or VERSION-betaX (without v, v is for tags)
|
||||
* [ ] Edit ```VERSION.cmake``` to set the suffix to beta1, beta2 etc. Commit the result to the release branch only
|
||||
* [ ] Make sure to increase the version number of the branched of release, e.g. if you release 2.3.2 then you should change VERSION.cmake in 2.3 to 2.3.3 since that branch now will be 2.3.3
|
||||
* [ ] Create build for using owncloud-client-trigger (uncheck the "nightly build" checkbox, use the proper dropdown for version suffix) for theme 'ownCloud'
|
||||
* [ ] Create build for using owncloud-client-trigger (uncheck the "nightly build" checkbox, use the proper dropdown for version suffix) for theme 'testpilotcloud'
|
||||
* [ ] Only now download the last created source .tar.xz and sign it with gpg. Copy the signature into a new .asc file. (timing issue because currently 'testpilotcloud' re-creates the source .tar.xz)
|
||||
* (no need to copy builds as they are already in testing directory or repository) (https://github.com/owncloud/enterprise/wiki/Desktop-Signing-Knowledge)
|
||||
* [ ] Mac: Perform smoke test (Install, make sure it does not explode, and check if all version indicators are correct)
|
||||
* [ ] Win: Perform smoke test (Install, make sure it does not explode, and check if all version indicators are correct)
|
||||
* [ ] Linux: Smoke test of one distro package (Install, make sure it does not explode, and check if all version indicators are correct)
|
||||
* [ ] Linux: Run @SamuAlfageme 's magic Linux-test-all-packages-script
|
||||
* [ ] Create a signed tag using ```git tag -u E94E7B37 tagname``` (https://github.com/owncloud/enterprise/wiki/Desktop-Signing-Knowledge)
|
||||
* [ ] Create a pull request to the owncloud.org repository to update the install page (strings.php, page-desktop.php) and the changelog on owncloud.org. From now on download packages from the staging webserver.
|
||||
* [ ] Inform packagers @dragotin (openSUSE), @hefee (Debian), ??? (Fedora)
|
||||
* [ ] Announce on https://central.owncloud.org
|
||||
* [ ] Inform community mailinglists devel@owncloud.org and testpilots@owncloud.org (make sure to mention it is an rc). Link to the central post so discussion happens there.
|
||||
* [ ] Check crash reporter
|
||||
|
||||
One week before the final release:
|
||||
* [ ] Communicate the release schedule on mailinglist release-coordination@owncloud.com. Give a high level overview of the upcoming new features, changes etc.
|
||||
* [ ] Ensure marketing is aware (marketing@owncloud.com) and prepared for the release (social, .com website, cust. communications)
|
||||
* [ ] Inform GCX knows the next version is about 1 week out (gcx@owncloud.com)
|
||||
|
||||
Day before final Release:
|
||||
* [ ] Check the translations coming from transifex: All synchronized?
|
||||
* [ ] Run the tx.pl scripts on the final code tag
|
||||
* [ ] Run ```make test```
|
||||
* [ ] Run smashbox
|
||||
* [ ] Inform product management and marketing that we are 1 day out
|
||||
|
||||
On Release Day (for final release):
|
||||
* [ ] Add last updates to Changelog in the client source repository.
|
||||
* [ ] Branch off a release branch called VERSION (without v, v is for tags)
|
||||
* [ ] Edit ```VERSION.cmake``` to set the suffix to "" etc. Commit the result to the release branch only
|
||||
* [ ] Create build for using owncloud-client-trigger (uncheck the "nightly build" checkbox, use the proper dropdown for version suffix) for theme 'ownCloud'
|
||||
* [ ] Create build for using owncloud-client-trigger (uncheck the "nightly build" checkbox, use the proper dropdown for version suffix) for theme 'testpilotcloud'
|
||||
* [ ] Only now download the last created source .tar.xz and sign it with gpg. Copy the signature into a new .asc file. (timing issue because currently 'testpilotcloud' re-creates the source .tar.xz) (https://github.com/owncloud/enterprise/wiki/Desktop-Signing-Knowledge)
|
||||
* [ ] Branch isv:ownCloud:desktop to isv:ownCloud:desktop:client-X.Y.Z before overwriting https://github.com/owncloud/administration/blob/master/jenkins/obs_integration/obs-backup-prj.sh (the linux packages will land in the :testing repository still)
|
||||
```obs-backup-prj.sh isv:ownCloud:desktop isv:ownCloud:desktop:client-2.4.1 owncloud-client 2.4.1 # (if not already done)```
|
||||
|
||||
* [ ] Re-download Mac builds and check signature. Interactive in installer window
|
||||
* [ ] Re-download Win build check signature. From Mac or Linux: ```osslsigncode verify ownCloud-version-setup.exe```
|
||||
* [ ] Mac: Perform smoke test (Install, make sure it does not explode, and check if all version indicators are correct)
|
||||
* [ ] Win: Perform smoke test (Install, make sure it does not explode, and check if all version indicators are correct)
|
||||
* [ ] Linux: Smoke test of one distro package (Install, make sure it does not explode, and check if all version indicators are correct)
|
||||
* [ ] Linux: Run @SamuAlfageme 's client-linux-tests Jenkins job (this tests only package installations!) Adjust REPO_URL in https://jenkins.int.owncloud.com/job/client-linux-tests/build (Better: gitlab?)
|
||||
* [ ] Win/Mac Copy builds from ```testing``` to ```stable``` on download.owncloud.com, double check the download links. (make sure the .asc is there too)
|
||||
* [ ] Linux: disable publishing on project isv:ownCloud:desktop
|
||||
* [ ] Linux: Use https://github.com/owncloud/administration/blob/master/jenkins/obs_integration/obs-deepcopy-prj.sh to copy from isv:ownCloud:community:testing to isv:ownCloud:desktop
|
||||
```obs-deepcopy-prj.sh isv:ownCloud:desktop:testing isv:ownCloud:desktop```
|
||||
```obs-deepcopy-prj.sh isv:ownCloud:testpilot:testing isv:ownCloud:testpilot```
|
||||
* [ ] Linux: Re-enable OBS publishing on the project after official release date and if all distros build (check for accidentially disabled packages too)
|
||||
* [ ] Linux: Wait until everything is built and published, then disable publishing on project isv:ownCloud:desktop
|
||||
* [ ] Create git signed tag in client repository using ```git tag -u E94E7B37 tagname``` (https://github.com/owncloud/enterprise/wiki/Desktop-Signing-Knowledge)
|
||||
* [ ] Create a (draft) release on https://github.com/owncloud/client/releases
|
||||
* [ ] Update https://owncloud.org/changelog/desktop-client/
|
||||
* [ ] Update https://owncloud.org/download/#owncloud-desktop-client -> Download ownCloud -> click open 'Desktop Client', edit win/mac/lin, each all three tabs "Production", "Technical Preview" [disabled], "Test pilot"
|
||||
* [ ] Announce on https://central.owncloud.org
|
||||
* [ ] Announce on announcements@owncloud.org Link to the central post so discussion happens there.
|
||||
* [ ] Inform packagers @dragotin (openSUSE) @hefee (Debian) @Germano0 (Fedora)
|
||||
* [ ] Send out Social (tweet, blog, other)
|
||||
* [ ] Send out customer communication (if any)
|
||||
* [ ] Inform GCX that the new version is released (gcx@owncloud.com)
|
||||
* [ ] Inform release-coordination@owncloud.com
|
||||
* [ ] Ensure marketing is aware (marketing@owncloud.com)
|
||||
* [ ] Take pride and celebrate!
|
||||
* [ ] Tell GCX to increment the minimum supported version for enterprise customers
|
||||
* [ ] Check if minimum.supported.desktop.version (https://github.com/owncloud/core/blob/master/config/config.sample.php#L1152) needs to be updated in server
|
||||
|
||||
15 minutes after after release:
|
||||
* [ ] Test all advertised download links to have the expected version
|
||||
* [ ] Check for build errors in OBS, do
|
||||
```obs-deepcopy-prj.sh isv:ownCloud:desktop isv:ownCloud:desktop:client-2.X.X```
|
||||
* [ ] disable publishing in OBS to prevent that accidential rebuilds hit the end users.
|
||||
|
||||
A few days after the release (for final release)
|
||||
* [ ] Review changes in the release branch, merge back into master
|
||||
* [ ] check the crash reporter if auto update is a good idea or we need a new release
|
||||
* [ ] Update the updater script ```clientupdater.php``` https://github.com/owncloud/enterprise/wiki/How-to-use-the-Client-Updater#updating-the-owncloud-hosted-updater
|
||||
* [ ] Execute announced deprecations. Disable builds for deprecated platforms. Update accordingly: https://doc.owncloud.org/server/latest/admin_manual/installation/system_requirements.html#desktop
|
||||
* [ ] Increment version number in nightly builds. Special case: after the last release in a branch, jump forward to the 'next release branch'... That may mean, this is nightly is the same as edge then.
|
||||
|
||||
```
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "doc/ocdoc"]
|
||||
path = doc/ocdoc
|
||||
url = https://github.com/owncloud/documentation
|
||||
[submodule "src/3rdparty/qtmacgoodies"]
|
||||
path = src/3rdparty/qtmacgoodies
|
||||
url = https://github.com/guruz/qtmacgoodies.git
|
||||
@@ -10,6 +7,6 @@
|
||||
[submodule "src/3rdparty/libcrashreporter-qt"]
|
||||
path = src/3rdparty/libcrashreporter-qt
|
||||
url = git://github.com/dschmidt/libcrashreporter-qt.git
|
||||
[submodule "src/3rdparty/qtkeychain"]
|
||||
path = src/3rdparty/qtkeychain
|
||||
url = https://github.com/frankosterfeld/qtkeychain.git
|
||||
[submodule "doc/docs-themes"]
|
||||
path = doc/docs-themes
|
||||
url = https://github.com/owncloud/docs-themes.git
|
||||
|
||||
37
.travis.yml
37
.travis.yml
@@ -1,37 +0,0 @@
|
||||
sudo: required
|
||||
|
||||
language: cpp
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
branches:
|
||||
only:
|
||||
- coverity_scan
|
||||
|
||||
before_install:
|
||||
- sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
|
||||
- sudo sh -c "echo 'deb-src http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
|
||||
- wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/Ubuntu_14.04/Release.key
|
||||
- sudo apt-key add - < Release.key
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y build-dep owncloud-client
|
||||
- checkout=$(git show-ref --head --hash head)
|
||||
- cd ../
|
||||
- wget https://scan.coverity.com/download/linux-64 --post-data "token=$token&project=owncloud%2Fmirall" -O coverity_tool.tgz
|
||||
- mkdir coverity
|
||||
- tar -xvf coverity_tool.tgz -C coverity --strip-components=1
|
||||
- export PATH=$PATH:$PWD/coverity/bin/
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
install:
|
||||
- cd ../
|
||||
- mkdir client-build
|
||||
- cd client-build
|
||||
- cmake -DCMAKE_BUILD_TYPE="Debug" $TRAVIS_BUILD_DIR
|
||||
- cov-build --dir cov-int make
|
||||
- tar czvf client.tgz cov-int
|
||||
- curl --form token=$token --form email=lukas@statuscode.ch --form file=@$PWD/client.tgz --form version="$checkout" --form description="$checkout" https://scan.coverity.com/builds?project=owncloud%2Fmirall
|
||||
|
||||
# Hack to stop processing
|
||||
script: true
|
||||
139
CMakeLists.txt
139
CMakeLists.txt
@@ -1,20 +1,23 @@
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(VERSION 2.8.0)
|
||||
if(POLICY CMP0020)
|
||||
cmake_policy(SET CMP0020 NEW)
|
||||
endif()
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
project(client)
|
||||
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
|
||||
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
|
||||
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
|
||||
include ( ${OEM_THEME_DIR}/OEM.cmake )
|
||||
else ()
|
||||
include ( ${CMAKE_SOURCE_DIR}/OWNCLOUD.cmake )
|
||||
endif()
|
||||
|
||||
# Default suffix if the theme doesn't define one
|
||||
if(NOT DEFINED APPLICATION_VIRTUALFILE_SUFFIX)
|
||||
set(APPLICATION_VIRTUALFILE_SUFFIX "${APPLICATION_SHORTNAME}_virtual" CACHE STRING "Virtual file suffix (not including the .)")
|
||||
endif()
|
||||
|
||||
# need this logic to not mess with re/uninstallations via macosx.pkgproj
|
||||
if(${APPLICATION_REV_DOMAIN} STREQUAL "com.owncloud.desktopclient")
|
||||
set(APPLICATION_REV_DOMAIN_INSTALLER "com.ownCloud.client")
|
||||
@@ -22,16 +25,19 @@ else()
|
||||
set(APPLICATION_REV_DOMAIN_INSTALLER ${APPLICATION_REV_DOMAIN})
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED APPLICATION_SHORTNAME)
|
||||
set ( APPLICATION_SHORTNAME ${APPLICATION_NAME} )
|
||||
endif()
|
||||
|
||||
# For usage in XML files we preprocess
|
||||
string(REPLACE "&" "&" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME}")
|
||||
string(REPLACE "<" "<" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME_XML_ESCAPED}")
|
||||
string(REPLACE ">" ">" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME_XML_ESCAPED}")
|
||||
|
||||
set(PACKAGE "${APPLICATION_SHORTNAME}-client")
|
||||
if (NOT DEFINED LINUX_PACKAGE_SHORTNAME)
|
||||
set(LINUX_PACKAGE_SHORTNAME "${APPLICATION_SHORTNAME}")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED PACKAGE)
|
||||
set(PACKAGE "${LINUX_PACKAGE_SHORTNAME}-client")
|
||||
endif()
|
||||
|
||||
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
||||
|
||||
if(NOT CRASHREPORTER_EXECUTABLE)
|
||||
@@ -41,7 +47,13 @@ endif()
|
||||
include(Warnings)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/VERSION.cmake)
|
||||
# For config.h
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
# Allows includes based on src/ like #include "common/utility.h" or #include "csync/csync.h"
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/src
|
||||
)
|
||||
|
||||
# disable the crashreporter if libcrashreporter-qt is not available or we're building for ARM
|
||||
if( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" OR NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/libcrashreporter-qt/CMakeLists.txt")
|
||||
@@ -52,14 +64,6 @@ if(NOT WITH_CRASHREPORTER)
|
||||
message(STATUS "Build of crashreporter disabled.")
|
||||
endif()
|
||||
|
||||
#####
|
||||
## handle DBUS for Fdo notifications
|
||||
if( UNIX AND NOT APPLE )
|
||||
add_definitions( -DUSE_FDO_NOTIFICATIONS)
|
||||
set(WITH_DBUS ON)
|
||||
endif()
|
||||
####
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
include(GenerateExportHeader)
|
||||
@@ -68,6 +72,12 @@ include(GetGitRevisionDescription)
|
||||
|
||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
|
||||
add_definitions(
|
||||
-DQT_USE_QSTRINGBUILDER
|
||||
-DQT_MESSAGELOGCONTEXT #enable function name and line number in debug output
|
||||
-DQT_DEPRECATED_WARNINGS
|
||||
)
|
||||
|
||||
# if we cannot get it from git, directly try .tag (packages)
|
||||
# this will work if the tar balls have been properly created
|
||||
# via git-archive.
|
||||
@@ -120,7 +130,22 @@ if(NO_MSG_HANDLER)
|
||||
add_definitions(-DNO_MSG_HANDLER=1)
|
||||
endif()
|
||||
|
||||
# this option creates only libocsync and libowncloudsync
|
||||
# this option builds the shell integration
|
||||
option(BUILD_SHELL_INTEGRATION "BUILD_SHELL_INTEGRATION" ON)
|
||||
|
||||
# this option builds/installs the generic shell integration icons
|
||||
option(BUILD_SHELL_INTEGRATION_ICONS "BUILD_SHELL_INTEGRATION_ICONS" ON)
|
||||
|
||||
# this options builds the dolphin integration plugin
|
||||
option(BUILD_SHELL_INTEGRATION_DOLPHIN "BUILD_SHELL_INTEGRATION_DOLPHIN" ON)
|
||||
|
||||
# this options builds the nautilus (like) integration plugins
|
||||
option(BUILD_SHELL_INTEGRATION_NAUTILUS "BUILD_SHELL_INTEGRATION_NAUTILUS" ON)
|
||||
|
||||
# this option builds the client
|
||||
option(BUILD_CLIENT "BUILD_CLIENT" ON)
|
||||
|
||||
# this option creates only libocsync and libowncloudsync (NOTE: BUILD_CLIENT needs to be on)
|
||||
option(BUILD_LIBRARIES_ONLY "BUILD_LIBRARIES_ONLY" OFF)
|
||||
|
||||
# When this option is enabled, 5xx errors are not added to the blacklist
|
||||
@@ -153,34 +178,25 @@ if(APPLE)
|
||||
set( SOCKETAPI_TEAM_IDENTIFIER_PREFIX "" CACHE STRING "SocketApi prefix (including a following dot) that must match the codesign key's TeamIdentifier/Organizational Unit" )
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL 1.0.0 REQUIRED)
|
||||
if(BUILD_CLIENT)
|
||||
if(APPLE)
|
||||
find_package(Sparkle)
|
||||
endif(APPLE)
|
||||
|
||||
if(APPLE)
|
||||
find_package(Sparkle)
|
||||
endif(APPLE)
|
||||
|
||||
if(UNIX)
|
||||
find_package(INotify REQUIRED)
|
||||
else()
|
||||
find_package(INotify)
|
||||
endif()
|
||||
find_package(Sphinx)
|
||||
find_package(PdfLatex)
|
||||
|
||||
find_package(SQLite3 3.8.0 REQUIRED)
|
||||
# On some OS, we want to use our own, not the system sqlite
|
||||
if (USE_OUR_OWN_SQLITE3)
|
||||
include_directories(BEFORE ${SQLITE3_INCLUDE_DIR})
|
||||
if (WIN32)
|
||||
add_definitions(-DSQLITE_API=__declspec\(dllimport\))
|
||||
if(UNIX)
|
||||
find_package(INotify REQUIRED)
|
||||
else()
|
||||
find_package(INotify)
|
||||
endif()
|
||||
find_package(Sphinx)
|
||||
find_package(PdfLatex)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(ZLIB)
|
||||
|
||||
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
configure_file(test/test_journal.db "${CMAKE_BINARY_DIR}/test/test_journal.db" COPYONLY)
|
||||
if (NOT DEFINED APPLICATION_ICON_NAME)
|
||||
set(APPLICATION_ICON_NAME "${APPLICATION_SHORTNAME}")
|
||||
endif()
|
||||
|
||||
include(OwnCloudCPack.cmake)
|
||||
|
||||
@@ -189,20 +205,34 @@ add_definitions(-D_UNICODE)
|
||||
if( WIN32 )
|
||||
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
||||
add_definitions( -DNOMINMAX )
|
||||
# Get APIs from from Vista onwards.
|
||||
add_definitions( -D_WIN32_WINNT=0x0600)
|
||||
add_definitions( -DWINVER=0x0600)
|
||||
endif( WIN32 )
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
# Handle Translations, pick all client_* files from trans directory.
|
||||
file( GLOB TRANS_FILES ${CMAKE_SOURCE_DIR}/translations/client_*.ts)
|
||||
set(TRANSLATIONS ${TRANS_FILES})
|
||||
|
||||
add_subdirectory(csync)
|
||||
add_subdirectory(src)
|
||||
if(NOT BUILD_LIBRARIES_ONLY)
|
||||
add_subdirectory(shell_integration)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(doc/dev)
|
||||
add_subdirectory(admin)
|
||||
endif(NOT BUILD_LIBRARIES_ONLY)
|
||||
if(BUILD_CLIENT)
|
||||
add_subdirectory(src)
|
||||
if(NOT BUILD_LIBRARIES_ONLY)
|
||||
add_subdirectory(man)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(doc/dev)
|
||||
if(IS_DIRECTORY ${CMAKE_SOURCE_DIR}/admin)
|
||||
add_subdirectory(admin)
|
||||
endif(IS_DIRECTORY ${CMAKE_SOURCE_DIR}/admin)
|
||||
endif(NOT BUILD_LIBRARIES_ONLY)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHELL_INTEGRATION)
|
||||
add_subdirectory(shell_integration)
|
||||
endif()
|
||||
|
||||
if(UNIT_TESTING)
|
||||
include(CTest)
|
||||
@@ -210,10 +240,13 @@ if(UNIT_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif(UNIT_TESTING)
|
||||
|
||||
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
configure_file(version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
|
||||
|
||||
if(BUILD_OWNCLOUD_OSX_BUNDLE)
|
||||
install(FILES sync-exclude.lst DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/)
|
||||
configure_file(sync-exclude.lst bin/${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/sync-exclude.lst COPYONLY)
|
||||
else()
|
||||
elseif(BUILD_CLIENT)
|
||||
install( FILES sync-exclude.lst DESTINATION ${SYSCONFDIR}/${APPLICATION_SHORTNAME} )
|
||||
configure_file(sync-exclude.lst bin/sync-exclude.lst COPYONLY)
|
||||
endif()
|
||||
|
||||
@@ -23,7 +23,7 @@ If your issue appears to be a bug, and hasn't been reported, open a new issue.
|
||||
Help us to maximize the effort we can spend fixing issues and adding new
|
||||
features, by not reporting duplicate issues.
|
||||
|
||||
[template]: https://raw.github.com/owncloud/client/master/issue_template.md
|
||||
[template]: https://raw.github.com/owncloud/client/master/.github/issue_template.md
|
||||
[mailinglist]: https://mail.kde.org/mailman/listinfo/owncloud
|
||||
[forum]: http://forum.owncloud.org/
|
||||
[irc]: http://webchat.freenode.net/?channels=owncloud&uio=d4
|
||||
|
||||
211
ChangeLog
211
ChangeLog
@@ -1,7 +1,213 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.3.3 (2017-07-XX)
|
||||
version 2.5.0 (2018-06-xx)
|
||||
* Local discovery: Speed up by skipping directories without changes reported by the file system watcher.
|
||||
* Windows: Add sync folders to Explorer's navigation pane (#5295)
|
||||
* Conflicts: Change conflict file naming scheme
|
||||
* Conflicts: Add user name to conflict file name (#6325)
|
||||
* ConnectionValidator: change the minimum server version to 7.0
|
||||
* ConnectionValidator: Warn when the server version is less than 9.1
|
||||
* Experimental option to create virtual files and download contents on demand ("placeholders")
|
||||
* Experimental option to upload conflict files (#4557)
|
||||
* Wizard: Remove the "Skip folder config" button and instead add a radio button (#3664)
|
||||
* Sharing: Add "copy public link" to menu (#6356)
|
||||
* Protocol: Introduce context menu with "open in browser" (#6121)
|
||||
* Shell integration: Add "Open in browser" entry in the explorer menu (#5903)
|
||||
* Sync journal: Fix crash when unmounting a drive while a sync is running (#6049)
|
||||
* Client certs: Improve error message (#6128)
|
||||
* User shares: Show avatars
|
||||
* Settings: Hide selective sync buttons while disconnected (#5809)
|
||||
* Excludes: Optimize further the matching of exclude files using regular expression
|
||||
* Don't use Qt deprecated API now that we required Qt 5.6
|
||||
* Windows: Update Overlay Icon naming
|
||||
* SyncEngine: Recover when the PUT reply (or chunkin's MOVE) is lost (#5106)
|
||||
* Config: Look for exclude file in a relative path.
|
||||
* Config: Versionize settings
|
||||
* Credentials: Re-try on Linux if daemon not running (#4274, #6522)
|
||||
* Windows: Fixed MSVC build and compiler bugs
|
||||
* Proxy: Hostname validation and reconnection on setting change (#6140)
|
||||
* owncloudcmd: Set proxy earlier (#6281)
|
||||
* Exclude regex: Restore old matching on Windows (#6245)
|
||||
* Build system: Modernize the CMakeLists.txt files
|
||||
* Use standard png2ico
|
||||
* Sync: Deal with file/folder conflicts (#6312)
|
||||
* Protocol: Correct sorting by size (#6326)
|
||||
* SocketAPI: dynamic action menu
|
||||
* Hidden option to move remote-deleted files to trash (#6265)
|
||||
* Tray: Change icon for unresolved conflicts (#6277)
|
||||
* FolderStatusModel: Refresh folders on Problem sync (#6337)
|
||||
* SyncJournal: Clear etag filter before sync
|
||||
* SyncEngine: Use separate state for two unicode conversions
|
||||
* Conflicts: Add documentation link to conflicts listing (#6396)
|
||||
* owncloudcmd: Do not read the proxy settings from the gui's config file
|
||||
* Discovery: Error if properties are missing (#6317)
|
||||
* ProgressInfo: Add information for local vs remote discovery
|
||||
* Issues tab: Invalidate issues selectively (#6226)
|
||||
* SyncResult: Make sure the number of conflicts is correct (#6226)
|
||||
* IssuesWidget: Don't allow two issues for the same file/folder
|
||||
* IssuesWidget: addItem performance improvement
|
||||
* Remove the "CSync" wording from the error messages
|
||||
* Apply branding to crashreporter resources file
|
||||
* Dolphin plugin: fall back if $XDG_RUNTIME_DIR is empty
|
||||
* SslButton: Add HTTP/2 info (#3146)
|
||||
* propagateuploadv1: Fixed an assert with ownCloud 5
|
||||
* Folder: normalize the local path. (#4424)
|
||||
* SslButton: Improve speed (especially on macOS) (#6031)
|
||||
* Blacklisting must prevent parent etag updates (#6411)
|
||||
* FolderStatusModel: fix potential assert
|
||||
* Nautilus integration: Not a ColumnProvider
|
||||
* Nautilus integration: Fix python3 compatibility (#6406)
|
||||
* Conflicts: Change tags to be more user friendly (#6365)
|
||||
* Notify if an explicitly excluded folder is created (#6222)
|
||||
* Theme: unify ownCloudTheme and Theme classes
|
||||
* Share link: Update permission wording (#6192)
|
||||
* SyncJournalDb::setSelectiveSyncList: Always use a transaction (#6431)
|
||||
* Folders: Use "Problem" icon for unresolved conflicts (#6277)
|
||||
* macOS: Unload the Finder extension on exit (#5382, #3819)
|
||||
* LogDir: Go to new file on Problem/Abort too (#6442)
|
||||
* LogDir: Compress log when switching files (#6442)
|
||||
* Logging: Add persistent auto-logdir option (#6442)
|
||||
* .owncloudsynclog: Allow 10 MB of size (#6420)
|
||||
* .owncloudsynclog: Persist X-Request-ID for correlation with server (#6420)
|
||||
* Notifications: Lower hiding timeout
|
||||
* Download: Use the <s:message> from the reply in the error message (#6459)
|
||||
* Notifications: Also have clickable link (#6236)
|
||||
* UI: High-DPI layout fixes
|
||||
* Network settings: Better warnings about bad configuration (#5885)
|
||||
* Share dialog: Allow opening it if the file's contents are still syncing (#4608)
|
||||
* Share dialog: Don't hide account settings when opening it (#6185)
|
||||
* Share dialog: Remove odd grey square on OSX (#5774)
|
||||
* Share dialog: Preserve the entered password when unrelated changes are done (#6512)
|
||||
* Folder watcher: Show a notification if it becomes unreliable (#6119)
|
||||
* Ignore editor: Preserve comments in the exclude list file
|
||||
* Propagation: Do not abort a sync if the server closes the connection (#6516)
|
||||
* Propagation: Increase the timeout for the last MOVE/PUT for huge files (#6527)
|
||||
* Update bundled sqlite version to 3.23.1
|
||||
* Auto Updater: Drop down menu to switch update channels
|
||||
|
||||
version 2.4.1 (2018-03-05)
|
||||
* Ignore files with file names that can't be encoded for the filesystem (#6287, #5676, #5719)
|
||||
* Issues: Speed up insertion and add hard upper limit (#6272)
|
||||
* Notifications: Fix "Dismiss" action
|
||||
* Notifications: Fix timer invocation on macOS
|
||||
* Notifications: Immediately poll when account online
|
||||
* Protocol: Remove entries for auto resolved conflicts (#6316)
|
||||
* owncloudcmd: Set proxy before capabilities call (#6281)
|
||||
* owncloudcmd: Do not do the capability call when --nonshib is passed
|
||||
* Avatars: Use old location for servers <10 (#6279)
|
||||
* Link shares: Change default share name (#6298)
|
||||
* Sharing: Use maximum allowed permissions for new share (#6346)
|
||||
* Nautilus integration: Work with python2 and python3
|
||||
* Windows: Don't delete contents behind directory junctions (#6322)
|
||||
* SyncJournal: Don't use LIKE with paths (#6322)
|
||||
* Fix setting launch-on-startup when the first account is set up (#6347)
|
||||
* HTTP2: Only allow with Qt 5.9.4 (#6285)
|
||||
* Crash fixes
|
||||
|
||||
version 2.4.0 (2017-12-21)
|
||||
* If you're using 2.4.0 alpha1, please upgrade as previous alphas/rcs had an issue with hidden files and renames!
|
||||
* OAuth2 authentication support by opening external browser (#5668)
|
||||
* Shibboleth: Change to use OAuth2 if supported (#6198)
|
||||
* Sharing: Add support for multiple public link shares (#5655)
|
||||
* Sharing: Add option to copy/email private links (#5023, #5627)
|
||||
* Sharing: Add option "show file listing" (#5837)
|
||||
* Sharing: Show warning that links are public (#5747)
|
||||
* Sharing: Sharing dialog redesign: multiple share links support (#5695)
|
||||
* Sharing: Make "can edit" partially checked sometimes (#5642)
|
||||
* Sharing: Trigger a sync for folder affected by a change of sharing (#6098)
|
||||
* Wizard: Never propose an existing folder for syncing (#5597)
|
||||
* Wizard: Don't show last page anymore, go to settings directly (#5726)
|
||||
* Wizard: Handle url-shortener redirects (#5954)
|
||||
* Wizard: Resolve url/ redirects only if url/status.php not found (#5954)
|
||||
* Wizard: Add explanation text when server error is shown (#6157)
|
||||
* Wizard: Update the window size on high dpi screen (#6156)
|
||||
* Wizard: Don't report confusing error message (#6116)
|
||||
* Gui: Display the user server avatar (#5482)
|
||||
* Gui: Use display name of user, not internal name
|
||||
* Server URL: Update configuration in case of permanent redirection (#5972)
|
||||
* Gui: Allow to add multiple sync folder connection of the same folder (#6032)
|
||||
* Tray Menu: More detailed status messages
|
||||
* Tray Menu: Shibboleth: raise the browser when clicking on the tray (#6105)
|
||||
* Activity: Link errors from the account tab, allow filtering by account/folder (#5861)
|
||||
* Activity: Present conflicts more prominently (#5894)
|
||||
* Activity: Allow sorting the columns in issues and protocol tabs (#6093, #6086)
|
||||
* Selective Sync: Open sub folder context menu (#5596)
|
||||
* Selective Sync: Skip excluded folders when reading db (#5772)
|
||||
* Selective Sync: Remove local files of unselected folder despite other modified files (#5783)
|
||||
* Excludes: Remove .htaccess form list of excluded files (#5701)
|
||||
* Excludes: Hardcode desktop.ini
|
||||
* Excludes: Allow escaping "#" (#6012)
|
||||
* Excludes: Use faster matching via QRegularExpression (#6063)
|
||||
* Discovery: Increase the MAX_DEPTH and show deep folders as ignored (#1067)
|
||||
* Discovery: General speed improvements
|
||||
* Downloads: Remove empty temporary if disk space full (#5746)
|
||||
* Downloads: Read Content-MD5 header for object store setups
|
||||
* Checksums: Add global disable environment variable (#5017)
|
||||
* Quota: PropagateUpload: Model of remote quota, avoid some uploads (#5537)
|
||||
* Create favorite also in folder wizard (#455)
|
||||
* Windows: Use the application icon for the Windows 8 sidebar favorite (#2446, #5690)
|
||||
* macOS: Finder sidebar icon (#296)
|
||||
* Overlay Icons: Consider also the "shared by me" as shared (#4788)
|
||||
* Overlay Icons: Update right after sharing (#6115)
|
||||
* Overlay Icons: Fix different case paths not matching (#5257)
|
||||
* Overlay Icons: Detect changes in the shared flag (#6098)
|
||||
* Windows Overlay Icons: Potential hang fixes
|
||||
* Linux Overlay Icons: fix branded nemo and caja shell integration (#5966)
|
||||
* Credentials: Fix behavior for bad password (#5989)
|
||||
* Credentials: Don't create empty client cert keychain entries (#5752)
|
||||
* Credentials: Namespace windows cred keys (#6125)
|
||||
* Credentials: Use per-account keychain entries (#5830, #6126)
|
||||
* AccountSettings: Triggering log in re-ask about previously rejected certificates (#5819)
|
||||
* owncloudcmd: Added bandwidth limit parameter (#5707)
|
||||
* owncloudcmd: Fix timestamps, Fix --logdebug
|
||||
* AccountSettings: Sync with clean discovery on Ctrl-F6 (#5666)
|
||||
* Sync: Dynamic sizing of chunks in chunked uploads for improved big file upload performance (#5852)
|
||||
* Sync: Introduce overall errors that are not tied to a file (#5746)
|
||||
* Sync: Better messaging for 507 Insufficient Storage (#5537)
|
||||
* Sync: Create conflicts by comparing the hash of files with identical mtime/size (#5589)
|
||||
* Sync: Avoid downloads by comparing the hash of files with identical mtime/size (#6153)
|
||||
* Sync: Upload conflict files if OWNCLOUD_UPLOAD_CONFLICT_FILES environment variable is set (#6038)
|
||||
* Sync: Blacklist: Don't let errors become warnings (#5516)
|
||||
* Sync: Check etag again after active sync (#4116)
|
||||
* Sync: Rename handling fixes: duplicate file ids (#6096, #6212)
|
||||
* Sync: Rename handling fixes: File size must be equal
|
||||
* Sync: Rename handling: Fix duplicate files on abort/resume sync (#5949)
|
||||
* Sync: Add capability for invalid filename regexes (#6092)
|
||||
* SyncJournalDB: Fall back to DELETE journal mode if WAL mode does not seem to work (#5723)
|
||||
* SyncJournalDB: Don't crash if the db file is readonly (#6050)
|
||||
* SyncJournalDB: DB close error is not fatal
|
||||
* Fix at least one memory leak
|
||||
* Documentation improvements
|
||||
* Logging improvements (With Qt logging categories) (#5671)
|
||||
* Logging filtering per account (#5672)
|
||||
* Crash fixes
|
||||
* Test improvements
|
||||
* Small UI layout fixes
|
||||
* Performance improvements
|
||||
* Maintenance Mode: Detect maintenance mode (#4485)
|
||||
* Maintenance Mode: Add a 1 to 5 min reconnection delay (#5872)
|
||||
* HTTP: Send a unique X-Request-ID with each request (#5853)
|
||||
* HTTP: Support HTTP2 when built and running with Qt 5.9.x (Official packages still on Qt 5.6.x) (#5659)
|
||||
* owncloudcmd: Don't start if connection or auth fails (#5692)
|
||||
* csync: Switch build from C to C++ (#6033)
|
||||
* csync: Refactor a lot to use common data structures to save memory and memory copying
|
||||
* csync: Switch some data structures to Qt data structures
|
||||
* csync: Switch to using upper layer SyncJournalDB (#6087)
|
||||
* Switch 3rdparty/json usage to Qt5's QJson (#5710)
|
||||
* OpenSSL: Don't require directly, only via Qt (#5833)
|
||||
* Remove iconv dependency, use Qt for file system locale encoding/decoding (emoji filename support on macOS) (#5875)
|
||||
* Compilation: Remove Qt 4 code (#6025, #5702, #5505)
|
||||
* Harmonize source code style with clang-format (#5732)
|
||||
* Switch over to Qt 5 function pointer signal/slot syntax (#6041)
|
||||
* Compile with stack-smashing protection
|
||||
* Updater: Rudimentary support for beta channel (#6048)
|
||||
|
||||
version 2.3.4 (2017-11-02)
|
||||
* Checksums: Use addData function to avoid endless loop CPU load issues with Office files
|
||||
* Packaging: Require ZLIB
|
||||
|
||||
version 2.3.3 (2017-08-29)
|
||||
* Chunking NG: Don't use old chunking on new DAV endpoint (#5855)
|
||||
* Selective Sync: Skip excluded folders when reading DB, don't let them show errors (#5772)
|
||||
* Settings: Make window bigger so Qt version is always visible (#5760)
|
||||
@@ -10,6 +216,7 @@ version 2.3.3 (2017-07-XX)
|
||||
* Overlay Icons: Fix potential hangs on Windows
|
||||
* SyncJournalDB: Don't use ._ as filename pattern if that does not work because of SMB storage settings (#5844)
|
||||
* SyncJournalDB: Log reason for sqlite3 opening errors
|
||||
* Notifications: Proapgate "Dismiss" button action to server (#5922)
|
||||
* Switch Linux build also to Qt 5.6.2 (#5470)
|
||||
* Stopped maintaining Qt 4 buildability
|
||||
|
||||
@@ -127,7 +334,6 @@ version 2.2.0 (release 2016-05-12)
|
||||
* Documentation Improvements, ie. about overlay icons
|
||||
* Translation fixes
|
||||
* Countless other bugfixes
|
||||
* Sqlite Update to recent version
|
||||
* Update of QtKeyChain to support Windows credential store
|
||||
* Packaging of dolphin overlay icon module for bleeding edge distros
|
||||
|
||||
@@ -198,7 +404,6 @@ version 2.1 (release 2015-12-03)
|
||||
* Fixed getting size for selective sync (#3986)
|
||||
* Re-added close button in the settings window (#3713)
|
||||
* Added abililty to handle storage limitations gracefully (#3736)
|
||||
* Updated 3rdparty dependencies: sqlite version 3.9.1
|
||||
* Organized patches to our base Qt version into admin/qt/patches
|
||||
* Plus: A lot of unmentioned improvements and fixes
|
||||
|
||||
|
||||
92
Jenkinsfile
vendored
92
Jenkinsfile
vendored
@@ -1,42 +1,72 @@
|
||||
#!groovy
|
||||
|
||||
//
|
||||
// We now run the tests in Debug mode so that ASSERTs are triggered.
|
||||
// Ideally we should run the tests in both Debug and Release so we catch
|
||||
// all possible error combinations.
|
||||
// See also the top comment in syncenginetestutils.h
|
||||
//
|
||||
// We are building "Linux - GCC" with "make" and "Linux - Clang" with ninja,
|
||||
// the combinations are more or less arbitrarily chosen. We just want to
|
||||
// check that both compilers and both CMake generators work. It's
|
||||
// unlikely that a specific generator only breaks with a specific
|
||||
// compiler.
|
||||
|
||||
// Constructed from the DockerFile in admin/linux/DockerFile
|
||||
def linux = docker.image('dominikschmidt/docker-owncloud-client-linux:latest')
|
||||
// Constructed from the DockerFile in admin/win/docker/DockerFile
|
||||
def win32 = docker.image('dominikschmidt/docker-owncloud-client-win32-cross:latest')
|
||||
|
||||
node('CLIENT') {
|
||||
stage 'Checkout'
|
||||
checkout scm
|
||||
sh '''git submodule update --init'''
|
||||
|
||||
stage 'Qt5'
|
||||
sh '''rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF ..
|
||||
make -j4
|
||||
ctest --output-on-failure'''
|
||||
stage 'Linux - Pull Docker Image'
|
||||
linux.pull()
|
||||
|
||||
stage 'Qt5 - clang'
|
||||
sh '''rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DWITH_TESTING=1 -DBUILD_WITH_QT4=OFF ..
|
||||
make -j4
|
||||
ctest --output-on-failure'''
|
||||
stage 'Linux - GCC'
|
||||
linux.inside {
|
||||
sh '''
|
||||
export HOME="$(pwd)/home"
|
||||
rm -rf build home
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 ..
|
||||
make -j4
|
||||
LC_ALL=C.UTF-8 ctest -V --output-on-failure
|
||||
'''
|
||||
}
|
||||
|
||||
stage 'Linux - Clang'
|
||||
linux.inside {
|
||||
sh '''
|
||||
export HOME="$(pwd)/home"
|
||||
rm -rf build home
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE="Debug" -DUNIT_TESTING=1 ..
|
||||
ninja -j4
|
||||
LC_ALL=C.UTF-8 ctest -V --output-on-failure
|
||||
'''
|
||||
}
|
||||
|
||||
stage 'Win32'
|
||||
def win32 = docker.image('guruz/docker-owncloud-client-win32:latest')
|
||||
win32.pull() // make sure we have the latest available from Docker Hub
|
||||
win32.inside {
|
||||
sh '''
|
||||
rm -rf build-win32
|
||||
mkdir build-win32
|
||||
cd build-win32
|
||||
../admin/win/download_runtimes.sh
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
|
||||
make -j4
|
||||
make package
|
||||
ctest .
|
||||
'''
|
||||
}
|
||||
stage 'Win32 Cross - Pull Docker Image'
|
||||
win32.pull()
|
||||
|
||||
stage 'Win32 Cross'
|
||||
win32.inside {
|
||||
sh '''
|
||||
rm -rf build-win32
|
||||
mkdir build-win32
|
||||
cd build-win32
|
||||
../admin/win/download_runtimes.sh
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
|
||||
make -j4
|
||||
make package
|
||||
ctest .
|
||||
'''
|
||||
}
|
||||
|
||||
// Stage 'macOS' TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
set( APPLICATION_NAME "ownCloud" )
|
||||
set( APPLICATION_SHORTNAME "ownCloud" )
|
||||
set( APPLICATION_EXECUTABLE "owncloud" )
|
||||
set( APPLICATION_DOMAIN "owncloud.com" )
|
||||
set( APPLICATION_VENDOR "ownCloud" )
|
||||
set( APPLICATION_UPDATE_URL "https://updates.owncloud.com/client/" CACHE string "URL for updater" )
|
||||
set( APPLICATION_ICON_NAME "owncloud" )
|
||||
set( APPLICATION_VIRTUALFILE_SUFFIX "owncloud" CACHE STRING "Virtual file suffix (not including the .)")
|
||||
|
||||
set( LINUX_PACKAGE_SHORTNAME "owncloud" )
|
||||
|
||||
set( THEME_CLASS "ownCloudTheme" )
|
||||
set( APPLICATION_REV_DOMAIN "com.owncloud.desktopclient" )
|
||||
@@ -15,4 +20,4 @@ set( MAC_INSTALLER_BACKGROUND_FILE "${CMAKE_SOURCE_DIR}/admin/osx/installer-back
|
||||
|
||||
option( WITH_CRASHREPORTER "Build crashreporter" OFF )
|
||||
set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE string "URL for crash reporter" )
|
||||
set( CRASHREPORTER_ICON ":/owncloud-icon.png" )
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ if(WIN32)
|
||||
set( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" ) # File used as a description of a project /path/to/project/ReadMe.txt
|
||||
set( CPACK_PACKAGE_DESCRIPTION_SUMMARY "${APPLICATION_NAME} Syncing Client" ) # Description summary of a project
|
||||
# CPACK_PACKAGE_EXECUTABLES List of pairs of executables and labels. Used by the NSIS generator to create Start Menu shortcuts. ccmake;CMake
|
||||
set( CPACK_PACKAGE_INSTALL_DIRECTORY ${APPLICATION_SHORTNAME} ) # Installation directory on the target system -> C:\Program Files\fellody
|
||||
set( CPACK_PACKAGE_INSTALL_DIRECTORY ${APPLICATION_SHORTNAME} ) # Installation directory on the target system -> C:\Program Files\${APPLICATION_SHORTNAME}
|
||||
set( CPACK_PACKAGE_INSTALL_REGISTRY_KEY ${APPLICATION_SHORTNAME} ) # Registry key used when installing this project CMake 2.5.0
|
||||
set( CPACK_PACKAGE_NAME ${APPLICATION_NAME} ) # Package name, defaults to the project name
|
||||
set( CPACK_PACKAGE_VENDOR "http://${APPLICATION_DOMAIN}" ) # Package vendor name
|
||||
|
||||
40
README.md
40
README.md
@@ -1,10 +1,7 @@
|
||||
# ownCloud Desktop Client
|
||||
|
||||
| Job | State |
|
||||
|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| client-build-matrix | [](https://ci.owncloud.org/job/client-build-matrix-linux/) |
|
||||
| client-test-matrix-linux-no-build | [](https://ci.owncloud.org/job/client-test-matrix-linux-no-build/) |
|
||||
| coverity_scan | [](https://scan.coverity.com/projects/owncloud-mirall)
|
||||
[](https://jenkins.owncloud.org/job/owncloud-client/job/client/job/master/) [](https://ci.appveyor.com/project/ownclouders/client/branch/master)
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -15,7 +12,7 @@ with your computer.
|
||||
|
||||
### Binary packages
|
||||
|
||||
* Refer to the download page https://owncloud.org/install/#install-clients
|
||||
* Refer to the download page https://owncloud.org/download/#owncloud-desktop-client
|
||||
|
||||
### Source code
|
||||
|
||||
@@ -27,21 +24,9 @@ https://github.com/owncloud/client.
|
||||
|
||||
## Building the source code
|
||||
|
||||
[Building the Client](http://doc.owncloud.org/desktop/2.2/building.html)
|
||||
[Building the Client](http://doc.owncloud.org/desktop/2.3/building.html)
|
||||
in the ownCloud Desktop Client manual.
|
||||
|
||||
## Maintainers and Contributors
|
||||
|
||||
The maintainers of this repository are:
|
||||
|
||||
* Klaas Freitag <freitag@owncloud.com>
|
||||
* Daniel Molkentin <danimo@owncloud.com>
|
||||
* Markus Goetz <guruz@owncloud.com>
|
||||
* Olivier Goffart <ogoffart@owncloud.com>
|
||||
|
||||
ownCloud Desktop Client is developed by the ownCloud community and receives
|
||||
patches from a variety of authors.
|
||||
|
||||
## Reporting issues and contributing
|
||||
|
||||
If you find any bugs or have any suggestion for improvement, please
|
||||
@@ -59,6 +44,23 @@ If you want to contact us, e.g. before starting a more complex feature,
|
||||
you can join us at
|
||||
[#owncloud-client-dev](irc://irc.freenode.net/#owncloud-client-dev).
|
||||
|
||||
## Maintainers and Contributors
|
||||
|
||||
The current maintainers of this repository are:
|
||||
|
||||
* Markus Goetz <guruz@owncloud.com>
|
||||
* Olivier Goffart <ogoffart@owncloud.com>
|
||||
* Christian Kamm <mail@ckamm.de>
|
||||
|
||||
ownCloud Desktop Client is developed by the ownCloud community and [receives
|
||||
patches from a variety of authors](https://github.com/owncloud/client/graphs/contributors).
|
||||
|
||||
Past maintainers:
|
||||
|
||||
* Klaas Freitag <freitag@owncloud.com>
|
||||
* Daniel Molkentin <daniel@molkentin.de>
|
||||
* Andreas Schneider <asn@cryptomilk.org>
|
||||
|
||||
## License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
set( MIRALL_VERSION_MAJOR 2 )
|
||||
set( MIRALL_VERSION_MINOR 3 )
|
||||
set( MIRALL_VERSION_PATCH 3 )
|
||||
set( MIRALL_VERSION_YEAR 2017 )
|
||||
set( MIRALL_VERSION_MINOR 5 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_YEAR 2018 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "git") #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "alpha") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
22
admin/linux/Dockerfile
Normal file
22
admin/linux/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
# This DockerFile is used to create the image used for Jenkins, the CI system (see Jenkinsfile)
|
||||
# It is not meant to be used to create the production packages.
|
||||
|
||||
# Distro with Qt 5.6
|
||||
FROM ubuntu:yakkety
|
||||
|
||||
RUN apt-get update -q && DEBIAN_FRONTEND=noninteractive apt-get install -q -y --no-install-recommends \
|
||||
locales \
|
||||
build-essential \
|
||||
clang \
|
||||
ninja-build \
|
||||
cmake \
|
||||
extra-cmake-modules \
|
||||
libsqlite3-dev \
|
||||
libssl-dev \
|
||||
libcmocka-dev \
|
||||
qt5-default \
|
||||
qttools5-dev-tools \
|
||||
libqt5webkit5-dev \
|
||||
qt5keychain-dev \
|
||||
kio-dev \
|
||||
&& apt-get clean
|
||||
8
admin/linux/clean_tarball.sh
Executable file
8
admin/linux/clean_tarball.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -vrf admin/
|
||||
rm -vrf src/3rdparty/sqlite3 # FIXME: For CentOS6 we have to use our bundled sqlite
|
||||
rm -vrf binary/
|
||||
rm -vrf src/3rdparty/libcrashreporter-qt
|
||||
rm -vrf shell_integration/windows
|
||||
rm -vrf shell_integration/MacOSX
|
||||
@@ -11,7 +11,8 @@ else()
|
||||
set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0")
|
||||
endif()
|
||||
|
||||
configure_file(create_mac_pkg.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh)
|
||||
configure_file(macosx.pkgproj ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj)
|
||||
find_package(Qt5 5.6 COMPONENTS Core REQUIRED)
|
||||
configure_file(create_mac.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh)
|
||||
configure_file(macosx.pkgproj.cmake ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj)
|
||||
configure_file(pre_install.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh)
|
||||
configure_file(post_install.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/post_install.sh)
|
||||
|
||||
@@ -23,7 +23,7 @@ identity="$3"
|
||||
prjfile=$build_path/admin/osx/macosx.pkgproj
|
||||
|
||||
# The name of the installer package
|
||||
installer="@APPLICATION_SHORTNAME@-@MIRALL_VERSION_FULL@@MIRALL_VERSION_SUFFIX@"
|
||||
installer="@APPLICATION_SHORTNAME@-qt@Qt5Core_VERSION@-@MIRALL_VERSION_FULL@@MIRALL_VERSION_SUFFIX@"
|
||||
installer_file="$installer.pkg"
|
||||
installer_file_tar="$installer.pkg.tar"
|
||||
installer_file_tar_bz2="$installer.pkg.tar.bz2"
|
||||
@@ -22,6 +22,7 @@ import subprocess
|
||||
import commands
|
||||
import sys
|
||||
from glob import glob
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
def QueryQMake(attrib):
|
||||
return subprocess.check_output([qmake_path, '-query', attrib]).rstrip('\n')
|
||||
@@ -92,6 +93,8 @@ commands.append(['mkdir', '-p', resources_dir])
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
|
||||
binaries = [i for i in glob(os.path.join(bundle_dir, 'Contents', 'MacOS', "*")) if is_exe(i)];
|
||||
|
||||
qt_version = QueryQMake('QT_VERSION')
|
||||
print "Using Qt", qt_version
|
||||
|
||||
fixed_libraries = []
|
||||
fixed_frameworks = []
|
||||
@@ -334,9 +337,19 @@ def FindQtPlugin(name):
|
||||
for binary in binaries:
|
||||
FixBinary(binary)
|
||||
|
||||
|
||||
if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
|
||||
QT_PLUGINS.append('styles/libqmacstyle.dylib')
|
||||
for plugin in QT_PLUGINS:
|
||||
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
||||
|
||||
if LooseVersion(qt_version) >= LooseVersion("5.10.0"):
|
||||
args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.10.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
|
||||
commands.append(args)
|
||||
else:
|
||||
args = ['plutil', '-insert', 'LSMinimumSystemVersion', '-string', '10.7.0', os.path.join(bundle_dir, 'Contents', 'Info.plist')]
|
||||
commands.append(args)
|
||||
|
||||
if len(sys.argv) <= 2:
|
||||
print 'Will run %d commands:' % len(commands)
|
||||
for command in commands:
|
||||
|
||||
@@ -506,536 +506,6 @@
|
||||
<key>UUID</key>
|
||||
<string>7D7219B7-1897-48C3-8533-842BDEC46F71</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>PACKAGE_FILES</key>
|
||||
<dict>
|
||||
<key>DEFAULT_INSTALL_LOCATION</key>
|
||||
<string>/</string>
|
||||
<key>HIERARCHY</key>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Utilities</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Applications</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>509</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Application Support</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Documentation</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Filesystems</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Frameworks</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Input Methods</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Internet Plug-Ins</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>LaunchAgents</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>LaunchDaemons</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>PreferencePanes</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Preferences</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Printers</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>PrivilegedHelperTools</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>QuickLook</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>QuickTime</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Screen Savers</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Library/ScriptingAdditions/SyncStateFinder.osax/Contents</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>SyncStateFinder.osax</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ScriptingAdditions</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Scripts</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Services</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Widgets</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Library</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Extensions</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Library</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>System</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>Shared</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>1023</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>Users</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>/</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>PAYLOAD_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>VERSION</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>PACKAGE_SCRIPTS</key>
|
||||
<dict>
|
||||
<key>POSTINSTALL_PATH</key>
|
||||
<dict/>
|
||||
<key>PREINSTALL_PATH</key>
|
||||
<dict/>
|
||||
<key>RESOURCES</key>
|
||||
<array/>
|
||||
</dict>
|
||||
<key>PACKAGE_SETTINGS</key>
|
||||
<dict>
|
||||
<key>AUTHENTICATION</key>
|
||||
<integer>1</integer>
|
||||
<key>CONCLUSION_ACTION</key>
|
||||
<integer>0</integer>
|
||||
<key>IDENTIFIER</key>
|
||||
<string>com.ownCloud.finderPlugin</string>
|
||||
<key>LOCATION</key>
|
||||
<integer>0</integer>
|
||||
<key>NAME</key>
|
||||
<string>Legacy Finder Plugin (OS X 10.9 or older)</string>
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>@MIRALL_VERSION_FULL@</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>UUID</key>
|
||||
<string>39F61FCD-6EAA-4F3A-81C6-25E3F667DFB5</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PROJECT</key>
|
||||
<dict>
|
||||
@@ -1103,56 +573,15 @@
|
||||
<key>UUID</key>
|
||||
<string>9647ADC0-BD53-4D7D-A561-73D383AACDE1</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>DESCRIPTION</key>
|
||||
<array/>
|
||||
<key>OPTIONS</key>
|
||||
<dict>
|
||||
<key>HIDDEN</key>
|
||||
<false/>
|
||||
<key>STATE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>PACKAGE_UUID</key>
|
||||
<string>39F61FCD-6EAA-4F3A-81C6-25E3F667DFB5</string>
|
||||
<key>REQUIREMENTS</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>BEHAVIOR</key>
|
||||
<integer>1</integer>
|
||||
<key>DICTIONARY</key>
|
||||
<dict>
|
||||
<key>IC_REQUIREMENT_JAVASCRIPT_FUNCTION</key>
|
||||
<string>olderOsx</string>
|
||||
<key>IC_REQUIREMENT_JAVASCRIPT_PARAMETERS</key>
|
||||
<array/>
|
||||
</dict>
|
||||
<key>IDENTIFIER</key>
|
||||
<string>fr.whitebox.Packages.requirement.javascript</string>
|
||||
<key>MESSAGE</key>
|
||||
<array/>
|
||||
<key>NAME</key>
|
||||
<string>JavaScript</string>
|
||||
<key>STATE</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
<key>TITLE</key>
|
||||
<array/>
|
||||
<key>TOOLTIP</key>
|
||||
<array/>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>UUID</key>
|
||||
<string>1D2C47E0-5FD3-4623-B934-1347C66782D0</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>REMOVED</key>
|
||||
<dict/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>INSTALLATION TYPE</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
<key>MODE</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>INSTALLATION_STEPS</key>
|
||||
<array>
|
||||
@@ -1272,7 +701,7 @@
|
||||
<key>BUILD_PATH</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>../install/.</string>
|
||||
<string>@CMAKE_INSTALL_PREFIX@/.</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
@@ -1450,18 +879,6 @@
|
||||
<string>@CMAKE_INSTALL_DIR@</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SHARED_GLOBAL_DATA</key>
|
||||
<dict>
|
||||
<key>IC_REQUIREMENT_JAVASCRIPT_SHARED_SOURCE_CODE</key>
|
||||
<string>
|
||||
function olderOsx() {
|
||||
if(system.compareVersions(system.version.ProductVersion, '10.10') == -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>VERSION</key>
|
||||
@@ -1,12 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
osascript << EOF
|
||||
# Check if Finder is running (for systems with Finder disabled)
|
||||
finder_status=`ps aux | grep "/System/Library/CoreServices/Finder.app/Contents/MacOS/Finder" | grep -v "grep"`
|
||||
if ! [ "$finder_status" == "" ] ; then # Finder is running
|
||||
osascript << EOF
|
||||
tell application "Finder"
|
||||
activate
|
||||
select the last Finder window
|
||||
reveal POSIX file "/Applications/@APPLICATION_EXECUTABLE@.app"
|
||||
end tell
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Always enable the new 10.10 finder plugin if available
|
||||
if [ -x "$(command -v pluginkit)" ]; then
|
||||
|
||||
@@ -3,7 +3,4 @@
|
||||
# kill the old version. see issue #2044
|
||||
killall @APPLICATION_EXECUTABLE@
|
||||
|
||||
# Unload the Finder plugin. see issue #2105
|
||||
killall Finder
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
[ "$#" -lt 2 ] && echo "Usage: sign_dmg.sh <dmg> <identity>" && exit
|
||||
|
||||
src_dmg="$1"
|
||||
tmp_dmg="writable_$1"
|
||||
signed_dmg="signed_$1"
|
||||
identity="$2"
|
||||
|
||||
QT_FMWKS=`basename ${TMP_APP}/Contents/Frameworks`/Qt*
|
||||
QT_FMWK_VERSION="5"
|
||||
|
||||
fix_frameworks() {
|
||||
TMP_APP=$1
|
||||
QT_FMWK_PATH=$2
|
||||
QT_FMWKS=$3/Qt*.framework
|
||||
|
||||
echo "Patching Qt frameworks..."
|
||||
for FMWK in $QT_FMWKS; do
|
||||
FMWK_NAME=`basename -s .framework $FMWK`
|
||||
FMWK=`basename $FMWK`
|
||||
FMWK_PATH="${TMP_APP}/Contents/Frameworks/${FMWK}"
|
||||
mkdir -p "${FMWK_PATH}/Versions/${QT_FMWK_VERSION}/Resources/"
|
||||
cp -avf "${QT_FMWK_PATH}/${FMWK}/Contents/Info.plist" "${FMWK_PATH}/Versions/${QT_FMWK_VERSION}/Resources"
|
||||
(cd "${FMWK_PATH}" && ln -sf "Versions/${QT_FMWK_VERSION}/Resources" "Resources")
|
||||
perl -pi -e "s/${FMWK_NAME}_debug/${FMWK_NAME}/" "${FMWK_PATH}/Resources/Info.plist"
|
||||
done
|
||||
}
|
||||
|
||||
mount="/Volumes/$(basename "$src_dmg"|sed 's,-\([0-9]\)\(.*\),,')"
|
||||
test -e "$tmp_dmg" && rm -rf "$tmp_dmg"
|
||||
hdiutil convert "$src_dmg" -format UDRW -o "$tmp_dmg"
|
||||
hdiutil attach "$tmp_dmg"
|
||||
pushd "$mount"
|
||||
fix_frameworks "$mount"/*.app `qmake -query QT_INSTALL_LIBS` "$mount"/*.app/Contents/Frameworks
|
||||
codesign -s "$identity" --deep "$mount"/*.app
|
||||
popd
|
||||
diskutil eject "$mount"
|
||||
test -e "$signed_dmg" && rm -rf "$signed_dmg"
|
||||
hdiutil convert "$tmp_dmg" -format UDBZ -o "$signed_dmg"
|
||||
@@ -27,8 +27,8 @@ SET(QT_MKSPECS_DIR ${CMAKE_FIND_ROOT_PATH}/share/qt5/mkspecs)
|
||||
SET(QT_QT_INCLUDE_DIR ${CMAKE_FIND_ROOT_PATH}/include)
|
||||
|
||||
# qt tools
|
||||
SET(QT_QMAKE_EXECUTABLE ${MINGW_PREFIX}-qmake )
|
||||
SET(QT_MOC_EXECUTABLE ${MINGW_PREFIX}-moc)
|
||||
SET(QT_RCC_EXECUTABLE ${MINGW_PREFIX}-rcc)
|
||||
SET(QT_UIC_EXECUTABLE ${MINGW_PREFIX}-uic)
|
||||
SET(QT_LRELEASE_EXECUTABLE ${MINGW_PREFIX}-lrelease)
|
||||
SET(QT_QMAKE_EXECUTABLE ${MINGW_PREFIX}-qmake-qt5)
|
||||
SET(QT_MOC_EXECUTABLE ${MINGW_PREFIX}-moc-qt5)
|
||||
SET(QT_RCC_EXECUTABLE ${MINGW_PREFIX}-rcc-qt5)
|
||||
SET(Qt5Widgets_UIC_EXECUTABLE ${MINGW_PREFIX}-uic-qt5)
|
||||
SET(QT_LRELEASE_EXECUTABLE ${MINGW_PREFIX}-lrelease-qt5)
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
FROM opensuse:42.1
|
||||
|
||||
MAINTAINER Daniel Molkentin <danimo@owncloud.com>
|
||||
|
||||
ENV TERM ansi
|
||||
ENV HOME /root
|
||||
|
||||
ENV REFRESHED_AT 20160421
|
||||
ENV REFRESHED_AT 20170113
|
||||
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys refresh
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_42.1/windows:mingw.repo
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_Leap_42.1/windows:mingw.repo
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/isv:ownCloud:toolchains:mingw:win32:2.3/openSUSE_Leap_42.1/isv:ownCloud:toolchains:mingw:win32:2.3.repo
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
|
||||
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
|
||||
mingw32-headers mingw32-runtime site-config mingw32-libwebp \
|
||||
mingw32-headers mingw32-runtime site-config mingw32-libwebp mingw32-libssp0 \
|
||||
mingw32-cross-libqt5-qmake mingw32-cross-libqt5-qttools mingw32-libqt5* \
|
||||
mingw32-qt5keychain* mingw32-angleproject* \
|
||||
mingw32-cross-nsis mingw32-libopenssl* \
|
||||
mingw32-sqlite* kdewin-png2ico \
|
||||
mingw32-sqlite* png2ico \
|
||||
osslsigncode wget
|
||||
|
||||
# RPM depends on curl for installs from HTTP
|
||||
|
||||
@@ -3,7 +3,7 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Vis versjonsmerknader"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Fant ${APPLICATION_EXECUTABLE}-prosess(er) som må stoppes.$\nVil du at installasjonsprogrammet skal stoppe dem for deg?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Terminerer ${APPLICATION_EXECUTABLE}-prosesser."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Fant ikke prosess som skulle termineres!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "En eldre versjon av ${APPLICATION_NAME} er installert på systemet ditt. Det anbefales at du avnistallerer den versjonen før installering av ny versjon. Velg hva du vil gjøre og klikk Neste for å fortsette."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "En eldre versjon av ${APPLICATION_NAME} er installert på systemet ditt. Det anbefales at du avinstallerer den versjonen før installering av ny versjon. Velg hva du vil gjøre og klikk Neste for å fortsette."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Avinstaller før installering"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Ikke avinstaller"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Allerede installert"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar las notas de la versión"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "El/los proceso/s ${APPLICATION_EXECUTABLE} debe/n ser detenidos.$\n¿Quiere que el instalador lo haga por usted?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Deteniendo el/los proceso/s ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "El/los proceso(s) ${APPLICATION_EXECUTABLE} debe(n) ser detenido(s).$\n¿Quiere que el instalador lo haga por usted?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Deteniendo el/los proceso(s) ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "¡Proceso a finalizar no encontrado!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} se encuentra instalada en el sistema. Se recomienda de instalar la versión actual antes de instalar la nueva. Seleccione la operacion deseada y haga click en Siguiente para continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} se encuentra instalada en el sistema. Se recomienda desinstalar la versión actual antes de instalar la nueva. Seleccione la operacion deseada y haga click en Siguiente para continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "No desinstalar"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ya está instalado"
|
||||
@@ -17,13 +17,13 @@ StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Elija la opcion de mantenim
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instalando ${APPLICATION_NAME} esenciales."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integración para Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instalando la integración para Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso directo al programa Menú de Inicio"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso directo al programa en Menú de Inicio"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Añadiendo accesos directos para ${APPLICATION_NAME} en el Menú de Inicio."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Acceso directo de Escritorio"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creando accesos directos de escritorio"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Atajo de accceso rápido"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Atajo de acceso rápido"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creando un Acceso Directo al Lanzador Rápido"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} esencial."
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} esenciales."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Acceso Directo de ${APPLICATION_NAME}"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Acceso Directo de Escritorio para ${APPLICATION_NAME}"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Lanzador Rápido de Accesos Director para ${APPLICATION_NAME}."
|
||||
|
||||
120
admin/win/nsi/lib/fileassoc.nsh
Normal file
120
admin/win/nsi/lib/fileassoc.nsh
Normal file
@@ -0,0 +1,120 @@
|
||||
; fileassoc.nsh
|
||||
; File association helper macros
|
||||
; Written by Saivert
|
||||
; See http://nsis.sourceforge.net/FileAssoc
|
||||
;
|
||||
; Features automatic backup system and UPDATEFILEASSOC macro for
|
||||
; shell change notification.
|
||||
;
|
||||
; |> How to use <|
|
||||
; To associate a file with an application so you can double-click it in explorer, use
|
||||
; the APP_ASSOCIATE macro like this:
|
||||
;
|
||||
; Example:
|
||||
; !insertmacro APP_ASSOCIATE "txt" "myapp.textfile" "Description of txt files" \
|
||||
; "$INSTDIR\myapp.exe,0" "Open with myapp" "$INSTDIR\myapp.exe $\"%1$\""
|
||||
;
|
||||
; Never insert the APP_ASSOCIATE macro multiple times, it is only ment
|
||||
; to associate an application with a single file and using the
|
||||
; the "open" verb as default. To add more verbs (actions) to a file
|
||||
; use the APP_ASSOCIATE_ADDVERB macro.
|
||||
;
|
||||
; Example:
|
||||
; !insertmacro APP_ASSOCIATE_ADDVERB "myapp.textfile" "edit" "Edit with myapp" \
|
||||
; "$INSTDIR\myapp.exe /edit $\"%1$\""
|
||||
;
|
||||
; To have access to more options when registering the file association use the
|
||||
; APP_ASSOCIATE_EX macro. Here you can specify the verb and what verb is to be the
|
||||
; standard action (default verb).
|
||||
;
|
||||
; And finally: To remove the association from the registry use the APP_UNASSOCIATE
|
||||
; macro. Here is another example just to wrap it up:
|
||||
; !insertmacro APP_UNASSOCIATE "txt" "myapp.textfile"
|
||||
;
|
||||
; |> Note <|
|
||||
; When defining your file class string always use the short form of your application title
|
||||
; then a period (dot) and the type of file. This keeps the file class sort of unique.
|
||||
; Examples:
|
||||
; Winamp.Playlist
|
||||
; NSIS.Script
|
||||
; Photoshop.JPEGFile
|
||||
;
|
||||
; |> Tech info <|
|
||||
; The registry key layout for a file association is:
|
||||
; HKEY_CLASSES_ROOT
|
||||
; <applicationID> = <"description">
|
||||
; shell
|
||||
; <verb> = <"menu-item text">
|
||||
; command = <"command string">
|
||||
;
|
||||
|
||||
!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
|
||||
; Backup the previously associated file class
|
||||
ReadRegStr $R0 HKCR ".${EXT}" ""
|
||||
WriteRegStr HKCR ".${EXT}" "${FILECLASS}_backup" "$R0"
|
||||
|
||||
WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}"
|
||||
|
||||
WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}`
|
||||
WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}`
|
||||
WriteRegStr HKCR "${FILECLASS}\shell" "" "open"
|
||||
WriteRegStr HKCR "${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
|
||||
WriteRegStr HKCR "${FILECLASS}\shell\open\command" "" `${COMMAND}`
|
||||
!macroend
|
||||
|
||||
!macro APP_ASSOCIATE_EX EXT FILECLASS DESCRIPTION ICON VERB DEFAULTVERB SHELLNEW COMMANDTEXT COMMAND
|
||||
; Backup the previously associated file class
|
||||
ReadRegStr $R0 HKCR ".${EXT}" ""
|
||||
WriteRegStr HKCR ".${EXT}" "${FILECLASS}_backup" "$R0"
|
||||
|
||||
WriteRegStr HKCR ".${EXT}" "" "${FILECLASS}"
|
||||
StrCmp "${SHELLNEW}" "0" +2
|
||||
WriteRegStr HKCR ".${EXT}\ShellNew" "NullFile" ""
|
||||
|
||||
WriteRegStr HKCR "${FILECLASS}" "" `${DESCRIPTION}`
|
||||
WriteRegStr HKCR "${FILECLASS}\DefaultIcon" "" `${ICON}`
|
||||
WriteRegStr HKCR "${FILECLASS}\shell" "" `${DEFAULTVERB}`
|
||||
WriteRegStr HKCR "${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}`
|
||||
WriteRegStr HKCR "${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}`
|
||||
!macroend
|
||||
|
||||
!macro APP_ASSOCIATE_ADDVERB FILECLASS VERB COMMANDTEXT COMMAND
|
||||
WriteRegStr HKCR "${FILECLASS}\shell\${VERB}" "" `${COMMANDTEXT}`
|
||||
WriteRegStr HKCR "${FILECLASS}\shell\${VERB}\command" "" `${COMMAND}`
|
||||
!macroend
|
||||
|
||||
!macro APP_ASSOCIATE_REMOVEVERB FILECLASS VERB
|
||||
DeleteRegKey HKCR `${FILECLASS}\shell\${VERB}`
|
||||
!macroend
|
||||
|
||||
|
||||
!macro APP_UNASSOCIATE EXT FILECLASS
|
||||
; Backup the previously associated file class
|
||||
ReadRegStr $R0 HKCR ".${EXT}" `${FILECLASS}_backup`
|
||||
WriteRegStr HKCR ".${EXT}" "" "$R0"
|
||||
|
||||
DeleteRegKey HKCR `${FILECLASS}`
|
||||
!macroend
|
||||
|
||||
!macro APP_ASSOCIATE_GETFILECLASS OUTPUT EXT
|
||||
ReadRegStr ${OUTPUT} HKCR ".${EXT}" ""
|
||||
!macroend
|
||||
|
||||
|
||||
; !defines for use with SHChangeNotify
|
||||
!ifdef SHCNE_ASSOCCHANGED
|
||||
!undef SHCNE_ASSOCCHANGED
|
||||
!endif
|
||||
!define SHCNE_ASSOCCHANGED 0x08000000
|
||||
!ifdef SHCNF_FLUSH
|
||||
!undef SHCNF_FLUSH
|
||||
!endif
|
||||
!define SHCNF_FLUSH 0x1000
|
||||
|
||||
!macro UPDATEFILEASSOC
|
||||
; Using the system.dll plugin to call the SHChangeNotify Win32 API function so we
|
||||
; can update the shell.
|
||||
System::Call "shell32::SHChangeNotify(i,i,i,i) (${SHCNE_ASSOCCHANGED}, ${SHCNF_FLUSH}, 0, 0)"
|
||||
!macroend
|
||||
|
||||
;EOF
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 25 KiB |
50
appveyor.ini
Normal file
50
appveyor.ini
Normal file
@@ -0,0 +1,50 @@
|
||||
[General]
|
||||
Branch = master
|
||||
ShallowClone = True
|
||||
Command=craft
|
||||
|
||||
# Variables defined here override the default value
|
||||
# The variable names are casesensitive
|
||||
[Variables]
|
||||
#Values need to be overwritten to create a chache
|
||||
UseCache = True
|
||||
CreateCache = False
|
||||
QtVersion = 5.10.1
|
||||
OpenSslVersion = 1.1.0h
|
||||
CacheVersion = Qt_${Variables:QtVersion}-1
|
||||
|
||||
# Settings applicable for all Crafts matrices
|
||||
# Settings are Category/key=value
|
||||
# Category is case sensitive
|
||||
|
||||
[GeneralSettings]
|
||||
General/EMERGE_PKGDSTDIR=${Variables:APPVEYOR_BUILD_FOLDER}/binaries
|
||||
Paths/python = C:\Python36
|
||||
Paths/python27 = C:\Python27
|
||||
Paths/downloaddir = ${Variables:Root}\downloads
|
||||
ShortPath/Enabled = False
|
||||
ShortPath/EnableJunctions = True
|
||||
ShortPath/JunctionDir = C:\CM-SP\
|
||||
Packager/CacheDir = ${Variables:Root}\cache
|
||||
Packager/UseCache = ${Variables:UseCache}
|
||||
Packager/CreateCache = ${Variables:CreateCache}
|
||||
Packager/CacheVersion = ${Variables:CacheVersion}
|
||||
; Packager/RepositoryUrl = https://files.kde.org/craft/
|
||||
Packager/PackageType = PortablePackager
|
||||
Packager/RepositoryUrl = http://ftp.acc.umu.se/mirror/kde.org/files/craft/master/
|
||||
Compile/BuildType = RelWithDebInfo
|
||||
ContinuousIntegration/Enabled = True
|
||||
|
||||
[BlueprintSettings]
|
||||
# don't try to pip install on the ci
|
||||
python-modules.ignored = True
|
||||
|
||||
libs/qt5.version = ${Variables:QtVersion}
|
||||
win32libs/openssl.version = ${Variables:OpenSslVersion}
|
||||
craft/craft-core.version = master
|
||||
|
||||
[windows-msvc2017_64-cl]
|
||||
General/ABI = windows-msvc2017_64-cl
|
||||
|
||||
[windows-msvc2017_32-cl]
|
||||
General/ABI = windows-msvc2017_32-cl
|
||||
43
appveyor.yml
Normal file
43
appveyor.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
version: '{build}-{branch}'
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
clone_depth: 50
|
||||
|
||||
|
||||
init:
|
||||
- ps: |
|
||||
function craft($target) {
|
||||
& C:\Python36\python.exe "C:\CraftMaster\CraftMaster\CraftMaster.py" --config "$env:APPVEYOR_BUILD_FOLDER\appveyor.ini" --variables "APPVEYOR_BUILD_FOLDER=$env:APPVEYOR_BUILD_FOLDER" --target $target -c $args
|
||||
if($LASTEXITCODE -ne 0) {exit $LASTEXITCODE}
|
||||
}
|
||||
|
||||
install:
|
||||
- ps: |
|
||||
#use cmd to silence powershell behaviour for stderr
|
||||
& cmd /C "git clone -q --depth=1 git://anongit.kde.org/craftmaster.git C:\CraftMaster\CraftMaster 2>&1"
|
||||
|
||||
craft $env:TARGET -i craft
|
||||
craft $env:TARGET --add-blueprint-repository [git]https://github.com/owncloud/craft-blueprints-owncloud.git
|
||||
craft $env:TARGET --install-deps owncloud-client
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
craft $env:TARGET --no-cache --src-dir $env:APPVEYOR_BUILD_FOLDER owncloud-client
|
||||
|
||||
after_build:
|
||||
- ps: |
|
||||
craft $env:TARGET --src-dir $env:APPVEYOR_BUILD_FOLDER --package owncloud-client
|
||||
|
||||
test_script:
|
||||
- ps: |
|
||||
craft $env:TARGET --src-dir $env:APPVEYOR_BUILD_FOLDER --test owncloud-client
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: windows-msvc2017_32-cl
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
- TARGET: windows-msvc2017_64-cl
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
2
binary
2
binary
Submodule binary updated: 1818b48380...39bfc426e5
@@ -20,7 +20,7 @@
|
||||
<file>resources/lock-https.png</file>
|
||||
<file>resources/lock-https@2x.png</file>
|
||||
<file>resources/account.png</file>
|
||||
<file>resources/more.png</file>
|
||||
<file>resources/more.svg</file>
|
||||
<file>resources/delete.png</file>
|
||||
<file>resources/bell.png</file>
|
||||
</qresource>
|
||||
|
||||
@@ -70,45 +70,64 @@ macro (KDE4_ADD_APP_ICON appsources pattern)
|
||||
endif(PNG2ICO_EXECUTABLE AND WINDRES_EXECUTABLE)
|
||||
endif(WIN32)
|
||||
if (APPLE)
|
||||
# first convert image to a tiff using the Mac OS X "sips" utility,
|
||||
# then use tiff2icns to convert to an icon
|
||||
find_program(SIPS_EXECUTABLE NAMES sips)
|
||||
find_program(TIFF2ICNS_EXECUTABLE NAMES tiff2icns)
|
||||
if (SIPS_EXECUTABLE AND TIFF2ICNS_EXECUTABLE)
|
||||
file(GLOB_RECURSE files "${pattern}")
|
||||
# we can only test for the 128-icon like that - we don't use patterns anymore
|
||||
foreach (it ${files})
|
||||
if (it MATCHES ".*128.*" )
|
||||
set (_icon ${it})
|
||||
endif (it MATCHES ".*128.*")
|
||||
endforeach (it)
|
||||
file(GLOB_RECURSE files "${pattern}")
|
||||
file(MAKE_DIRECTORY ${appsources}.iconset)
|
||||
|
||||
if (_icon)
|
||||
|
||||
# first, get the basename of our app icon
|
||||
add_custom_command(OUTPUT ${_outfilename}.icns ${outfilename}.tiff
|
||||
COMMAND ${SIPS_EXECUTABLE} -s format tiff ${_icon} --out ${outfilename}.tiff
|
||||
COMMAND ${TIFF2ICNS_EXECUTABLE} ${outfilename}.tiff ${_outfilename}.icns
|
||||
DEPENDS ${_icon}
|
||||
)
|
||||
# List from:
|
||||
# https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
|
||||
foreach (it ${files})
|
||||
if (it MATCHES ".*icon-16.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_16x16.png COPYONLY)
|
||||
elseif (it MATCHES ".*icon-32.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_16x16@2x.png COPYONLY)
|
||||
configure_file(${it} ${appsources}.iconset/icon_32x32.png COPYONLY)
|
||||
elseif (it MATCHES ".*icon-64.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_32x32@2x.png COPYONLY)
|
||||
elseif (it MATCHES ".*icon-128.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_128x128.png COPYONLY)
|
||||
elseif (it MATCHES ".*icon-256.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_128x128@2x.png COPYONLY)
|
||||
configure_file(${it} ${appsources}.iconset/icon_256x256.png COPYONLY)
|
||||
elseif (it MATCHES ".*icon-512.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_256x256@2x.png COPYONLY)
|
||||
configure_file(${it} ${appsources}.iconset/icon_512x512.png COPYONLY)
|
||||
elseif (it MATCHES ".*icon-1024.*")
|
||||
configure_file(${it} ${appsources}.iconset/icon_512x512@2x.png COPYONLY)
|
||||
endif()
|
||||
endforeach (it)
|
||||
|
||||
# This will register the icon into the bundle
|
||||
set(MACOSX_BUNDLE_ICON_FILE ${appsources}.icns)
|
||||
# Copy the sidebar icons in the main app bundle for the FinderSync extension to pick.
|
||||
# https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
|
||||
foreach (it ${files})
|
||||
if (it MATCHES ".*sidebar-16.*")
|
||||
configure_file(${it} ${appsources}.iconset/sidebar_16x16.png COPYONLY)
|
||||
elseif (it MATCHES ".*sidebar-18.*")
|
||||
configure_file(${it} ${appsources}.iconset/sidebar_18x18.png COPYONLY)
|
||||
elseif (it MATCHES ".*sidebar-32.*")
|
||||
configure_file(${it} ${appsources}.iconset/sidebar_16x16@2x.png COPYONLY)
|
||||
configure_file(${it} ${appsources}.iconset/sidebar_32x32.png COPYONLY)
|
||||
elseif (it MATCHES ".*sidebar-36.*")
|
||||
configure_file(${it} ${appsources}.iconset/sidebar_18x18@2x.png COPYONLY)
|
||||
elseif (it MATCHES ".*sidebar-64.*")
|
||||
configure_file(${it} ${appsources}.iconset/sidebar_32x32@2x.png COPYONLY)
|
||||
endif()
|
||||
endforeach (it)
|
||||
|
||||
# Append the icns file to the sources list so it will be a dependency to the
|
||||
# main target
|
||||
list(APPEND ${appsources} ${_outfilename}.icns)
|
||||
add_custom_command(OUTPUT ${_outfilename}.icns
|
||||
COMMAND echo === Building bundle icns with iconset:
|
||||
COMMAND ls -1 ${appsources}.iconset
|
||||
COMMAND iconutil -c icns -o ${_outfilename}.icns ${appsources}.iconset
|
||||
DEPENDS ${files}
|
||||
)
|
||||
|
||||
# Install the icon into the Resources dir in the bundle
|
||||
set_source_files_properties(${_outfilename}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
# This will register the icon into the bundle
|
||||
set(MACOSX_BUNDLE_ICON_FILE ${appsources}.icns)
|
||||
|
||||
else(_icon)
|
||||
# TODO - try to scale a non-128 icon...? Try to convert an SVG on the fly?
|
||||
message(STATUS "Unable to find an 128x128 icon that matches pattern ${pattern} for variable ${appsources} - application will not have an application icon!")
|
||||
endif(_icon)
|
||||
# Append the icns file to the sources list so it will be a dependency to the
|
||||
# main target
|
||||
list(APPEND ${appsources} ${_outfilename}.icns)
|
||||
|
||||
else(SIPS_EXECUTABLE AND TIFF2ICNS_EXECUTABLE)
|
||||
message(STATUS "Unable to find the sips and tiff2icns utilities - application will not have an application icon!")
|
||||
endif(SIPS_EXECUTABLE AND TIFF2ICNS_EXECUTABLE)
|
||||
# Install the icon into the Resources dir in the bundle
|
||||
set_source_files_properties(${_outfilename}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
endif(APPLE)
|
||||
endmacro (KDE4_ADD_APP_ICON)
|
||||
|
||||
382
cmake/modules/ECMAddAppIcon.cmake
Normal file
382
cmake/modules/ECMAddAppIcon.cmake
Normal file
@@ -0,0 +1,382 @@
|
||||
#.rst:
|
||||
# ECMAddAppIcon
|
||||
# -------------
|
||||
#
|
||||
# Add icons to executable files and packages.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_add_app_icon(<sources_var>
|
||||
# ICONS <icon> [<icon> [...]]
|
||||
# [SIDEBAR_ICONS <icon> [<icon> [...]] # Since 5.4x
|
||||
# [OUTFILE_BASE <name>]) # Since 5.4x
|
||||
# )
|
||||
#
|
||||
# The given icons, whose names must match the pattern::
|
||||
#
|
||||
# <size>-<other_text>.png
|
||||
#
|
||||
# will be added to the executable target whose sources are specified by
|
||||
# ``<sources_var>`` on platforms that support it (Windows and Mac OS X).
|
||||
# Other icon files are ignored but on Mac SVG files can be supported and
|
||||
# it is thus possible to mix those with png files in a single macro call.
|
||||
#
|
||||
# ``<size>`` is a numeric pixel size (typically 16, 32, 48, 64, 128 or 256).
|
||||
# ``<other_text>`` can be any other text. See the platform notes below for any
|
||||
# recommendations about icon sizes.
|
||||
#
|
||||
# ``SIDEBAR_ICONS`` can be used to add Mac OS X sidebar
|
||||
# icons to the generated iconset. They are used when a folder monitored by the
|
||||
# application is dragged into Finder's sidebar. Since 5.4x.
|
||||
#
|
||||
# ``OUTFILE_BASE`` will be used as the basename for the icon file. If
|
||||
# you specify it, the icon file will be called ``<OUTFILE_BASE>.icns`` on Mac OS X
|
||||
# and ``<OUTFILE_BASE>.ico`` on Windows. If you don't specify it, it defaults
|
||||
# to ``<sources_var>.<ext>``. Since 5.4x.
|
||||
#
|
||||
#
|
||||
# Windows notes
|
||||
# * Icons are compiled into the executable using a resource file.
|
||||
# * Icons may not show up in Windows Explorer if the executable
|
||||
# target does not have the ``WIN32_EXECUTABLE`` property set.
|
||||
# * The tool png2ico is required. See :find-module:`FindPng2Ico`.
|
||||
# * Supported sizes: 16, 32, 48, 64, 128.
|
||||
#
|
||||
# Mac OS X notes
|
||||
# * The executable target must have the ``MACOSX_BUNDLE`` property set.
|
||||
# * Icons are added to the bundle.
|
||||
# * If the ksvg2icns tool from KIconThemes is available, .svg and .svgz
|
||||
# files are accepted; the first that is converted successfully to .icns
|
||||
# will provide the application icon. SVG files are ignored otherwise.
|
||||
# * The tool iconutil (provided by Apple) is required for bitmap icons.
|
||||
# * Supported sizes: 16, 32, 64, 128, 256 (and 512, 1024 after OS X 10.9).
|
||||
# * At least a 128x128px (or an SVG) icon is required.
|
||||
# * Larger sizes are automatically used to substitute for smaller sizes on
|
||||
# "Retina" (high-resolution) displays. For example, a 32px icon, if
|
||||
# provided, will be used as a 32px icon on standard-resolution displays,
|
||||
# and as a 16px-equivalent icon (with an "@2x" tag) on high-resolution
|
||||
# displays. That is why you should provide 64px and 1024px icons although
|
||||
# they are not supported anymore directly. Instead they will be used as
|
||||
# 32px@2x and 512px@2x. ksvg2icns handles this internally.
|
||||
# * This function sets the ``MACOSX_BUNDLE_ICON_FILE`` variable to the name
|
||||
# of the generated icns file, so that it will be used as the
|
||||
# ``MACOSX_BUNDLE_ICON_FILE`` target property when you call
|
||||
# ``add_executable``.
|
||||
# * Sidebar icons should typically provided in 16, 32, 64, 128 and 256px.
|
||||
#
|
||||
# Since 1.7.0.
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
# Copyright 2014 Ralf Habacker <ralf.habacker@freenet.de>
|
||||
# Copyright 2006-2009 Alexander Neundorf, <neundorf@kde.org>
|
||||
# Copyright 2006, 2007, Laurent Montel, <montel@kde.org>
|
||||
# Copyright 2007 Matthias Kretz <kretz@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
function(ecm_add_app_icon appsources)
|
||||
set(options)
|
||||
set(oneValueArgs OUTFILE_BASE)
|
||||
set(multiValueArgs ICONS SIDEBAR_ICONS)
|
||||
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT ARG_ICONS)
|
||||
message(FATAL_ERROR "No ICONS argument given to ecm_add_app_icon")
|
||||
endif()
|
||||
if(ARG_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unexpected arguments to ecm_add_app_icon: ${ARG_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
find_program(KSVG2ICNS NAMES ksvg2icns)
|
||||
foreach(icon ${ARG_ICONS})
|
||||
get_filename_component(icon_full ${icon} ABSOLUTE)
|
||||
get_filename_component(icon_type ${icon_full} EXT)
|
||||
# do we have ksvg2icns in the path and did we receive an svg (or compressed svg) icon?
|
||||
if(KSVG2ICNS AND (${icon_type} STREQUAL ".svg" OR ${icon_type} STREQUAL ".svgz"))
|
||||
# convert the svg icon to an icon resource
|
||||
execute_process(COMMAND ${KSVG2ICNS} "${icon_full}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE KSVG2ICNS_ERROR)
|
||||
if(${KSVG2ICNS_ERROR})
|
||||
message(AUTHOR_WARNING "ksvg2icns could not generate an OS X application icon from ${icon}")
|
||||
else()
|
||||
# install the icns file we just created
|
||||
get_filename_component(icon_name ${icon_full} NAME_WE)
|
||||
set(MACOSX_BUNDLE_ICON_FILE ${icon_name}.icns PARENT_SCOPE)
|
||||
set(${appsources} "${${appsources}};${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns" PARENT_SCOPE)
|
||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
# we're done now
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
_ecm_add_app_icon_categorize_icons("${ARG_ICONS}" "icons" "16;32;48;64;128;256;512;1024")
|
||||
if(ARG_SIDEBAR_ICONS)
|
||||
_ecm_add_app_icon_categorize_icons("${ARG_SIDEBAR_ICONS}" "sidebar_icons" "16;18;32;36;64")
|
||||
endif()
|
||||
|
||||
set(mac_icons
|
||||
# Icons: https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
|
||||
${icons_at_16px}
|
||||
${icons_at_32px}
|
||||
${icons_at_64px}
|
||||
${icons_at_128px}
|
||||
${icons_at_256px}
|
||||
${icons_at_512px}
|
||||
${icons_at_1024px}
|
||||
|
||||
# Sidebar Icons: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
|
||||
${sidebar_icons_at_16px}
|
||||
${sidebar_icons_at_18px}
|
||||
${sidebar_icons_at_32px}
|
||||
${sidebar_icons_at_36px}
|
||||
${sidebar_icons_at_64px})
|
||||
if (NOT icons_at_128px)
|
||||
message(AUTHOR_WARNING "No 128px icon provided; this will not work on Mac OS X")
|
||||
endif()
|
||||
|
||||
|
||||
set(windows_icons_classic ${icons_at_16px}
|
||||
${icons_at_24px}
|
||||
${icons_at_32px}
|
||||
${icons_at_48px}
|
||||
${icons_at_64px}
|
||||
${icons_at_128px})
|
||||
set(windows_icons_modern ${windows_icons_classic}
|
||||
${icons_at_256px}
|
||||
${icons_at_512px}
|
||||
${icons_at_1024px})
|
||||
|
||||
if (NOT (windows_icons_modern OR windows_icons_classic))
|
||||
message(AUTHOR_WARNING "No icons suitable for use on Windows provided")
|
||||
endif()
|
||||
|
||||
if (ARG_OUTFILE_BASE)
|
||||
set (_outfilebasename "${ARG_OUTFILE_BASE}")
|
||||
else()
|
||||
set (_outfilebasename "${appsources}")
|
||||
endif()
|
||||
set (_outfilename "${CMAKE_CURRENT_BINARY_DIR}/${_outfilebasename}")
|
||||
|
||||
if (WIN32 AND (windows_icons_modern OR windows_icons_classic))
|
||||
set(saved_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_FIND_MODULE_DIR})
|
||||
find_package(Png2Ico)
|
||||
find_package(IcoTool)
|
||||
set(CMAKE_MODULE_PATH "${saved_CMAKE_MODULE_PATH}")
|
||||
|
||||
function(create_windows_icon_and_rc command args deps)
|
||||
add_custom_command(
|
||||
OUTPUT "${_outfilename}.ico"
|
||||
COMMAND ${command}
|
||||
ARGS ${args}
|
||||
DEPENDS ${deps}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
# this bit's a little hacky to make the dependency stuff work
|
||||
file(WRITE "${_outfilename}.rc.in" "IDI_ICON1 ICON DISCARDABLE \"${_outfilename}.ico\"\n")
|
||||
add_custom_command(
|
||||
OUTPUT "${_outfilename}.rc"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy "${_outfilename}.rc.in" "${_outfilename}.rc"
|
||||
DEPENDS "${_outfilename}.ico"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
if (IcoTool_FOUND)
|
||||
set(icotool_args "-c -o \"${_outfilename}.ico\"")
|
||||
|
||||
# According to https://stackoverflow.com/a/40851713/2886832
|
||||
# Windows always chooses the first icon above 255px, all other ones will be ignored
|
||||
set(maxSize 0)
|
||||
foreach(size 256 512 1024)
|
||||
if(icons_at_${size}px)
|
||||
set(maxSize "${size}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(size 16 32 48 64 128 ${maxSize})
|
||||
if(NOT icons_at_${size}px)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
set(icotool_icon_arg "")
|
||||
if(size STREQUAL "${maxSize}")
|
||||
# maxSize icon needs to be included as raw png
|
||||
list(APPEND icotool_args "-r")
|
||||
endif()
|
||||
|
||||
foreach(icon ${icons_at_${size}px})
|
||||
list(APPEND icotool_args "${icons_at_${size}px}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
create_windows_icon_and_rc(IcoTool::IcoTool "${icotool_args}" "${windows_icons_modern}")
|
||||
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
||||
|
||||
# standard png2ico has no rcfile argument
|
||||
elseif(Png2Ico_FOUND AND NOT Png2Ico_HAS_RCFILE_ARGUMENT AND windows_icons_classic)
|
||||
set(png2ico_args)
|
||||
list(APPEND png2ico_args "${_outfilename}.ico")
|
||||
list(APPEND png2ico_args "${windows_icons_classic}")
|
||||
|
||||
create_windows_icon_and_rc(Png2Ico::Png2Ico "${png2ico_args}" "${windows_icons_classic}")
|
||||
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
||||
|
||||
# png2ico from kdewin provides rcfile argument
|
||||
elseif(Png2Ico_FOUND AND windows_icons_classic)
|
||||
add_custom_command(
|
||||
OUTPUT "${_outfilename}.rc" "${_outfilename}.ico"
|
||||
COMMAND Png2Ico::Png2Ico
|
||||
ARGS
|
||||
--rcfile "${_outfilename}.rc"
|
||||
"${_outfilename}.ico"
|
||||
${windows_icons_classic}
|
||||
DEPENDS ${windows_icons_classic}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
||||
# else none of the supported tools was found
|
||||
else()
|
||||
message(WARNING "Unable to find the png2ico or icotool utilities or icons in matching sizes - application will not have an application icon!")
|
||||
endif()
|
||||
elseif (APPLE AND mac_icons)
|
||||
# first generate .iconset directory structure, then convert to .icns format using the Mac OS X "iconutil" utility,
|
||||
# to create retina compatible icon, you need png source files in pixel resolution 16x16, 32x32, 64x64, 128x128,
|
||||
# 256x256, 512x512, 1024x1024
|
||||
find_program(ICONUTIL_EXECUTABLE NAMES iconutil)
|
||||
if (ICONUTIL_EXECUTABLE)
|
||||
add_custom_command(
|
||||
OUTPUT "${_outfilename}.iconset"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E make_directory "${_outfilename}.iconset"
|
||||
)
|
||||
set(iconset_icons)
|
||||
macro(copy_icon filename sizename type)
|
||||
add_custom_command(
|
||||
OUTPUT "${_outfilename}.iconset/${type}_${sizename}.png"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy
|
||||
"${filename}"
|
||||
"${_outfilename}.iconset/${type}_${sizename}.png"
|
||||
DEPENDS
|
||||
"${_outfilename}.iconset"
|
||||
"${filename}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
list(APPEND iconset_icons
|
||||
"${_outfilename}.iconset/${type}_${sizename}.png")
|
||||
endmacro()
|
||||
foreach(size 16 32 128 256 512)
|
||||
math(EXPR double_size "2 * ${size}")
|
||||
foreach(file ${icons_at_${size}px})
|
||||
copy_icon("${file}" "${size}x${size}" "icon")
|
||||
endforeach()
|
||||
foreach(file ${icons_at_${double_size}px})
|
||||
copy_icon("${file}" "${size}x${size}@2x" "icon")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
foreach(size 16 18 32)
|
||||
math(EXPR double_size "2 * ${size}")
|
||||
foreach(file ${sidebar_icons_at_${size}px})
|
||||
copy_icon("${file}" "${size}x${size}" "sidebar")
|
||||
endforeach()
|
||||
foreach(file ${sidebar_icons_at_${double_size}px})
|
||||
copy_icon("${file}" "${size}x${size}@2x" "sidebar")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# generate .icns icon file
|
||||
add_custom_command(
|
||||
OUTPUT "${_outfilename}.icns"
|
||||
COMMAND ${ICONUTIL_EXECUTABLE}
|
||||
ARGS
|
||||
--convert icns
|
||||
--output "${_outfilename}.icns"
|
||||
"${_outfilename}.iconset"
|
||||
DEPENDS "${iconset_icons}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
# This will register the icon into the bundle
|
||||
set(MACOSX_BUNDLE_ICON_FILE "${_outfilebasename}.icns" PARENT_SCOPE)
|
||||
|
||||
# Append the icns file to the sources list so it will be a dependency to the
|
||||
# main target
|
||||
set(${appsources} "${${appsources}};${_outfilename}.icns" PARENT_SCOPE)
|
||||
|
||||
# Install the icon into the Resources dir in the bundle
|
||||
set_source_files_properties("${_outfilename}.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
else()
|
||||
message(STATUS "Unable to find the iconutil utility - application will not have an application icon!")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(_ecm_add_app_icon_categorize_icons icons type known_sizes)
|
||||
set(_${type}_known_sizes)
|
||||
foreach(size ${known_sizes})
|
||||
set(${type}_at_${size}px)
|
||||
list(APPEND _${type}_known_sizes ${size})
|
||||
endforeach()
|
||||
|
||||
|
||||
foreach(icon ${icons})
|
||||
get_filename_component(icon_full ${icon} ABSOLUTE)
|
||||
if (NOT EXISTS "${icon_full}")
|
||||
message(AUTHOR_WARNING "${icon_full} does not exist, ignoring")
|
||||
else()
|
||||
get_filename_component(icon_name ${icon} NAME)
|
||||
string(REGEX MATCH "([0-9]+)\\-[^/]+\\.([a-z]+)$"
|
||||
_dummy "${icon_name}")
|
||||
set(size "${CMAKE_MATCH_1}")
|
||||
set(ext "${CMAKE_MATCH_2}")
|
||||
|
||||
if (NOT (ext STREQUAL "svg" OR ext STREQUAL "svgz"))
|
||||
if (NOT size)
|
||||
message(AUTHOR_WARNING "${icon_full} is not named correctly for ecm_add_app_icon - ignoring")
|
||||
elseif (NOT ext STREQUAL "png")
|
||||
message(AUTHOR_WARNING "${icon_full} is not a png file - ignoring")
|
||||
else()
|
||||
list(FIND _${type}_known_sizes ${size} offset)
|
||||
|
||||
if (offset GREATER -1)
|
||||
list(APPEND ${type}_at_${size}px "${icon_full}")
|
||||
elseif()
|
||||
message(STATUS "not found ${type}_at_${size}px ${icon_full}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
297
cmake/modules/ECMFindModuleHelpers.cmake
Normal file
297
cmake/modules/ECMFindModuleHelpers.cmake
Normal file
@@ -0,0 +1,297 @@
|
||||
#.rst:
|
||||
# ECMFindModuleHelpers
|
||||
# --------------------
|
||||
#
|
||||
# Helper macros for find modules: ecm_find_package_version_check(),
|
||||
# ecm_find_package_parse_components() and
|
||||
# ecm_find_package_handle_library_components().
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_find_package_version_check(<name>)
|
||||
#
|
||||
# Prints warnings if the CMake version or the project's required CMake version
|
||||
# is older than that required by extra-cmake-modules.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_find_package_parse_components(<name>
|
||||
# RESULT_VAR <variable>
|
||||
# KNOWN_COMPONENTS <component1> [<component2> [...]]
|
||||
# [SKIP_DEPENDENCY_HANDLING])
|
||||
#
|
||||
# This macro will populate <variable> with a list of components found in
|
||||
# <name>_FIND_COMPONENTS, after checking that all those components are in the
|
||||
# list of KNOWN_COMPONENTS; if there are any unknown components, it will print
|
||||
# an error or warning (depending on the value of <name>_FIND_REQUIRED) and call
|
||||
# return().
|
||||
#
|
||||
# The order of components in <variable> is guaranteed to match the order they
|
||||
# are listed in the KNOWN_COMPONENTS argument.
|
||||
#
|
||||
# If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable
|
||||
# <name>_<component>_component_deps will be checked for dependent components.
|
||||
# If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)
|
||||
# dependencies will also be added to <variable>.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_find_package_handle_library_components(<name>
|
||||
# COMPONENTS <component> [<component> [...]]
|
||||
# [SKIP_DEPENDENCY_HANDLING])
|
||||
# [SKIP_PKG_CONFIG])
|
||||
#
|
||||
# Creates an imported library target for each component. The operation of this
|
||||
# macro depends on the presence of a number of CMake variables.
|
||||
#
|
||||
# The <name>_<component>_lib variable should contain the name of this library,
|
||||
# and <name>_<component>_header variable should contain the name of a header
|
||||
# file associated with it (whatever relative path is normally passed to
|
||||
# '#include'). <name>_<component>_header_subdir variable can be used to specify
|
||||
# which subdirectory of the include path the headers will be found in.
|
||||
# ecm_find_package_components() will then search for the library
|
||||
# and include directory (creating appropriate cache variables) and create an
|
||||
# imported library target named <name>::<component>.
|
||||
#
|
||||
# Additional variables can be used to provide additional information:
|
||||
#
|
||||
# If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and
|
||||
# pkg-config is found, the pkg-config module given by
|
||||
# <name>_<component>_pkg_config will be searched for and used to help locate the
|
||||
# library and header file. It will also be used to set
|
||||
# <name>_<component>_VERSION.
|
||||
#
|
||||
# Note that if version information is found via pkg-config,
|
||||
# <name>_<component>_FIND_VERSION can be set to require a particular version
|
||||
# for each component.
|
||||
#
|
||||
# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property
|
||||
# of the imported target for <component> will be set to contain the imported
|
||||
# targets for the components listed in <name>_<component>_component_deps.
|
||||
# <component>_FOUND will also be set to false if any of the compoments in
|
||||
# <name>_<component>_component_deps are not found. This requires the components
|
||||
# in <name>_<component>_component_deps to be listed before <component> in the
|
||||
# COMPONENTS argument.
|
||||
#
|
||||
# The following variables will be set:
|
||||
#
|
||||
# ``<name>_TARGETS``
|
||||
# the imported targets
|
||||
# ``<name>_LIBRARIES``
|
||||
# the found libraries
|
||||
# ``<name>_INCLUDE_DIRS``
|
||||
# the combined required include directories for the components
|
||||
# ``<name>_DEFINITIONS``
|
||||
# the "other" CFLAGS provided by pkg-config, if any
|
||||
# ``<name>_VERSION``
|
||||
# the value of ``<name>_<component>_VERSION`` for the first component that
|
||||
# has this variable set (note that components are searched for in the order
|
||||
# they are passed to the macro), although if it is already set, it will not
|
||||
# be altered
|
||||
#
|
||||
# Note that these variables are never cleared, so if
|
||||
# ecm_find_package_handle_library_components() is called multiple times with
|
||||
# different components (typically because of multiple find_package() calls) then
|
||||
# ``<name>_TARGETS``, for example, will contain all the targets found in any
|
||||
# call (although no duplicates).
|
||||
#
|
||||
# Since pre-1.0.0.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
macro(ecm_find_package_version_check module_name)
|
||||
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
||||
message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
|
||||
endif()
|
||||
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
|
||||
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(ecm_find_package_parse_components module_name)
|
||||
set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
|
||||
set(ecm_fppc_oneValueArgs RESULT_VAR)
|
||||
set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
|
||||
cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})
|
||||
|
||||
if(ECM_FPPC_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
if(NOT ECM_FPPC_RESULT_VAR)
|
||||
message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
|
||||
endif()
|
||||
if(NOT ECM_FPPC_KNOWN_COMPONENTS)
|
||||
message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
|
||||
endif()
|
||||
if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
|
||||
set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
|
||||
endif()
|
||||
|
||||
if(${module_name}_FIND_COMPONENTS)
|
||||
set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})
|
||||
|
||||
if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
|
||||
# Make sure deps are included
|
||||
foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
|
||||
foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
|
||||
list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
|
||||
if("${ecm_fppc_index}" STREQUAL "-1")
|
||||
if(NOT ${module_name}_FIND_QUIETLY)
|
||||
message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
|
||||
endif()
|
||||
list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
else()
|
||||
message(STATUS "Skipping dependency handling for ${module_name}")
|
||||
endif()
|
||||
list(REMOVE_DUPLICATES ecm_fppc_requestedComps)
|
||||
|
||||
# This makes sure components are listed in the same order as
|
||||
# KNOWN_COMPONENTS (potentially important for inter-dependencies)
|
||||
set(${ECM_FPPC_RESULT_VAR})
|
||||
foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
|
||||
list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
|
||||
if(NOT "${ecm_fppc_index}" STREQUAL "-1")
|
||||
list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
|
||||
list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
|
||||
endif()
|
||||
endforeach()
|
||||
# if there are any left, they are unknown components
|
||||
if(ecm_fppc_requestedComps)
|
||||
set(ecm_fppc_msgType STATUS)
|
||||
if(${module_name}_FIND_REQUIRED)
|
||||
set(ecm_fppc_msgType FATAL_ERROR)
|
||||
endif()
|
||||
if(NOT ${module_name}_FIND_QUIETLY)
|
||||
message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
else()
|
||||
set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(ecm_find_package_handle_library_components module_name)
|
||||
set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
|
||||
set(ecm_fpwc_oneValueArgs)
|
||||
set(ecm_fpwc_multiValueArgs COMPONENTS)
|
||||
cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})
|
||||
|
||||
if(ECM_FPWC_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
if(NOT ECM_FPWC_COMPONENTS)
|
||||
message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package(PkgConfig)
|
||||
foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
|
||||
set(ecm_fpwc_dep_vars)
|
||||
set(ecm_fpwc_dep_targets)
|
||||
if(NOT SKIP_DEPENDENCY_HANDLING)
|
||||
foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
|
||||
list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
|
||||
list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
|
||||
pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
|
||||
${${module_name}_${ecm_fpwc_comp}_pkg_config})
|
||||
endif()
|
||||
|
||||
find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
|
||||
NAMES ${${module_name}_${ecm_fpwc_comp}_header}
|
||||
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
|
||||
)
|
||||
find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
|
||||
NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
|
||||
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
|
||||
if(NOT ${module_name}_VERSION)
|
||||
set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
|
||||
FOUND_VAR
|
||||
${module_name}_${ecm_fpwc_comp}_FOUND
|
||||
REQUIRED_VARS
|
||||
${module_name}_${ecm_fpwc_comp}_LIBRARY
|
||||
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
|
||||
${ecm_fpwc_dep_vars}
|
||||
VERSION_VAR
|
||||
${module_name}_${ecm_fpwc_comp}_VERSION
|
||||
)
|
||||
|
||||
mark_as_advanced(
|
||||
${module_name}_${ecm_fpwc_comp}_LIBRARY
|
||||
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(${module_name}_${ecm_fpwc_comp}_FOUND)
|
||||
list(APPEND ${module_name}_LIBRARIES
|
||||
"${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
|
||||
list(APPEND ${module_name}_INCLUDE_DIRS
|
||||
"${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
|
||||
set(${module_name}_DEFINITIONS
|
||||
${${module_name}_DEFINITIONS}
|
||||
${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
|
||||
if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
|
||||
add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
|
||||
set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
|
||||
IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
|
||||
)
|
||||
endif()
|
||||
list(APPEND ${module_name}_TARGETS
|
||||
"${module_name}::${ecm_fpwc_comp}")
|
||||
endif()
|
||||
endforeach()
|
||||
if(${module_name}_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
|
||||
endif()
|
||||
if(${module_name}_INCLUDE_DIRS)
|
||||
list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
|
||||
endif()
|
||||
if(${module_name}_DEFINITIONS)
|
||||
list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
|
||||
endif()
|
||||
if(${module_name}_TARGETS)
|
||||
list(REMOVE_DUPLICATES ${module_name}_TARGETS)
|
||||
endif()
|
||||
endmacro()
|
||||
1
cmake/modules/ECMFindModuleHelpersStub.cmake
Normal file
1
cmake/modules/ECMFindModuleHelpersStub.cmake
Normal file
@@ -0,0 +1 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../modules/ECMFindModuleHelpers.cmake)
|
||||
27
cmake/modules/FindIcoTool.cmake
Normal file
27
cmake/modules/FindIcoTool.cmake
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright 2017 Vincent Pinon <vpinon@kde.org>
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)
|
||||
ecm_find_package_version_check(IcoTool)
|
||||
find_program(IcoTool_EXECUTABLE NAMES icotool)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(IcoTool
|
||||
FOUND_VAR
|
||||
IcoTool_FOUND
|
||||
REQUIRED_VARS
|
||||
IcoTool_EXECUTABLE
|
||||
)
|
||||
mark_as_advanced(IcoTool_EXECUTABLE)
|
||||
|
||||
if (IcoTool_FOUND)
|
||||
if (NOT TARGET IcoTool::IcoTool)
|
||||
add_executable(IcoTool::IcoTool IMPORTED)
|
||||
set_target_properties(IcoTool::IcoTool PROPERTIES
|
||||
IMPORTED_LOCATION "${IcoTool_EXECUTABLE}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(IcoTool PROPERTIES
|
||||
URL "http://www.nongnu.org/icoutils/"
|
||||
DESCRIPTION "Executable that converts a collection of PNG files into a Windows icon file"
|
||||
)
|
||||
@@ -1,82 +0,0 @@
|
||||
# - Try to find Iconv
|
||||
# Once done this will define
|
||||
#
|
||||
# ICONV_FOUND - system has Iconv
|
||||
# ICONV_INCLUDE_DIRS - the Iconv include directory
|
||||
# ICONV_LIBRARIES - Link these to use Iconv
|
||||
# ICONV_DEFINITIONS - Compiler switches required for using Iconv
|
||||
#
|
||||
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckPrototypeDefinition)
|
||||
|
||||
find_path(ICONV_INCLUDE_DIR
|
||||
NAMES
|
||||
iconv.h sys/iconv.h
|
||||
)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
|
||||
check_include_file(iconv.h HAVE_ICONV_H)
|
||||
check_include_file(sys/iconv.h HAVE_SYS_ICONV_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES)
|
||||
|
||||
find_library(ICONV_LIBRARY
|
||||
NAMES
|
||||
iconv
|
||||
libiconv
|
||||
PATHS
|
||||
)
|
||||
|
||||
if (ICONV_LIBRARY)
|
||||
get_filename_component(_ICONV_NAME ${ICONV_LIBRARY} NAME)
|
||||
get_filename_component(_ICONV_PATH ${ICONV_LIBRARY} PATH)
|
||||
check_library_exists(${_ICONV_NAME} iconv ${_ICONV_PATH} HAVE_ICONV)
|
||||
else()
|
||||
check_function_exists(iconv HAVE_ICONV)
|
||||
endif()
|
||||
|
||||
if (HAVE_ICONV_H OR HAVE_SYS_ICONV_H)
|
||||
if (HAVE_ICONV_H)
|
||||
set(_ICONV_PROTO_INCLUDE "iconv.h")
|
||||
endif (HAVE_ICONV_H)
|
||||
if (HAVE_SYS_ICONV_H)
|
||||
set(_ICONV_PROTO_INCLUDE "sys/iconv.h")
|
||||
endif (HAVE_SYS_ICONV_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
|
||||
check_prototype_definition(iconv
|
||||
"size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)"
|
||||
"-1"
|
||||
${_ICONV_PROTO_INCLUDE}
|
||||
HAVE_ICONV_CONST)
|
||||
set(CMAKE_REQUIRED_INCLUDES)
|
||||
endif (HAVE_ICONV_H OR HAVE_SYS_ICONV_H)
|
||||
|
||||
set(ICONV_INCLUDE_DIRS
|
||||
${ICONV_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (ICONV_LIBRARY)
|
||||
set(ICONV_LIBRARIES
|
||||
${ICONV_LIBRARIES}
|
||||
${ICONV_LIBRARY}
|
||||
)
|
||||
endif (ICONV_LIBRARY)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
if (ICONV_LIBRARIES)
|
||||
find_package_handle_standard_args(Iconv DEFAULT_MSG ICONV_LIBRARIES ICONV_INCLUDE_DIRS)
|
||||
else()
|
||||
find_package_handle_standard_args(Iconv DEFAULT_MSG ICONV_INCLUDE_DIRS)
|
||||
endif()
|
||||
|
||||
# show the ICONV_INCLUDE_DIRS and ICONV_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(ICONV_INCLUDE_DIRS ICONV_LIBRARIES)
|
||||
@@ -1,306 +0,0 @@
|
||||
# - Try to find the OpenSSL encryption library
|
||||
# Once done this will define
|
||||
#
|
||||
# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL
|
||||
#
|
||||
# Read-Only variables:
|
||||
# OPENSSL_FOUND - system has the OpenSSL library
|
||||
# OPENSSL_INCLUDE_DIR - the OpenSSL include directory
|
||||
# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL
|
||||
# OPENSSL_VERSION - This is set to $major.$minor.$revision$path (eg. 0.9.8s)
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2006-2009 Kitware, Inc.
|
||||
# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
|
||||
# Copyright 2009-2011 Mathieu Malaterre <mathieu.malaterre@gmail.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (UNIX)
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(_OPENSSL QUIET openssl)
|
||||
endif (UNIX)
|
||||
|
||||
# http://www.slproweb.com/products/Win32OpenSSL.html
|
||||
SET(_OPENSSL_ROOT_HINTS
|
||||
$ENV{OPENSSL_ROOT_DIR}
|
||||
${OPENSSL_ROOT_DIR}
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
|
||||
)
|
||||
SET(_OPENSSL_ROOT_PATHS
|
||||
"$ENV{PROGRAMFILES}/OpenSSL"
|
||||
"$ENV{PROGRAMFILES}/OpenSSL-Win32"
|
||||
"$ENV{PROGRAMFILES}/OpenSSL-Win64"
|
||||
"C:/OpenSSL/"
|
||||
"C:/OpenSSL-Win32/"
|
||||
"C:/OpenSSL-Win64/"
|
||||
)
|
||||
SET(_OPENSSL_ROOT_HINTS_AND_PATHS
|
||||
HINTS ${_OPENSSL_ROOT_HINTS}
|
||||
PATHS ${_OPENSSL_ROOT_PATHS}
|
||||
)
|
||||
|
||||
FIND_PATH(OPENSSL_INCLUDE_DIR
|
||||
NAMES
|
||||
openssl/ssl.h
|
||||
HINTS
|
||||
${_OPENSSL_INCLUDEDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
IF(WIN32 AND NOT CYGWIN)
|
||||
# MINGW should go here too
|
||||
IF(MSVC)
|
||||
# /MD and /MDd are the standard values - if someone wants to use
|
||||
# others, the libnames have to change here too
|
||||
# use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b
|
||||
# TODO: handle /MT and static lib
|
||||
# In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix:
|
||||
# * MD for dynamic-release
|
||||
# * MDd for dynamic-debug
|
||||
# * MT for static-release
|
||||
# * MTd for static-debug
|
||||
|
||||
# Implementation details:
|
||||
# We are using the libraries located in the VC subdir instead of the parent directory eventhough :
|
||||
# libeay32MD.lib is identical to ../libeay32.lib, and
|
||||
# ssleay32MD.lib is identical to ../ssleay32.lib
|
||||
FIND_LIBRARY(LIB_EAY_DEBUG
|
||||
NAMES
|
||||
libeay32MDd
|
||||
libeay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
FIND_LIBRARY(LIB_EAY_RELEASE
|
||||
NAMES
|
||||
libeay32MD
|
||||
libeay32
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
FIND_LIBRARY(SSL_EAY_DEBUG
|
||||
NAMES
|
||||
ssleay32MDd
|
||||
ssleay32
|
||||
ssl
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
FIND_LIBRARY(SSL_EAY_RELEASE
|
||||
NAMES
|
||||
ssleay32MD
|
||||
ssleay32
|
||||
ssl
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"VC"
|
||||
"lib/VC"
|
||||
)
|
||||
|
||||
if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
|
||||
set( OPENSSL_LIBRARIES
|
||||
optimized ${SSL_EAY_RELEASE} debug ${SSL_EAY_DEBUG}
|
||||
optimized ${LIB_EAY_RELEASE} debug ${LIB_EAY_DEBUG}
|
||||
)
|
||||
else()
|
||||
set( OPENSSL_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} )
|
||||
endif()
|
||||
MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE)
|
||||
MARK_AS_ADVANCED(LIB_EAY_DEBUG LIB_EAY_RELEASE)
|
||||
ELSEIF(MINGW)
|
||||
# same player, for MingW
|
||||
FIND_LIBRARY(LIB_EAY
|
||||
NAMES
|
||||
libeay32
|
||||
crypto
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib/MinGW"
|
||||
)
|
||||
|
||||
FIND_LIBRARY(SSL_EAY
|
||||
NAMES
|
||||
ssleay32
|
||||
ssl
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
"lib"
|
||||
"lib/MinGW"
|
||||
)
|
||||
|
||||
MARK_AS_ADVANCED(SSL_EAY LIB_EAY)
|
||||
set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
|
||||
ELSE(MSVC)
|
||||
# Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues:
|
||||
FIND_LIBRARY(LIB_EAY
|
||||
NAMES
|
||||
libeay32
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
FIND_LIBRARY(SSL_EAY
|
||||
NAMES
|
||||
ssleay32
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
MARK_AS_ADVANCED(SSL_EAY LIB_EAY)
|
||||
set( OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} )
|
||||
ENDIF(MSVC)
|
||||
ELSE(WIN32 AND NOT CYGWIN)
|
||||
|
||||
FIND_LIBRARY(OPENSSL_SSL_LIBRARY
|
||||
NAMES
|
||||
ssl
|
||||
ssleay32
|
||||
ssleay32MD
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARY
|
||||
NAMES
|
||||
crypto
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
|
||||
MARK_AS_ADVANCED(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY)
|
||||
|
||||
# compat defines
|
||||
SET(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY})
|
||||
SET(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
|
||||
SET(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
|
||||
|
||||
ENDIF(WIN32 AND NOT CYGWIN)
|
||||
|
||||
function(from_hex HEX DEC)
|
||||
string(TOUPPER "${HEX}" HEX)
|
||||
set(_res 0)
|
||||
string(LENGTH "${HEX}" _strlen)
|
||||
|
||||
while (_strlen GREATER 0)
|
||||
math(EXPR _res "${_res} * 16")
|
||||
string(SUBSTRING "${HEX}" 0 1 NIBBLE)
|
||||
string(SUBSTRING "${HEX}" 1 -1 HEX)
|
||||
if (NIBBLE STREQUAL "A")
|
||||
math(EXPR _res "${_res} + 10")
|
||||
elseif (NIBBLE STREQUAL "B")
|
||||
math(EXPR _res "${_res} + 11")
|
||||
elseif (NIBBLE STREQUAL "C")
|
||||
math(EXPR _res "${_res} + 12")
|
||||
elseif (NIBBLE STREQUAL "D")
|
||||
math(EXPR _res "${_res} + 13")
|
||||
elseif (NIBBLE STREQUAL "E")
|
||||
math(EXPR _res "${_res} + 14")
|
||||
elseif (NIBBLE STREQUAL "F")
|
||||
math(EXPR _res "${_res} + 15")
|
||||
else()
|
||||
math(EXPR _res "${_res} + ${NIBBLE}")
|
||||
endif()
|
||||
|
||||
string(LENGTH "${HEX}" _strlen)
|
||||
endwhile()
|
||||
|
||||
set(${DEC} ${_res} PARENT_SCOPE)
|
||||
endfunction(from_hex)
|
||||
|
||||
if (OPENSSL_INCLUDE_DIR)
|
||||
if (_OPENSSL_VERSION)
|
||||
set(OPENSSL_VERSION "${_OPENSSL_VERSION}")
|
||||
elseif(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
|
||||
REGEX "^#define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
|
||||
|
||||
# The version number is encoded as 0xMNNFFPPS: major minor fix patch status
|
||||
# The status gives if this is a developer or prerelease and is ignored here.
|
||||
# Major, minor, and fix directly translate into the version numbers shown in
|
||||
# the string. The patch field translates to the single character suffix that
|
||||
# indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so
|
||||
# on.
|
||||
|
||||
string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$"
|
||||
"\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}")
|
||||
list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR)
|
||||
list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR)
|
||||
from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR)
|
||||
list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX)
|
||||
from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX)
|
||||
list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH)
|
||||
|
||||
if (NOT OPENSSL_VERSION_PATCH STREQUAL "00")
|
||||
from_hex("${OPENSSL_VERSION_PATCH}" _tmp)
|
||||
# 96 is the ASCII code of 'a' minus 1
|
||||
math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96")
|
||||
unset(_tmp)
|
||||
# Once anyone knows how OpenSSL would call the patch versions beyond 'z'
|
||||
# this should be updated to handle that, too. This has not happened yet
|
||||
# so it is simply ignored here for now.
|
||||
string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING)
|
||||
endif (NOT OPENSSL_VERSION_PATCH STREQUAL "00")
|
||||
|
||||
set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
|
||||
endif (_OPENSSL_VERSION)
|
||||
endif (OPENSSL_INCLUDE_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if (OPENSSL_VERSION)
|
||||
find_package_handle_standard_args(OpenSSL
|
||||
REQUIRED_VARS
|
||||
OPENSSL_LIBRARIES
|
||||
OPENSSL_INCLUDE_DIR
|
||||
VERSION_VAR
|
||||
OPENSSL_VERSION
|
||||
FAIL_MESSAGE
|
||||
"Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
|
||||
)
|
||||
else (OPENSSL_VERSION)
|
||||
find_package_handle_standard_args(OpenSSL "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
|
||||
OPENSSL_LIBRARIES
|
||||
OPENSSL_INCLUDE_DIR
|
||||
)
|
||||
endif (OPENSSL_VERSION)
|
||||
|
||||
MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
|
||||
117
cmake/modules/FindPng2Ico.cmake
Normal file
117
cmake/modules/FindPng2Ico.cmake
Normal file
@@ -0,0 +1,117 @@
|
||||
#.rst:
|
||||
# FindPng2Ico
|
||||
# -----------
|
||||
#
|
||||
# Try to find png2ico.
|
||||
#
|
||||
# If the png2ico executable is not in your PATH, you can provide
|
||||
# an alternative name or full path location with the ``Png2Ico_EXECUTABLE``
|
||||
# variable.
|
||||
#
|
||||
# This will define the following variables:
|
||||
#
|
||||
# ``Png2Ico_FOUND``
|
||||
# True if png2ico is available.
|
||||
#
|
||||
# ``Png2Ico_EXECUTABLE``
|
||||
# The png2ico executable.
|
||||
#
|
||||
# If ``Png2Ico_FOUND`` is TRUE, it will also define the following imported
|
||||
# target:
|
||||
#
|
||||
# ``Png2Ico::Png2Ico``
|
||||
# The png2ico executable.
|
||||
#
|
||||
# and the following variables:
|
||||
#
|
||||
# ``Png2Ico_HAS_COLORS_ARGUMENT``
|
||||
# Whether png2ico accepts a ``--colors`` argument. `Matthias Benkmann's
|
||||
# tool <http://www.winterdrache.de/freeware/png2ico/>`_ does, while the
|
||||
# version of png2ico from the `"KDE On Windows" (kdewin)
|
||||
# <https://projects.kde.org/projects/kdesupport/kdewin>`_ project does not.
|
||||
#
|
||||
# ``Png2Ico_HAS_RCFILE_ARGUMENT``
|
||||
# Whether png2ico accepts an ``--rcfile`` argument. The version of png2ico
|
||||
# from the `"KDE On Windows" (kdewin)
|
||||
# <https://projects.kde.org/projects/kdesupport/kdewin>`_ project does,
|
||||
# while `Matthias Benkmann's tool
|
||||
# <http://www.winterdrache.de/freeware/png2ico/>`_ does not.
|
||||
#
|
||||
# Since 1.7.0.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#=============================================================================
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)
|
||||
|
||||
ecm_find_package_version_check(Png2Ico)
|
||||
|
||||
# Find png2ico
|
||||
find_program(Png2Ico_EXECUTABLE NAMES png2ico)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Png2Ico
|
||||
FOUND_VAR
|
||||
Png2Ico_FOUND
|
||||
REQUIRED_VARS
|
||||
Png2Ico_EXECUTABLE
|
||||
)
|
||||
|
||||
mark_as_advanced(Png2Ico_EXECUTABLE)
|
||||
|
||||
if (Png2Ico_FOUND)
|
||||
execute_process(
|
||||
COMMAND "${Png2Ico_EXECUTABLE}" --help
|
||||
OUTPUT_VARIABLE _png2ico_help_text
|
||||
ERROR_VARIABLE _png2ico_help_text
|
||||
)
|
||||
if (_png2ico_help_text MATCHES ".*--rcfile .*")
|
||||
set(Png2Ico_HAS_RCFILE_ARGUMENT TRUE)
|
||||
else()
|
||||
set(Png2Ico_HAS_RCFILE_ARGUMENT FALSE)
|
||||
endif()
|
||||
if (_png2ico_help_text MATCHES ".*--colors .*")
|
||||
set(Png2Ico_HAS_COLORS_ARGUMENT TRUE)
|
||||
else()
|
||||
set(Png2Ico_HAS_COLORS_ARGUMENT FALSE)
|
||||
endif()
|
||||
unset(_png2ico_help_text)
|
||||
|
||||
if (NOT TARGET Png2Ico::Png2Ico)
|
||||
add_executable(Png2Ico::Png2Ico IMPORTED)
|
||||
set_target_properties(Png2Ico::Png2Ico PROPERTIES
|
||||
IMPORTED_LOCATION "${Png2Ico_EXECUTABLE}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(Png2Ico PROPERTIES
|
||||
URL "http://www.winterdrache.de/freeware/png2ico/ or https://projects.kde.org/projects/kdesupport/kdewin"
|
||||
DESCRIPTION "Executable that converts a collection of PNG files into a Windows icon file"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>@APPLICATION_EXECUTABLE@</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>ownCloud.icns</string>
|
||||
<string>@APPLICATION_EXECUTABLE@.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>@APPLICATION_REV_DOMAIN@</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
@@ -27,12 +27,47 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@MIRALL_VERSION_STRING@</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>(C) 2014-2016 @APPLICATION_VENDOR@</string>
|
||||
<string>(C) 2014-2018 @APPLICATION_VENDOR@</string>
|
||||
<key>SUShowReleaseNotes</key>
|
||||
<false/>
|
||||
<key>LSMinimumBundleVersion</key>
|
||||
<string>10.7.0</string>
|
||||
<key>SUPublicDSAKeyFile</key>
|
||||
<string>dsa_pub.pem</string>
|
||||
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>@APPLICATION_REV_DOMAIN@.VIRTUALFILE</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<string>@APPLICATION_VIRTUALFILE_SUFFIX@</string>
|
||||
<key>public.mime-type</key>
|
||||
<string>application/octet-stream</string>
|
||||
</dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>@APPLICATION_EXECUTABLE@ Download Virtual File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Owner</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>@APPLICATION_REV_DOMAIN@.VIRTUALFILE</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# - MACRO_ADD_PLUGIN(name [WITH_PREFIX] file1 .. fileN)
|
||||
#
|
||||
# Create a plugin from the given source files.
|
||||
# If WITH_PREFIX is given, the resulting plugin will have the
|
||||
# prefix "lib", otherwise it won't.
|
||||
#
|
||||
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
|
||||
# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <asn@cryptomilk.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
macro (MACRO_ADD_PLUGIN _target_NAME _with_PREFIX)
|
||||
|
||||
if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
set(_first_SRC)
|
||||
else (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
set(_first_SRC ${_with_PREFIX})
|
||||
endif (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
|
||||
add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
|
||||
|
||||
if (_first_SRC)
|
||||
set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
|
||||
endif (_first_SRC)
|
||||
|
||||
endmacro (MACRO_ADD_PLUGIN _name _sources)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
# (c) 2014 Copyright ownCloud GmbH
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# - macro_copy_file(_src _dst)
|
||||
# Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst}
|
||||
#
|
||||
# Example:
|
||||
# macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/.)
|
||||
# Copies file icon.png to ${CMAKE_CURRENT_BINARY_DIR} directory
|
||||
#
|
||||
# Copyright (c) 2006-2007 Wengo
|
||||
# Copyright (c) 2006-2008 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING file.
|
||||
|
||||
|
||||
macro (macro_copy_file _src _dst)
|
||||
# Removes all path containing .svn or CVS or CMakeLists.txt during the copy
|
||||
if (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
|
||||
|
||||
if (CMAKE_VERBOSE_MAKEFILE)
|
||||
message(STATUS "Copy file from ${_src} to ${_dst}")
|
||||
endif (CMAKE_VERBOSE_MAKEFILE)
|
||||
|
||||
# Creates directory if necessary
|
||||
get_filename_component(_path ${_dst} PATH)
|
||||
file(MAKE_DIRECTORY ${_path})
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy_if_different ${_src} ${_dst}
|
||||
OUTPUT_QUIET
|
||||
)
|
||||
endif (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
|
||||
endmacro (macro_copy_file)
|
||||
@@ -7,6 +7,8 @@
|
||||
!define APPLICATION_CMD_EXECUTABLE "@APPLICATION_EXECUTABLE@cmd.exe"
|
||||
!define APPLICATION_DOMAIN "@APPLICATION_DOMAIN@"
|
||||
!define APPLICATION_LICENSE "@APPLICATION_LICENSE@"
|
||||
!define APPLICATION_VIRTUALFILE_SUFFIX "@APPLICATION_VIRTUALFILE_SUFFIX@"
|
||||
!define APPLICATION_VIRTUALFILE_FILECLASS "@APPLICATION_EXECUTABLE@.@APPLICATION_VIRTUALFILE_SUFFIX@"
|
||||
!define WIN_SETUP_BITMAP_PATH "@WIN_SETUP_BITMAP_PATH@"
|
||||
|
||||
!define CRASHREPORTER_EXECUTABLE "@CRASHREPORTER_EXECUTABLE@"
|
||||
@@ -100,6 +102,8 @@ ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
|
||||
!include Library.nsh ;Used by the COM registration for shell extensions
|
||||
!include x64.nsh ;Used to determine the right arch for the shell extensions
|
||||
|
||||
!include ${source_path}/admin/win/nsi/lib/fileassoc.nsh
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Memento selections stored in registry.
|
||||
;-----------------------------------------------------------------------------
|
||||
@@ -461,10 +465,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libgcc_s_sjlj-1.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwinpthread-1.dll"
|
||||
File "${MING_BIN}\libssp-0.dll"
|
||||
|
||||
;CSync configs
|
||||
File "${SOURCE_PATH}/sync-exclude.lst"
|
||||
|
||||
;Add file association
|
||||
!insertmacro APP_ASSOCIATE "${APPLICATION_VIRTUALFILE_SUFFIX}" "${APPLICATION_VIRTUALFILE_FILECLASS}" "Virtual File for Remote File" "$INSTDIR\${APPLICATION_EXECUTABLE},0" "Download" "$INSTDIR\${APPLICATION_EXECUTABLE} $\"%1$\""
|
||||
|
||||
SectionEnd
|
||||
|
||||
!ifdef OPTION_SECTION_SC_SHELL_EXT
|
||||
@@ -603,6 +611,35 @@ Section Uninstall
|
||||
Abort $UNINSTALL_ABORT
|
||||
owncloud_installed:
|
||||
|
||||
; Delete Navigation Pane entries added for Windows 10.
|
||||
; On 64bit Windows, the client will be writing to the 64bit registry.
|
||||
${If} ${RunningX64}
|
||||
SetRegView 64
|
||||
${EndIf}
|
||||
StrCpy $0 0
|
||||
loop:
|
||||
; Look at every registered explorer namespace for HKCU and check if it was added by our application
|
||||
; (we write to a custom "ApplicationName" value there).
|
||||
EnumRegKey $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace" $0
|
||||
StrCmp $1 "" done
|
||||
|
||||
ReadRegStr $R0 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\$1" "ApplicationName"
|
||||
StrCmp $R0 "${APPLICATION_NAME}" deleteClsid
|
||||
; Increment the index when not deleting the enumerated key.
|
||||
IntOp $0 $0 + 1
|
||||
goto loop
|
||||
|
||||
deleteClsid:
|
||||
DetailPrint "Removing Navigation Pane CLSID $1"
|
||||
; Should match FolderMan::updateCloudStorageRegistry
|
||||
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\$1"
|
||||
DeleteRegKey HKCU "Software\Classes\CLSID\$1"
|
||||
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" $1
|
||||
goto loop
|
||||
done:
|
||||
; Go back to the 32bit registry.
|
||||
SetRegView lastused
|
||||
|
||||
;Delete registry keys.
|
||||
DeleteRegValue HKLM "Software\${APPLICATION_VENDOR}\${APPLICATION_NAME}" "VersionBuild"
|
||||
DeleteRegValue HKLM "Software\${APPLICATION_VENDOR}\${APPLICATION_NAME}" "VersionMajor"
|
||||
@@ -613,6 +650,9 @@ Section Uninstall
|
||||
|
||||
DeleteRegKey HKCR "${APPLICATION_NAME}"
|
||||
|
||||
;Remove file association
|
||||
!insertmacro APP_UNASSOCIATE "${APPLICATION_VIRTUALFILE_SUFFIX}" "${APPLICATION_VIRTUALFILE_FILECLASS}"
|
||||
|
||||
;Shell extension
|
||||
!ifdef OPTION_SECTION_SC_SHELL_EXT
|
||||
!define LIBRARY_COM
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
# (c) 2014 Copyright ownCloud GmbH
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
include (MacroOptionalFindPackage)
|
||||
include (MacroLogFeature)
|
||||
|
||||
option(BUILD_WITH_QT4 "Build with Qt4 no matter if Qt5 was found" OFF)
|
||||
|
||||
if( BUILD_WITH_QT4 )
|
||||
message(STATUS "Search for Qt5 was disabled by option BUILD_WITH_QT4")
|
||||
else( BUILD_WITH_QT4 )
|
||||
find_package(Qt5Core QUIET)
|
||||
endif( BUILD_WITH_QT4 )
|
||||
|
||||
if( Qt5Core_FOUND )
|
||||
message(STATUS "Found Qt5 core, checking for further dependencies...")
|
||||
find_package(Qt5Network REQUIRED)
|
||||
find_package(Qt5Xml REQUIRED)
|
||||
find_package(Qt5Concurrent REQUIRED)
|
||||
if(UNIT_TESTING)
|
||||
find_package(Qt5Test REQUIRED)
|
||||
endif()
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
if(APPLE)
|
||||
find_package(Qt5MacExtras REQUIRED)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT NO_SHIBBOLETH)
|
||||
find_package(Qt5WebKitWidgets)
|
||||
find_package(Qt5WebKit)
|
||||
if(NOT Qt5WebKitWidgets_FOUND)
|
||||
message(FATAL_ERROR "Qt5WebKit required for Shibboleth. Use -DNO_SHIBBOLETH=1 to disable it.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else( Qt5Core_FOUND )
|
||||
if(WIN32 OR APPLE)
|
||||
if (NOT BUILD_WITH_QT4)
|
||||
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
|
||||
endif ()
|
||||
endif(WIN32 OR APPLE)
|
||||
endif( Qt5Core_FOUND )
|
||||
|
||||
|
||||
if( Qt5Core_FOUND )
|
||||
message(STATUS "Using Qt 5!")
|
||||
|
||||
# We need this to find the paths to qdbusxml2cpp and co
|
||||
if (WITH_DBUS)
|
||||
find_package(Qt5DBus REQUIRED)
|
||||
include_directories(${Qt5DBus_INCLUDES})
|
||||
add_definitions(${Qt5DBus_DEFINITIONS})
|
||||
endif (WITH_DBUS)
|
||||
include_directories(${Qt5Core_INCLUDES})
|
||||
add_definitions(${Qt5Core_DEFINITIONS})
|
||||
if (NOT WIN32) #implied on Win32
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
endif(NOT WIN32)
|
||||
# set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
|
||||
|
||||
if(APPLE AND NOT TOKEN_AUTH_ONLY)
|
||||
include_directories(${Qt5MacExtras_INCLUDE_DIRS})
|
||||
add_definitions(${Qt5MacExtras_DEFINITIONS})
|
||||
set (QT_LIBRARIES ${QT_LIBRARIES} ${Qt5MacExtras_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_LIBRARIES_ONLY)
|
||||
macro(qt_wrap_ui)
|
||||
qt5_wrap_ui(${ARGN})
|
||||
endmacro()
|
||||
else()
|
||||
# hack
|
||||
SET(QT_UIC_EXECUTABLE "")
|
||||
endif()
|
||||
|
||||
macro(qt_add_resources)
|
||||
qt5_add_resources(${ARGN})
|
||||
endmacro()
|
||||
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
find_package(Qt5LinguistTools)
|
||||
if(Qt5LinguistTools_FOUND)
|
||||
macro(qt_add_translation)
|
||||
qt5_add_translation(${ARGN})
|
||||
endmacro()
|
||||
else()
|
||||
macro(qt_add_translation)
|
||||
endmacro()
|
||||
endif()
|
||||
else()
|
||||
macro(qt_add_translation)
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
macro(qt_add_dbus_interface)
|
||||
qt5_add_dbus_interface(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_add_dbus_adaptor)
|
||||
qt5_add_dbus_adaptor(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_wrap_cpp)
|
||||
qt5_wrap_cpp(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(install_qt_executable)
|
||||
install_qt5_executable(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(setup_qt)
|
||||
endmacro()
|
||||
|
||||
set(QT_RCC_EXECUTABLE "${Qt5Core_RCC_EXECUTABLE}")
|
||||
|
||||
#Enable deprecated symbols
|
||||
add_definitions("-DQT_DISABLE_DEPRECATED_BEFORE=0")
|
||||
|
||||
add_definitions("-DQT_USE_QSTRINGBUILDER") #optimize string concatenation
|
||||
add_definitions("-DQT_MESSAGELOGCONTEXT") #enable function name and line number in debug output
|
||||
endif( Qt5Core_FOUND )
|
||||
|
||||
if(NOT Qt5Core_FOUND)
|
||||
message(STATUS "Could not find Qt5, searching for Qt4 instead...")
|
||||
|
||||
set(NEEDED_QT4_COMPONENTS "QtCore" "QtXml" "QtNetwork" "QtGui" "QtWebkit")
|
||||
if( BUILD_TESTS )
|
||||
list(APPEND NEEDED_QT4_COMPONENTS "QtTest")
|
||||
endif()
|
||||
|
||||
find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS} )
|
||||
macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://www.qt-project.org" TRUE "" "If you see this, although libqt4-devel is installed, check whether the \n qtwebkit-devel package and whatever contains QtUiTools is installed too")
|
||||
|
||||
macro(qt5_use_modules)
|
||||
endmacro()
|
||||
|
||||
macro(qt_wrap_ui)
|
||||
qt4_wrap_ui(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_add_resources)
|
||||
qt4_add_resources(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_add_translation)
|
||||
qt4_add_translation(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_add_dbus_interface)
|
||||
qt4_add_dbus_interface(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_add_dbus_adaptor)
|
||||
qt4_add_dbus_adaptor(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(qt_wrap_cpp)
|
||||
qt4_wrap_cpp(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(install_qt_executable)
|
||||
install_qt4_executable(${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(setup_qt)
|
||||
set(QT_USE_QTGUI TRUE)
|
||||
set(QT_USE_QTSQL TRUE)
|
||||
set(QT_USE_QTNETWORK TRUE)
|
||||
set(QT_USE_QTXML TRUE)
|
||||
set(QT_USE_QTWEBKIT TRUE)
|
||||
set(QT_USE_QTDBUS TRUE)
|
||||
|
||||
include( ${QT_USE_FILE} )
|
||||
endmacro()
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION)
|
||||
if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)
|
||||
add_definitions("-DQ_DECL_OVERRIDE=override")
|
||||
else()
|
||||
add_definitions("-DQ_DECL_OVERRIDE=")
|
||||
endif()
|
||||
else() #clang or others
|
||||
add_definitions("-DQ_DECL_OVERRIDE=override")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if( Qt5Core_DIR )
|
||||
set( HAVE_QT5 TRUE )
|
||||
else( Qt5Core_DIR )
|
||||
set( HAVE_QT5 FALSE )
|
||||
endif( Qt5Core_DIR )
|
||||
@@ -1,58 +0,0 @@
|
||||
# - macro_asciidoc2man(inputfile outputfile)
|
||||
#
|
||||
# Create a manpage with asciidoc.
|
||||
# Example: macro_asciidoc2man(foo.txt foo.1)
|
||||
#
|
||||
# Copyright (c) 2006, Andreas Schneider, <asn@cryptomilk.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
include(MacroCopyFile)
|
||||
|
||||
macro(MACRO_ASCIIDOC2MAN _a2m_input _a2m_output)
|
||||
find_program(A2X
|
||||
NAMES
|
||||
a2x
|
||||
)
|
||||
#message("+++ A2X: ${A2X}")
|
||||
|
||||
if (A2X)
|
||||
|
||||
#message("+++ ${A2X} --doctype=manpage --format=manpage --destination-dir=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${_a2m_input}")
|
||||
macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_a2m_input} ${CMAKE_CURRENT_BINARY_DIR}/${_a2m_input})
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${A2X} --doctype=manpage --format=manpage ${_a2m_input}
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
RESULT_VARIABLE
|
||||
A2M_MAN_GENERATED
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
#message("+++ A2M_MAN_GENERATED: ${A2M_MAN_GENERATED}")
|
||||
if (A2M_MAN_GENERATED EQUAL 0)
|
||||
find_file(A2M_MAN_FILE
|
||||
NAME
|
||||
${_a2m_output}
|
||||
PATHS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
if (A2M_MAN_FILE)
|
||||
get_filename_component(A2M_MAN_CATEGORY ${A2M_MAN_FILE} EXT)
|
||||
string(SUBSTRING ${A2M_MAN_CATEGORY} 1 1 A2M_MAN_CATEGORY)
|
||||
install(
|
||||
FILES
|
||||
${A2M_MAN_FILE}
|
||||
DESTINATION
|
||||
${MAN_INSTALL_DIR}/man${A2M_MAN_CATEGORY}
|
||||
)
|
||||
endif (A2M_MAN_FILE)
|
||||
endif (A2M_MAN_GENERATED EQUAL 0)
|
||||
|
||||
endif (A2X)
|
||||
endmacro(MACRO_ASCIIDOC2MAN _a2m_input _a2m_file)
|
||||
@@ -3,10 +3,15 @@
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
|
||||
|
||||
# Fix sqlite compilation on macOS
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
# Fix sqlite compilation on MinGW
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-discarded-qualifiers")
|
||||
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION)
|
||||
if(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
#cmakedefine APPLICATION_SHORTNAME "@APPLICATION_SHORTNAME@"
|
||||
#cmakedefine APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@"
|
||||
#cmakedefine APPLICATION_UPDATE_URL "@APPLICATION_UPDATE_URL@"
|
||||
#cmakedefine APPLICATION_ICON_NAME "@APPLICATION_ICON_NAME@"
|
||||
#cmakedefine APPLICATION_VIRTUALFILE_SUFFIX "@APPLICATION_VIRTUALFILE_SUFFIX@"
|
||||
#define APPLICATION_DOTVIRTUALFILE_SUFFIX "." APPLICATION_VIRTUALFILE_SUFFIX
|
||||
|
||||
#cmakedefine ZLIB_FOUND @ZLIB_FOUND@
|
||||
|
||||
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
||||
#cmakedefine SHAREDIR "@SHAREDIR@"
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
|
||||
|
||||
# global needed variables
|
||||
set(APPLICATION_NAME "ocsync")
|
||||
|
||||
set(LIBRARY_VERSION ${MIRALL_VERSION})
|
||||
set(LIBRARY_SOVERSION "0")
|
||||
|
||||
# add definitions
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefinePlatformDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
include(DefineOptions.cmake)
|
||||
|
||||
include(DefineInstallationPaths)
|
||||
|
||||
# add macros
|
||||
include(MacroAddPlugin)
|
||||
include(MacroCopyFile)
|
||||
|
||||
if (NOT WIN32)
|
||||
find_package(Iconv)
|
||||
endif (NOT WIN32)
|
||||
|
||||
find_package(SQLite3 3.8.0 REQUIRED)
|
||||
|
||||
include(ConfigureChecks.cmake)
|
||||
|
||||
|
||||
set(SOURCE_DIR ${CMAKE_SOURCE_DIR})
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake)
|
||||
|
||||
if (MEM_NULL_TESTS)
|
||||
add_definitions(-DCSYNC_MEM_NULL_TESTS)
|
||||
endif (MEM_NULL_TESTS)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_TESTING ON)
|
||||
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
include(AddCMockaTest)
|
||||
add_subdirectory(tests)
|
||||
endif (CMOCKA_FOUND)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h)
|
||||
configure_file(config_test.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_test.h)
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
set(UPDATE_TYPE "true")
|
||||
|
||||
set(MEMORYCHECK_SUPPRESSIONS_FILE ${CMAKE_SOURCE_DIR}/tests/valgrind-csync.supp)
|
||||
|
||||
set(CTEST_PROJECT_NAME "csync")
|
||||
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
|
||||
|
||||
set(CTEST_DROP_METHOD "http")
|
||||
set(CTEST_DROP_SITE "mock.cryptomilk.org")
|
||||
set(CTEST_DROP_LOCATION "/submit.php?project=${CTEST_PROJECT_NAME}")
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
set(CTEST_CUSTOM_MEMCHECK_IGNORE
|
||||
${CTEST_CUSTOM_MEMCHECK_IGNORE}
|
||||
check_std_c_jhash
|
||||
)
|
||||
@@ -1,7 +0,0 @@
|
||||
|
||||
/* mind to have trailing slashes! */
|
||||
|
||||
#define TESTFILES_DIR "@SOURCE_DIR@/csync/tests/ownCloud/testfiles/"
|
||||
|
||||
#define TEST_CONFIG_DIR "@SOURCE_DIR@/csync/tests/ownCloud/"
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
project(libcsync)
|
||||
|
||||
add_subdirectory(std)
|
||||
|
||||
# Statically include sqlite
|
||||
|
||||
set(CSYNC_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
CACHE INTERNAL "csync public include directories"
|
||||
)
|
||||
|
||||
set(CSYNC_PRIVATE_INCLUDE_DIRS
|
||||
${SQLITE3_INCLUDE_DIRS}
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(CSYNC_LIBRARY
|
||||
ocsync
|
||||
CACHE INTERNAL "ocsync library"
|
||||
)
|
||||
|
||||
set(CSYNC_LINK_LIBRARIES
|
||||
${CSTDLIB_LIBRARY}
|
||||
${CSYNC_REQUIRED_LIBRARIES}
|
||||
${SQLITE3_LIBRARIES}
|
||||
)
|
||||
|
||||
if(HAVE_ICONV AND WITH_ICONV)
|
||||
list(APPEND CSYNC_PRIVATE_INCLUDE_DIRS ${ICONV_INCLUDE_DIR})
|
||||
list(APPEND CSYNC_LINK_LIBRARIES ${ICONV_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# Specific option for builds tied to servers that do not support renaming extensions
|
||||
set(NO_RENAME_EXTENSION 0 CACHE BOOL "Do not issue rename if the extension changes")
|
||||
if(NO_RENAME_EXTENSION)
|
||||
add_definitions(-DNO_RENAME_EXTENSION)
|
||||
endif()
|
||||
|
||||
set(csync_SRCS
|
||||
csync.c
|
||||
csync_exclude.c
|
||||
csync_log.c
|
||||
csync_statedb.c
|
||||
csync_time.c
|
||||
csync_util.c
|
||||
csync_misc.c
|
||||
|
||||
csync_update.c
|
||||
csync_reconcile.c
|
||||
|
||||
csync_rename.cc
|
||||
|
||||
vio/csync_vio.c
|
||||
vio/csync_vio_file_stat.c
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND csync_SRCS
|
||||
vio/csync_vio_local_win.c
|
||||
)
|
||||
else()
|
||||
list(APPEND csync_SRCS
|
||||
vio/csync_vio_local_unix.c
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h)
|
||||
|
||||
set(csync_HDRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/csync_version.h
|
||||
csync.h
|
||||
vio/csync_vio.h
|
||||
vio/csync_vio_method.h
|
||||
vio/csync_vio_module.h
|
||||
)
|
||||
|
||||
# Statically include sqlite
|
||||
if (USE_OUR_OWN_SQLITE3)
|
||||
list(APPEND csync_SRCS ${SQLITE3_SOURCE})
|
||||
if (WIN32)
|
||||
# We want to export sqlite symbols from the ocsync DLL without
|
||||
# having to patch both sqlite3.h and the amalgation sqlite3.c,
|
||||
# so do the import/export magic manually through the build system.
|
||||
remove_definitions(-DSQLITE_API=__declspec\(dllimport\))
|
||||
add_definitions(-DSQLITE_API=__declspec\(dllexport\))
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
${CSYNC_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
|
||||
#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
|
||||
|
||||
generate_export_header( ${CSYNC_LIBRARY}
|
||||
BASE_NAME ${CSYNC_LIBRARY}
|
||||
EXPORT_MACRO_NAME OCSYNC_EXPORT
|
||||
EXPORT_FILE_NAME ocsynclib.h
|
||||
)
|
||||
|
||||
target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES})
|
||||
#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${CSYNC_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
RUNTIME_OUTPUT_DIRECTORY
|
||||
${BIN_OUTPUT_DIRECTORY}
|
||||
)
|
||||
if(BUILD_OWNCLOUD_OSX_BUNDLE)
|
||||
INSTALL(
|
||||
TARGETS
|
||||
${CSYNC_LIBRARY}
|
||||
LIBRARY DESTINATION
|
||||
${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION
|
||||
${LIB_INSTALL_DIR}
|
||||
RUNTIME DESTINATION
|
||||
${BIN_INSTALL_DIR}
|
||||
)
|
||||
else()
|
||||
INSTALL(
|
||||
TARGETS
|
||||
${CSYNC_LIBRARY}
|
||||
LIBRARY DESTINATION
|
||||
${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
|
||||
ARCHIVE DESTINATION
|
||||
${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
|
||||
RUNTIME DESTINATION
|
||||
${BIN_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,676 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_ICONV_H
|
||||
#include <sys/iconv.h>
|
||||
#endif
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
#include "csync_exclude.h"
|
||||
#include "csync_statedb.h"
|
||||
#include "csync_time.h"
|
||||
#include "csync_util.h"
|
||||
#include "csync_misc.h"
|
||||
#include "std/c_private.h"
|
||||
|
||||
#include "csync_update.h"
|
||||
#include "csync_reconcile.h"
|
||||
|
||||
#include "vio/csync_vio.h"
|
||||
|
||||
#include "csync_log.h"
|
||||
#include "csync_rename.h"
|
||||
#include "c_jhash.h"
|
||||
|
||||
static int _key_cmp(const void *key, const void *data) {
|
||||
uint64_t a;
|
||||
csync_file_stat_t *b;
|
||||
|
||||
a = *(uint64_t *) (key);
|
||||
b = (csync_file_stat_t *) data;
|
||||
|
||||
if (a < b->phash) {
|
||||
return -1;
|
||||
} else if (a > b->phash) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _data_cmp(const void *key, const void *data) {
|
||||
csync_file_stat_t *a, *b;
|
||||
|
||||
a = (csync_file_stat_t *) key;
|
||||
b = (csync_file_stat_t *) data;
|
||||
|
||||
if (a->phash < b->phash) {
|
||||
return -1;
|
||||
} else if (a->phash > b->phash) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void csync_create(CSYNC **csync, const char *local) {
|
||||
CSYNC *ctx;
|
||||
size_t len = 0;
|
||||
|
||||
ctx = c_malloc(sizeof(CSYNC));
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
/* remove trailing slashes */
|
||||
len = strlen(local);
|
||||
while(len > 0 && local[len - 1] == '/') --len;
|
||||
|
||||
ctx->local.uri = c_strndup(local, len);
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
ctx->current_fs = NULL;
|
||||
|
||||
ctx->abort = false;
|
||||
|
||||
ctx->ignore_hidden_files = true;
|
||||
|
||||
*csync = ctx;
|
||||
}
|
||||
|
||||
void csync_init(CSYNC *ctx, const char *db_file) {
|
||||
assert(ctx);
|
||||
/* Do not initialize twice */
|
||||
|
||||
assert(!(ctx->status & CSYNC_STATUS_INIT));
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
ctx->local.type = LOCAL_REPLICA;
|
||||
|
||||
ctx->remote.type = REMOTE_REPLICA;
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
ctx->statedb.file = c_strdup(db_file);
|
||||
|
||||
c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
|
||||
c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
|
||||
|
||||
ctx->remote.root_perms = 0;
|
||||
|
||||
ctx->status = CSYNC_STATUS_INIT;
|
||||
|
||||
/* initialize random generator */
|
||||
srand(time(NULL));
|
||||
}
|
||||
|
||||
int csync_update(CSYNC *ctx) {
|
||||
int rc = -1;
|
||||
struct timespec start, finish;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
/* Path of database file is set in csync_init */
|
||||
if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
csync_memstat_check();
|
||||
|
||||
if (!ctx->excludes) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "No exclude file loaded or defined!");
|
||||
}
|
||||
|
||||
/* update detection for local replica */
|
||||
csync_gettime(&start);
|
||||
ctx->current = LOCAL_REPLICA;
|
||||
ctx->replica = ctx->local.type;
|
||||
|
||||
rc = csync_ftw(ctx, ctx->local.uri, csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK) {
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Update detection for local replica took %.2f seconds walking %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
|
||||
csync_memstat_check();
|
||||
|
||||
/* update detection for remote replica */
|
||||
csync_gettime(&start);
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
|
||||
rc = csync_ftw(ctx, "", csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK) {
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Update detection for remote replica took %.2f seconds "
|
||||
"walking %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
|
||||
csync_memstat_check();
|
||||
|
||||
ctx->status |= CSYNC_STATUS_UPDATE;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
csync_statedb_close(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int csync_reconcile(CSYNC *ctx) {
|
||||
int rc = -1;
|
||||
struct timespec start, finish;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
/* Reconciliation for local replica */
|
||||
csync_gettime(&start);
|
||||
|
||||
if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctx->current = LOCAL_REPLICA;
|
||||
ctx->replica = ctx->local.type;
|
||||
|
||||
rc = csync_reconcile_updates(ctx);
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Reconciliation for local replica took %.2f seconds visiting %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
|
||||
|
||||
if (rc < 0) {
|
||||
if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
||||
ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR );
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Reconciliation for remote replica */
|
||||
csync_gettime(&start);
|
||||
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
|
||||
rc = csync_reconcile_updates(ctx);
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Reconciliation for remote replica took %.2f seconds visiting %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
|
||||
|
||||
if (rc < 0) {
|
||||
if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_RECONCILE_ERROR );
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx->status |= CSYNC_STATUS_RECONCILE;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
csync_statedb_close(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* local visitor which calls the user visitor with repacked stat info.
|
||||
*/
|
||||
static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||
int rc = 0;
|
||||
csync_file_stat_t *cur = NULL;
|
||||
CSYNC *ctx = NULL;
|
||||
c_rbtree_visit_func *visitor = NULL;
|
||||
_csync_treewalk_context *twctx = NULL;
|
||||
TREE_WALK_FILE trav;
|
||||
c_rbtree_t *other_tree = NULL;
|
||||
c_rbnode_t *other_node = NULL;
|
||||
|
||||
cur = (csync_file_stat_t *) obj;
|
||||
ctx = (CSYNC *) data;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we need the opposite tree! */
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
other_tree = ctx->remote.tree;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
other_tree = ctx->local.tree;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
other_node = c_rbtree_find(other_tree, &cur->phash);
|
||||
|
||||
if (!other_node) {
|
||||
/* Check the renamed path as well. */
|
||||
int len;
|
||||
uint64_t h = 0;
|
||||
char *renamed_path = csync_rename_adjust_path(ctx, cur->path);
|
||||
|
||||
if (!c_streq(renamed_path, cur->path)) {
|
||||
len = strlen( renamed_path );
|
||||
h = c_jhash64((uint8_t *) renamed_path, len, 0);
|
||||
other_node = c_rbtree_find(other_tree, &h);
|
||||
}
|
||||
SAFE_FREE(renamed_path);
|
||||
}
|
||||
|
||||
if (!other_node) {
|
||||
/* Check the source path as well. */
|
||||
int len;
|
||||
uint64_t h = 0;
|
||||
char *renamed_path = csync_rename_adjust_path_source(ctx, cur->path);
|
||||
|
||||
if (!c_streq(renamed_path, cur->path)) {
|
||||
len = strlen( renamed_path );
|
||||
h = c_jhash64((uint8_t *) renamed_path, len, 0);
|
||||
other_node = c_rbtree_find(other_tree, &h);
|
||||
}
|
||||
SAFE_FREE(renamed_path);
|
||||
}
|
||||
|
||||
if (obj == NULL || data == NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
twctx = (_csync_treewalk_context*) ctx->callbacks.userdata;
|
||||
if (twctx == NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (twctx->instruction_filter > 0 &&
|
||||
!(twctx->instruction_filter & cur->instruction) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
visitor = (c_rbtree_visit_func*)(twctx->user_visitor);
|
||||
if (visitor != NULL) {
|
||||
trav.path = cur->path;
|
||||
trav.size = cur->size;
|
||||
trav.modtime = cur->modtime;
|
||||
trav.mode = cur->mode;
|
||||
trav.type = cur->type;
|
||||
trav.instruction = cur->instruction;
|
||||
trav.rename_path = cur->destpath;
|
||||
trav.etag = cur->etag;
|
||||
trav.file_id = cur->file_id;
|
||||
trav.remotePerm = cur->remotePerm;
|
||||
trav.directDownloadUrl = cur->directDownloadUrl;
|
||||
trav.directDownloadCookies = cur->directDownloadCookies;
|
||||
trav.inode = cur->inode;
|
||||
|
||||
trav.error_status = cur->error_status;
|
||||
trav.has_ignored_files = cur->has_ignored_files;
|
||||
trav.checksum = cur->checksum;
|
||||
trav.checksumTypeId = cur->checksumTypeId;
|
||||
|
||||
if( other_node ) {
|
||||
csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
|
||||
trav.other.etag = other_stat->etag;
|
||||
trav.other.file_id = other_stat->file_id;
|
||||
trav.other.instruction = other_stat->instruction;
|
||||
trav.other.modtime = other_stat->modtime;
|
||||
trav.other.size = other_stat->size;
|
||||
} else {
|
||||
trav.other.etag = 0;
|
||||
trav.other.file_id = 0;
|
||||
trav.other.instruction = CSYNC_INSTRUCTION_NONE;
|
||||
trav.other.modtime = 0;
|
||||
trav.other.size = 0;
|
||||
}
|
||||
|
||||
rc = (*visitor)(&trav, twctx->userdata);
|
||||
cur->instruction = trav.instruction;
|
||||
if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
|
||||
SAFE_FREE(cur->etag);
|
||||
cur->etag = c_strdup(trav.etag);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* treewalk function, called from its wrappers below.
|
||||
*
|
||||
* it encapsulates the user visitor function, the filter and the userdata
|
||||
* into a treewalk_context structure and calls the rb treewalk function,
|
||||
* which calls the local _csync_treewalk_visitor in this module.
|
||||
* The user visitor is called from there.
|
||||
*/
|
||||
static int _csync_walk_tree(CSYNC *ctx, c_rbtree_t *tree, csync_treewalk_visit_func *visitor, int filter)
|
||||
{
|
||||
_csync_treewalk_context tw_ctx;
|
||||
int rc = -1;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EBADF;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (visitor == NULL || tree == NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return rc;
|
||||
}
|
||||
|
||||
tw_ctx.userdata = ctx->callbacks.userdata;
|
||||
tw_ctx.user_visitor = visitor;
|
||||
tw_ctx.instruction_filter = filter;
|
||||
|
||||
ctx->callbacks.userdata = &tw_ctx;
|
||||
|
||||
rc = c_rbtree_walk(tree, (void*) ctx, _csync_treewalk_visitor);
|
||||
if( rc < 0 ) {
|
||||
if( ctx->status_code == CSYNC_STATUS_OK )
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR);
|
||||
}
|
||||
ctx->callbacks.userdata = tw_ctx.userdata;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* wrapper function for treewalk on the remote tree
|
||||
*/
|
||||
int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter)
|
||||
{
|
||||
c_rbtree_t *tree = NULL;
|
||||
int rc = -1;
|
||||
|
||||
if(ctx != NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
tree = ctx->remote.tree;
|
||||
}
|
||||
|
||||
/* all error handling in the called function */
|
||||
rc = _csync_walk_tree(ctx, tree, visitor, filter);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* wrapper function for treewalk on the local tree
|
||||
*/
|
||||
int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter)
|
||||
{
|
||||
c_rbtree_t *tree = NULL;
|
||||
int rc = -1;
|
||||
|
||||
if (ctx != NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
ctx->current = LOCAL_REPLICA;
|
||||
tree = ctx->local.tree;
|
||||
}
|
||||
|
||||
/* all error handling in the called function */
|
||||
rc = _csync_walk_tree(ctx, tree, visitor, filter);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void _tree_destructor(void *data) {
|
||||
csync_file_stat_t *freedata = NULL;
|
||||
|
||||
freedata = (csync_file_stat_t *) data;
|
||||
csync_file_stat_free(freedata);
|
||||
}
|
||||
|
||||
/* reset all the list to empty.
|
||||
* used by csync_commit and csync_destroy */
|
||||
static void _csync_clean_ctx(CSYNC *ctx)
|
||||
{
|
||||
/* destroy the rbtrees */
|
||||
if (c_rbtree_size(ctx->local.tree) > 0) {
|
||||
c_rbtree_destroy(ctx->local.tree, _tree_destructor);
|
||||
}
|
||||
|
||||
if (c_rbtree_size(ctx->remote.tree) > 0) {
|
||||
c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
|
||||
}
|
||||
|
||||
csync_rename_destroy(ctx);
|
||||
|
||||
/* free memory */
|
||||
c_rbtree_free(ctx->local.tree);
|
||||
c_rbtree_free(ctx->remote.tree);
|
||||
|
||||
SAFE_FREE(ctx->remote.root_perms);
|
||||
}
|
||||
|
||||
int csync_commit(CSYNC *ctx) {
|
||||
int rc = 0;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
if (ctx->statedb.db != NULL
|
||||
&& csync_statedb_close(ctx) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ERR: closing of statedb failed.");
|
||||
rc = -1;
|
||||
}
|
||||
ctx->statedb.db = NULL;
|
||||
|
||||
_csync_clean_ctx(ctx);
|
||||
|
||||
ctx->remote.read_from_db = 0;
|
||||
ctx->read_remote_from_db = true;
|
||||
ctx->db_is_empty = false;
|
||||
|
||||
|
||||
/* Create new trees */
|
||||
c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
|
||||
c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
|
||||
|
||||
|
||||
ctx->status = CSYNC_STATUS_INIT;
|
||||
SAFE_FREE(ctx->error_string);
|
||||
|
||||
rc = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int csync_destroy(CSYNC *ctx) {
|
||||
int rc = 0;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
if (ctx->statedb.db != NULL
|
||||
&& csync_statedb_close(ctx) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ERR: closing of statedb failed.");
|
||||
rc = -1;
|
||||
}
|
||||
ctx->statedb.db = NULL;
|
||||
|
||||
_csync_clean_ctx(ctx);
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
SAFE_FREE(ctx->local.uri);
|
||||
SAFE_FREE(ctx->error_string);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
c_close_iconv();
|
||||
#endif
|
||||
|
||||
SAFE_FREE(ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void *csync_get_userdata(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return ctx->callbacks.userdata;
|
||||
}
|
||||
|
||||
int csync_set_userdata(CSYNC *ctx, void *userdata) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->callbacks.userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
csync_auth_callback csync_get_auth_callback(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx->callbacks.auth_function;
|
||||
}
|
||||
|
||||
int csync_set_status(CSYNC *ctx, int status) {
|
||||
if (ctx == NULL || status < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->status = status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CSYNC_STATUS csync_get_status(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ctx->status_code;
|
||||
}
|
||||
|
||||
const char *csync_get_status_string(CSYNC *ctx)
|
||||
{
|
||||
return csync_vio_get_status_string(ctx);
|
||||
}
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
int csync_set_iconv_codec(const char *from)
|
||||
{
|
||||
c_close_iconv();
|
||||
|
||||
if (from != NULL) {
|
||||
c_setup_iconv(from);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void csync_request_abort(CSYNC *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
ctx->abort = true;
|
||||
}
|
||||
}
|
||||
|
||||
void csync_resume(CSYNC *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
ctx->abort = false;
|
||||
}
|
||||
}
|
||||
|
||||
int csync_abort_requested(CSYNC *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
return ctx->abort;
|
||||
} else {
|
||||
return (1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void csync_file_stat_free(csync_file_stat_t *st)
|
||||
{
|
||||
if (st) {
|
||||
SAFE_FREE(st->directDownloadUrl);
|
||||
SAFE_FREE(st->directDownloadCookies);
|
||||
SAFE_FREE(st->etag);
|
||||
SAFE_FREE(st->destpath);
|
||||
SAFE_FREE(st->checksum);
|
||||
SAFE_FREE(st);
|
||||
}
|
||||
}
|
||||
@@ -1,430 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_exclude.h"
|
||||
#include "csync_misc.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifndef WITH_TESTING
|
||||
static
|
||||
#endif
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||
size_t i = 0;
|
||||
|
||||
// We never want duplicates, so check whether the string is already
|
||||
// in the list first.
|
||||
if (*inList) {
|
||||
for (i = 0; i < (*inList)->count; ++i) {
|
||||
char *pattern = (*inList)->vector[i];
|
||||
if (c_streq(pattern, string)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return c_strlist_add_grow(inList, string);
|
||||
}
|
||||
|
||||
/** Expands C-like escape sequences.
|
||||
*
|
||||
* The returned string is heap-allocated and owned by the caller.
|
||||
*/
|
||||
static const char *csync_exclude_expand_escapes(const char * input)
|
||||
{
|
||||
size_t i_len = strlen(input) + 1;
|
||||
char *out = c_malloc(i_len); // out can only be shorter
|
||||
|
||||
size_t i = 0;
|
||||
size_t o = 0;
|
||||
for (; i < i_len; ++i) {
|
||||
if (input[i] == '\\') {
|
||||
// at worst input[i+1] is \0
|
||||
switch (input[i+1]) {
|
||||
case '\'': out[o++] = '\''; break;
|
||||
case '"': out[o++] = '"'; break;
|
||||
case '?': out[o++] = '?'; break;
|
||||
case '\\': out[o++] = '\\'; break;
|
||||
case 'a': out[o++] = '\a'; break;
|
||||
case 'b': out[o++] = '\b'; break;
|
||||
case 'f': out[o++] = '\f'; break;
|
||||
case 'n': out[o++] = '\n'; break;
|
||||
case 'r': out[o++] = '\r'; break;
|
||||
case 't': out[o++] = '\t'; break;
|
||||
case 'v': out[o++] = '\v'; break;
|
||||
default:
|
||||
out[o++] = input[i];
|
||||
out[o++] = input[i+1];
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
out[o++] = input[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int csync_exclude_load(const char *fname, c_strlist_t **list) {
|
||||
int fd = -1;
|
||||
int i = 0;
|
||||
int rc = -1;
|
||||
int64_t size;
|
||||
char *buf = NULL;
|
||||
char *entry = NULL;
|
||||
mbchar_t *w_fname;
|
||||
|
||||
if (fname == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_fmode = _O_BINARY;
|
||||
#endif
|
||||
|
||||
w_fname = c_utf8_path_to_locale(fname);
|
||||
if (w_fname == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = _topen(w_fname, O_RDONLY);
|
||||
c_free_locale_string(w_fname);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
if (size < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
if (size == 0) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
buf = c_malloc(size + 1);
|
||||
if (read(fd, buf, size) != size) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
buf[size] = '\0';
|
||||
|
||||
/* FIXME: Use fgets and don't add duplicates */
|
||||
entry = buf;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (buf[i] == '\n' || buf[i] == '\r') {
|
||||
if (entry != buf + i) {
|
||||
buf[i] = '\0';
|
||||
if (*entry != '#') {
|
||||
const char *unescaped = csync_exclude_expand_escapes(entry);
|
||||
rc = _csync_exclude_add(list, unescaped);
|
||||
if( rc == 0 ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped);
|
||||
}
|
||||
SAFE_FREE(unescaped);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
entry = buf + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
SAFE_FREE(buf);
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// See http://support.microsoft.com/kb/74496 and
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||
// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955
|
||||
static const char* win_reserved_words[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
|
||||
"COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4",
|
||||
"LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "CLOCK$", "$Recycle.Bin" };
|
||||
|
||||
bool csync_is_windows_reserved_word(const char* filename) {
|
||||
|
||||
size_t win_reserve_words_len = sizeof(win_reserved_words) / sizeof(char*);
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < win_reserve_words_len; j++) {
|
||||
int len_reserved_word = strlen(win_reserved_words[j]);
|
||||
int len_filename = strlen(filename);
|
||||
if (len_filename == 2 && filename[1] == ':') {
|
||||
if (filename[0] >= 'a' && filename[0] <= 'z') {
|
||||
return true;
|
||||
}
|
||||
if (filename[0] >= 'A' && filename[0] <= 'Z') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (c_strncasecmp(filename, win_reserved_words[j], len_reserved_word) == 0) {
|
||||
if (len_filename == len_reserved_word) {
|
||||
return true;
|
||||
}
|
||||
if ((len_filename > len_reserved_word) && (filename[len_reserved_word] == '.')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
|
||||
size_t i = 0;
|
||||
const char *bname = NULL;
|
||||
size_t blen = 0;
|
||||
char *conflict = NULL;
|
||||
int rc = -1;
|
||||
CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
|
||||
CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
|
||||
|
||||
/* split up the path */
|
||||
bname = strrchr(path, '/');
|
||||
if (bname) {
|
||||
bname += 1; // don't include the /
|
||||
} else {
|
||||
bname = path;
|
||||
}
|
||||
blen = strlen(bname);
|
||||
|
||||
rc = csync_fnmatch("._sync_*.db*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
goto out;
|
||||
}
|
||||
rc = csync_fnmatch(".sync_*.db*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
goto out;
|
||||
}
|
||||
rc = csync_fnmatch(".csync_journal.db*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// check the strlen and ignore the file if its name is longer than 254 chars.
|
||||
// whenever changing this also check createDownloadTmpFileName
|
||||
if (blen > 254) {
|
||||
match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows cannot sync files ending in spaces (#2176). It also cannot
|
||||
// distinguish files ending in '.' from files without an ending,
|
||||
// as '.' is a separator that is not stored internally, so let's
|
||||
// not allow to sync those to avoid file loss/ambiguities (#416)
|
||||
if (blen > 1) {
|
||||
if (bname[blen-1]== ' ') {
|
||||
match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
|
||||
goto out;
|
||||
} else if (bname[blen-1]== '.' ) {
|
||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (csync_is_windows_reserved_word(bname)) {
|
||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Filter out characters not allowed in a filename on windows
|
||||
const char *p = NULL;
|
||||
for (p = path; *p; p++) {
|
||||
switch (*p) {
|
||||
case '\\':
|
||||
case ':':
|
||||
case '?':
|
||||
case '*':
|
||||
case '"':
|
||||
case '>':
|
||||
case '<':
|
||||
case '|':
|
||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||
goto out;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Always ignore conflict files, not only via the exclude list */
|
||||
rc = csync_fnmatch("*_conflict-*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
|
||||
rc = asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
rc = csync_fnmatch(conflict, path, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
SAFE_FREE(conflict);
|
||||
goto out;
|
||||
}
|
||||
SAFE_FREE(conflict);
|
||||
}
|
||||
|
||||
if( ! excludes ) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
c_strlist_t *path_components = NULL;
|
||||
if (check_leading_dirs) {
|
||||
/* Build a list of path components to check. */
|
||||
path_components = c_strlist_new(32);
|
||||
char *path_split = strdup(path);
|
||||
size_t len = strlen(path_split);
|
||||
for (i = len; ; --i) {
|
||||
// read backwards until a path separator is found
|
||||
if (i != 0 && path_split[i-1] != '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
|
||||
if (path_split[i] != 0) {
|
||||
c_strlist_add_grow(&path_components, path_split + i);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
|
||||
path_split[i-1] = '\0';
|
||||
c_strlist_add_grow(&path_components, path_split);
|
||||
}
|
||||
SAFE_FREE(path_split);
|
||||
}
|
||||
|
||||
/* Loop over all exclude patterns and evaluate the given path */
|
||||
for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
|
||||
bool match_dirs_only = false;
|
||||
char *pattern = excludes->vector[i];
|
||||
|
||||
type = CSYNC_FILE_EXCLUDE_LIST;
|
||||
if (!pattern[0]) { /* empty pattern */
|
||||
continue;
|
||||
}
|
||||
/* Excludes starting with ']' means it can be cleanup */
|
||||
if (pattern[0] == ']') {
|
||||
++pattern;
|
||||
if (filetype == CSYNC_FTW_TYPE_FILE) {
|
||||
type = CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
||||
}
|
||||
}
|
||||
/* Check if the pattern applies to pathes only. */
|
||||
if (pattern[strlen(pattern)-1] == '/') {
|
||||
if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) {
|
||||
continue;
|
||||
}
|
||||
match_dirs_only = true;
|
||||
pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
|
||||
}
|
||||
|
||||
/* check if the pattern contains a / and if, compare to the whole path */
|
||||
if (strchr(pattern, '/')) {
|
||||
rc = csync_fnmatch(pattern, path, FNM_PATHNAME);
|
||||
if( rc == 0 ) {
|
||||
match = type;
|
||||
}
|
||||
/* if the pattern requires a dir, but path is not, its still not excluded. */
|
||||
if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) {
|
||||
match = CSYNC_NOT_EXCLUDED;
|
||||
}
|
||||
}
|
||||
|
||||
/* if still not excluded, check each component and leading directory of the path */
|
||||
if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) {
|
||||
size_t j = 0;
|
||||
if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
|
||||
j = 1; // skip the first entry, which is bname
|
||||
}
|
||||
for (; j < path_components->count; ++j) {
|
||||
rc = csync_fnmatch(pattern, path_components->vector[j], 0);
|
||||
if (rc == 0) {
|
||||
match = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) {
|
||||
rc = csync_fnmatch(pattern, bname, 0);
|
||||
if (rc == 0) {
|
||||
match = type;
|
||||
}
|
||||
}
|
||||
if (match_dirs_only) {
|
||||
/* restore the '/' */
|
||||
pattern[strlen(pattern)] = '/';
|
||||
}
|
||||
}
|
||||
c_strlist_destroy(path_components);
|
||||
|
||||
out:
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype) {
|
||||
return _csync_excluded_common(excludes, path, filetype, false);
|
||||
}
|
||||
|
||||
CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype) {
|
||||
return _csync_excluded_common(excludes, path, filetype, true);
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_EXCLUDE_H
|
||||
#define _CSYNC_EXCLUDE_H
|
||||
|
||||
#include "ocsynclib.h"
|
||||
|
||||
enum csync_exclude_type_e {
|
||||
CSYNC_NOT_EXCLUDED = 0,
|
||||
CSYNC_FILE_SILENTLY_EXCLUDED,
|
||||
CSYNC_FILE_EXCLUDE_AND_REMOVE,
|
||||
CSYNC_FILE_EXCLUDE_LIST,
|
||||
CSYNC_FILE_EXCLUDE_INVALID_CHAR,
|
||||
CSYNC_FILE_EXCLUDE_TRAILING_SPACE,
|
||||
CSYNC_FILE_EXCLUDE_LONG_FILENAME,
|
||||
CSYNC_FILE_EXCLUDE_HIDDEN,
|
||||
CSYNC_FILE_EXCLUDE_STAT_FAILED
|
||||
};
|
||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Load exclude list
|
||||
*
|
||||
* @param ctx The context of the synchronizer.
|
||||
* @param fname The filename to load.
|
||||
*
|
||||
* @return 0 on success, -1 if an error occurred with errno set.
|
||||
*/
|
||||
int OCSYNC_EXPORT csync_exclude_load(const char *fname, c_strlist_t **list);
|
||||
|
||||
/**
|
||||
* @brief Check if the given path should be excluded in a traversal situation.
|
||||
*
|
||||
* It does only part of the work that csync_excluded does because it's assumed
|
||||
* that all leading directories have been run through csync_excluded_traversal()
|
||||
* before. This can be significantly faster.
|
||||
*
|
||||
* That means for '/foo/bar/file' only ('/foo/bar/file', 'file') is checked
|
||||
* against the exclude patterns.
|
||||
*
|
||||
* @param ctx The synchronizer context.
|
||||
* @param path The patch to check.
|
||||
*
|
||||
* @return 2 if excluded and needs cleanup, 1 if excluded, 0 if not.
|
||||
*/
|
||||
CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype);
|
||||
|
||||
/**
|
||||
* @brief csync_excluded_no_ctx
|
||||
* @param excludes
|
||||
* @param path
|
||||
* @param filetype
|
||||
* @return
|
||||
*/
|
||||
CSYNC_EXCLUDE_TYPE OCSYNC_EXPORT csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype);
|
||||
#endif /* _CSYNC_EXCLUDE_H */
|
||||
|
||||
/**
|
||||
* @brief Checks if filename is considered reserved by Windows
|
||||
* @param file_name filename
|
||||
* @return true if file is reserved, false otherwise
|
||||
*/
|
||||
bool csync_is_windows_reserved_word(const char *file_name);
|
||||
|
||||
|
||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
CSYNC_THREAD int csync_log_level;
|
||||
CSYNC_THREAD csync_log_callback csync_log_cb;
|
||||
CSYNC_THREAD void *csync_log_userdata;
|
||||
|
||||
static void csync_log_stderr(int verbosity,
|
||||
const char *function,
|
||||
const char *buffer)
|
||||
{
|
||||
fprintf(stderr, "[%d] %s", verbosity, function);
|
||||
fprintf(stderr, " %s\n", buffer);
|
||||
}
|
||||
static void csync_log_function(int verbosity,
|
||||
const char *function,
|
||||
const char *buffer)
|
||||
{
|
||||
csync_log_callback log_fn = csync_get_log_callback();
|
||||
if (log_fn) {
|
||||
char buf[1024];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s: %s", function, buffer);
|
||||
|
||||
log_fn(verbosity,
|
||||
function,
|
||||
buf,
|
||||
csync_get_log_userdata());
|
||||
return;
|
||||
}
|
||||
|
||||
csync_log_stderr(verbosity, function, buffer);
|
||||
}
|
||||
|
||||
|
||||
void csync_log(int verbosity,
|
||||
const char *function,
|
||||
const char *format, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
va_list va;
|
||||
|
||||
if (verbosity <= csync_get_log_level()) {
|
||||
va_start(va, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, va);
|
||||
va_end(va);
|
||||
csync_log_function(verbosity, function, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
int csync_set_log_level(int level) {
|
||||
if (level < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
csync_log_level = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_get_log_level(void) {
|
||||
return csync_log_level;
|
||||
}
|
||||
|
||||
int csync_set_log_callback(csync_log_callback cb) {
|
||||
if (cb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
csync_log_cb = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
csync_log_callback csync_get_log_callback(void) {
|
||||
return csync_log_cb;
|
||||
}
|
||||
|
||||
void *csync_get_log_userdata(void)
|
||||
{
|
||||
return csync_log_userdata;
|
||||
}
|
||||
|
||||
int csync_set_log_userdata(void *data)
|
||||
{
|
||||
csync_log_userdata = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync_log.h
|
||||
*
|
||||
* @brief Logging interface of csync
|
||||
*
|
||||
* @defgroup csyncLogInternals csync logging internals
|
||||
* @ingroup csyncInternalAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_LOG_H
|
||||
#define _CSYNC_LOG_H
|
||||
|
||||
/* GCC have printf type attribute check. */
|
||||
#ifndef PRINTF_ATTRIBUTE
|
||||
#ifdef __GNUC__
|
||||
#ifdef _WIN32
|
||||
#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__gnu_printf__, a, b)))
|
||||
#else
|
||||
#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
|
||||
#endif
|
||||
#else
|
||||
#define PRINTF_ATTRIBUTE(a,b)
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* ndef PRINTF_ATTRIBUTE */
|
||||
|
||||
enum csync_log_priority_e {
|
||||
CSYNC_LOG_PRIORITY_NOLOG = 0,
|
||||
CSYNC_LOG_PRIORITY_FATAL,
|
||||
CSYNC_LOG_PRIORITY_ALERT,
|
||||
CSYNC_LOG_PRIORITY_CRIT,
|
||||
CSYNC_LOG_PRIORITY_ERROR,
|
||||
CSYNC_LOG_PRIORITY_WARN,
|
||||
CSYNC_LOG_PRIORITY_NOTICE,
|
||||
CSYNC_LOG_PRIORITY_INFO,
|
||||
CSYNC_LOG_PRIORITY_DEBUG,
|
||||
CSYNC_LOG_PRIORITY_TRACE,
|
||||
CSYNC_LOG_PRIORITY_NOTSET,
|
||||
CSYNC_LOG_PRIORITY_UNKNOWN,
|
||||
};
|
||||
|
||||
#define CSYNC_LOG(priority, ...) \
|
||||
csync_log(priority, __func__, __VA_ARGS__)
|
||||
|
||||
void csync_log(int verbosity,
|
||||
const char *function,
|
||||
const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_LOG_H */
|
||||
|
||||
/* vim: set ft=c.doxygen ts=4 sw=4 et cindent: */
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync_private.h
|
||||
*
|
||||
* @brief Private interface of csync
|
||||
*
|
||||
* @defgroup csyncInternalAPI csync internal API
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_PRIVATE_H
|
||||
#define _CSYNC_PRIVATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "config_csync.h"
|
||||
#include "std/c_lib.h"
|
||||
#include "std/c_private.h"
|
||||
#include "csync.h"
|
||||
#include "csync_misc.h"
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_ICONV_H
|
||||
#include <sys/iconv.h>
|
||||
#endif
|
||||
|
||||
#include "csync_macros.h"
|
||||
|
||||
/**
|
||||
* How deep to scan directories.
|
||||
*/
|
||||
#define MAX_DEPTH 50
|
||||
|
||||
#define CSYNC_STATUS_INIT 1 << 0
|
||||
#define CSYNC_STATUS_UPDATE 1 << 1
|
||||
#define CSYNC_STATUS_RECONCILE 1 << 2
|
||||
#define CSYNC_STATUS_PROPAGATE 1 << 3
|
||||
|
||||
#define CSYNC_STATUS_DONE (CSYNC_STATUS_INIT | \
|
||||
CSYNC_STATUS_UPDATE | \
|
||||
CSYNC_STATUS_RECONCILE | \
|
||||
CSYNC_STATUS_PROPAGATE)
|
||||
|
||||
enum csync_replica_e {
|
||||
LOCAL_REPLICA,
|
||||
REMOTE_REPLICA
|
||||
};
|
||||
|
||||
typedef struct csync_file_stat_s csync_file_stat_t;
|
||||
|
||||
/**
|
||||
* @brief csync public structure
|
||||
*/
|
||||
struct csync_s {
|
||||
struct {
|
||||
csync_auth_callback auth_function;
|
||||
void *userdata;
|
||||
csync_update_callback update_callback;
|
||||
void *update_callback_userdata;
|
||||
|
||||
/* hooks for checking the white list (uses the update_callback_userdata) */
|
||||
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */);
|
||||
|
||||
|
||||
csync_vio_opendir_hook remote_opendir_hook;
|
||||
csync_vio_readdir_hook remote_readdir_hook;
|
||||
csync_vio_closedir_hook remote_closedir_hook;
|
||||
void *vio_userdata;
|
||||
|
||||
/* hook for comparing checksums of files during discovery */
|
||||
csync_checksum_hook checksum_hook;
|
||||
void *checksum_userdata;
|
||||
|
||||
} callbacks;
|
||||
c_strlist_t *excludes;
|
||||
|
||||
struct {
|
||||
char *file;
|
||||
sqlite3 *db;
|
||||
int exists;
|
||||
|
||||
sqlite3_stmt* by_hash_stmt;
|
||||
sqlite3_stmt* by_fileid_stmt;
|
||||
sqlite3_stmt* by_inode_stmt;
|
||||
|
||||
int lastReturnValue;
|
||||
} statedb;
|
||||
|
||||
struct {
|
||||
char *uri;
|
||||
c_rbtree_t *tree;
|
||||
enum csync_replica_e type;
|
||||
} local;
|
||||
|
||||
struct {
|
||||
c_rbtree_t *tree;
|
||||
enum csync_replica_e type;
|
||||
int read_from_db;
|
||||
const char *root_perms; /* Permission of the root folder. (Since the root folder is not in the db tree, we need to keep a separate entry.) */
|
||||
} remote;
|
||||
|
||||
|
||||
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
|
||||
struct {
|
||||
iconv_t iconv_cd;
|
||||
} options;
|
||||
#endif
|
||||
|
||||
/* replica we are currently walking */
|
||||
enum csync_replica_e current;
|
||||
|
||||
/* replica we want to work on */
|
||||
enum csync_replica_e replica;
|
||||
|
||||
/* Used in the update phase so changes in the sub directories can be notified to
|
||||
parent directories */
|
||||
csync_file_stat_t *current_fs;
|
||||
|
||||
/* csync error code */
|
||||
enum csync_status_codes_e status_code;
|
||||
|
||||
char *error_string;
|
||||
|
||||
int status;
|
||||
volatile int abort;
|
||||
void *rename_info;
|
||||
|
||||
/**
|
||||
* Specify if it is allowed to read the remote tree from the DB (default to enabled)
|
||||
*/
|
||||
bool read_remote_from_db;
|
||||
|
||||
/**
|
||||
* If true, the DB is considered empty and all reads are skipped. (default is false)
|
||||
* This is useful during the initial local discovery as it speeds it up significantly.
|
||||
*/
|
||||
bool db_is_empty;
|
||||
|
||||
bool ignore_hidden_files;
|
||||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct csync_file_stat_s {
|
||||
uint64_t phash; /* u64 */
|
||||
time_t modtime; /* u64 */
|
||||
int64_t size; /* u64 */
|
||||
size_t pathlen; /* u64 */
|
||||
uint64_t inode; /* u64 */
|
||||
mode_t mode; /* u32 */
|
||||
unsigned int type : 4;
|
||||
unsigned int child_modified : 1;
|
||||
unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */
|
||||
|
||||
char *destpath; /* for renames */
|
||||
const char *etag;
|
||||
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width in ownCloud. */
|
||||
char *directDownloadUrl;
|
||||
char *directDownloadCookies;
|
||||
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
|
||||
|
||||
const char *checksum;
|
||||
uint32_t checksumTypeId;
|
||||
|
||||
CSYNC_STATUS error_status;
|
||||
|
||||
enum csync_instructions_e instruction; /* u32 */
|
||||
char path[1]; /* u8 */
|
||||
}
|
||||
#if !defined(__SUNPRO_C) && !defined(_MSC_VER)
|
||||
__attribute__ ((packed))
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
;
|
||||
|
||||
OCSYNC_EXPORT void csync_file_stat_free(csync_file_stat_t *st);
|
||||
|
||||
/*
|
||||
* context for the treewalk function
|
||||
*/
|
||||
struct _csync_treewalk_context_s
|
||||
{
|
||||
csync_treewalk_visit_func *user_visitor;
|
||||
int instruction_filter;
|
||||
void *userdata;
|
||||
};
|
||||
typedef struct _csync_treewalk_context_s _csync_treewalk_context;
|
||||
|
||||
void set_errno_from_http_errcode( int err );
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_PRIVATE_H */
|
||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "csync_private.h"
|
||||
#include "csync_reconcile.h"
|
||||
#include "csync_util.h"
|
||||
#include "csync_statedb.h"
|
||||
#include "csync_rename.h"
|
||||
#include "c_jhash.h"
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler"
|
||||
#include "csync_log.h"
|
||||
|
||||
#include "inttypes.h"
|
||||
|
||||
/* Check if a file is ignored because one parent is ignored.
|
||||
* return the node of the ignored directoy if it's the case, or NULL if it is not ignored */
|
||||
static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int pathlen) {
|
||||
uint64_t h = 0;
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
/* compute the size of the parent directory */
|
||||
int parentlen = pathlen - 1;
|
||||
while (parentlen > 0 && path[parentlen] != '/') {
|
||||
parentlen--;
|
||||
}
|
||||
if (parentlen <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h = c_jhash64((uint8_t *) path, parentlen, 0);
|
||||
node = c_rbtree_find(tree, &h);
|
||||
if (node) {
|
||||
csync_file_stat_t *n = (csync_file_stat_t*)node->data;
|
||||
if (n->instruction == CSYNC_INSTRUCTION_IGNORE) {
|
||||
/* Yes, we are ignored */
|
||||
return node;
|
||||
} else {
|
||||
/* Not ignored */
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* Try if the parent itself is ignored */
|
||||
return _csync_check_ignored(tree, path, parentlen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main function in the reconcile pass.
|
||||
*
|
||||
* It's called for each entry in the local and remote rbtrees by
|
||||
* csync_reconcile()
|
||||
*
|
||||
* Before the reconcile phase the trees already know about changes
|
||||
* relative to the sync journal. This function's job is to spot conflicts
|
||||
* between local and remote changes and adjust the nodes accordingly.
|
||||
*
|
||||
* See doc/dev/sync-algorithm.md for an overview.
|
||||
*
|
||||
*
|
||||
* Older detail comment:
|
||||
*
|
||||
* We merge replicas at the file level. The merged replica contains the
|
||||
* superset of files that are on the local machine and server copies of
|
||||
* the replica. In the case where the same file is in both the local
|
||||
* and server copy, the file that was modified most recently is used.
|
||||
* This means that new files are not deleted, and updated versions of
|
||||
* existing files are not overwritten.
|
||||
*
|
||||
* When a file is updated, the merge algorithm compares the destination
|
||||
* file with the the source file. If the destination file is newer
|
||||
* (timestamp is newer), it is not overwritten. If both files, on the
|
||||
* source and the destination, have been changed, the newer file wins.
|
||||
*/
|
||||
static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
csync_file_stat_t *cur = NULL;
|
||||
csync_file_stat_t *other = NULL;
|
||||
csync_file_stat_t *tmp = NULL;
|
||||
uint64_t h = 0;
|
||||
int len = 0;
|
||||
|
||||
CSYNC *ctx = NULL;
|
||||
c_rbtree_t *tree = NULL;
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
cur = (csync_file_stat_t *) obj;
|
||||
ctx = (CSYNC *) data;
|
||||
|
||||
/* we need the opposite tree! */
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
tree = ctx->remote.tree;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
tree = ctx->local.tree;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
node = c_rbtree_find(tree, &cur->phash);
|
||||
|
||||
if (!node) {
|
||||
/* Check the renamed path as well. */
|
||||
char *renamed_path = csync_rename_adjust_path(ctx, cur->path);
|
||||
if (!c_streq(renamed_path, cur->path)) {
|
||||
len = strlen( renamed_path );
|
||||
h = c_jhash64((uint8_t *) renamed_path, len, 0);
|
||||
node = c_rbtree_find(tree, &h);
|
||||
}
|
||||
SAFE_FREE(renamed_path);
|
||||
}
|
||||
if (!node) {
|
||||
/* Check if it is ignored */
|
||||
node = _csync_check_ignored(tree, cur->path, cur->pathlen);
|
||||
/* If it is ignored, other->instruction will be IGNORE so this one will also be ignored */
|
||||
}
|
||||
|
||||
/* file only found on current replica */
|
||||
if (node == NULL) {
|
||||
switch(cur->instruction) {
|
||||
/* file has been modified */
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
cur->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
break;
|
||||
/* file has been removed on the opposite replica */
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
if (cur->has_ignored_files) {
|
||||
/* Do not remove a directory that has ignored files */
|
||||
break;
|
||||
}
|
||||
if (cur->child_modified) {
|
||||
/* re-create directory that has modified contents */
|
||||
cur->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
break;
|
||||
}
|
||||
cur->instruction = CSYNC_INSTRUCTION_REMOVE;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_EVAL_RENAME:
|
||||
if(ctx->current == LOCAL_REPLICA ) {
|
||||
/* use the old name to find the "other" node */
|
||||
tmp = csync_statedb_get_stat_by_inode(ctx, cur->inode);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through inode %" PRIu64 ": %s",
|
||||
cur->inode, tmp ? "true":"false");
|
||||
} else if( ctx->current == REMOTE_REPLICA ) {
|
||||
tmp = csync_statedb_get_stat_by_file_id(ctx, cur->file_id);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through file ID %s: %s",
|
||||
cur->file_id, tmp ? "true":"false");
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unknown replica...");
|
||||
}
|
||||
|
||||
if( tmp ) {
|
||||
len = strlen( tmp->path );
|
||||
if( len > 0 ) {
|
||||
h = c_jhash64((uint8_t *) tmp->path, len, 0);
|
||||
/* First, check that the file is NOT in our tree (another file with the same name was added) */
|
||||
node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h);
|
||||
if (node) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path);
|
||||
} else {
|
||||
/* Find the temporar file in the other tree. */
|
||||
node = c_rbtree_find(tree, &h);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "PHash of temporary opposite (%s): %" PRIu64 " %s",
|
||||
tmp->path , h, node ? "found": "not found" );
|
||||
if (node) {
|
||||
other = (csync_file_stat_t*)node->data;
|
||||
} else {
|
||||
/* the renamed file could not be found in the opposite tree. That is because it
|
||||
* is not longer existing there, maybe because it was renamed or deleted.
|
||||
* The journal is cleaned up later after propagation.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!other) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_NONE
|
||||
|| other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
|| cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
other->destpath = c_strdup( cur->path );
|
||||
if( !c_streq(cur->file_id, "") ) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
other->destpath = c_strdup( cur->path );
|
||||
|
||||
if( !c_streq(cur->file_id, "") ) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
|
||||
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
} else {
|
||||
assert(other->type != CSYNC_FTW_TYPE_DIR);
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = CSYNC_INSTRUCTION_SYNC;
|
||||
}
|
||||
csync_file_stat_free(tmp);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
bool is_conflict = true;
|
||||
/*
|
||||
* file found on the other replica
|
||||
*/
|
||||
other = (csync_file_stat_t *) node->data;
|
||||
|
||||
switch (cur->instruction) {
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) {
|
||||
// Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last.
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_EVAL_RENAME:
|
||||
/* If the file already exist on the other side, we have a conflict.
|
||||
Abort the rename and consider it is a new file. */
|
||||
cur->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
/* fall trough */
|
||||
/* file on current replica is changed or new */
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
// This operation is usually a no-op and will by default return false
|
||||
if (csync_file_locked_or_open(ctx->local.uri, cur->path)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path);
|
||||
cur->instruction = CSYNC_INSTRUCTION_ERROR;
|
||||
if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error
|
||||
cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN;
|
||||
break;
|
||||
} else {
|
||||
//CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path);
|
||||
}
|
||||
switch (other->instruction) {
|
||||
/* file on other replica is changed or new */
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
if (other->type == CSYNC_FTW_TYPE_DIR &&
|
||||
cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
// Folders of the same path are always considered equals
|
||||
is_conflict = false;
|
||||
} else {
|
||||
is_conflict = ((other->size != cur->size) || (other->modtime != cur->modtime));
|
||||
// FIXME: do a binary comparision of the file here because of the following
|
||||
// edge case:
|
||||
// The files could still have different content, even though the mtime
|
||||
// and size are the same.
|
||||
}
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
// If the files are considered equal, only update the DB with the etag from remote
|
||||
cur->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
}
|
||||
|
||||
break;
|
||||
/* file on the other replica has not been modified */
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_UPDATE_METADATA:
|
||||
if (cur->type != other->type) {
|
||||
// If the type of the entity changed, it's like NEW, but
|
||||
// needs to delete the other entity first.
|
||||
cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
cur->instruction = CSYNC_INSTRUCTION_SYNC;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_IGNORE:
|
||||
cur->instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//hide instruction NONE messages when log level is set to debug,
|
||||
//only show these messages on log level trace
|
||||
const char *repo = ctx->current == REMOTE_REPLICA ? "server" : "client";
|
||||
if(cur->instruction ==CSYNC_INSTRUCTION_NONE)
|
||||
{
|
||||
if(cur->type == CSYNC_FTW_TYPE_DIR)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
||||
"%-30s %s dir: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
}
|
||||
else
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
||||
"%-30s %s file: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cur->type == CSYNC_FTW_TYPE_DIR)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"%-30s %s dir: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
}
|
||||
else
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"%-30s %s file: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_reconcile_updates(CSYNC *ctx) {
|
||||
int rc;
|
||||
c_rbtree_t *tree = NULL;
|
||||
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
tree = ctx->local.tree;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
tree = ctx->remote.tree;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor);
|
||||
if( rc < 0 ) {
|
||||
ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* vim: set ts=8 sw=2 et cindent: */
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2012 by Olivier Goffart <ogoffart@woboq.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "csync_private.h"
|
||||
#include "csync_rename.h"
|
||||
}
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
static std::string _parentDir(const std::string &path) {
|
||||
int len = path.length();
|
||||
while(len > 0 && path[len-1]!='/') len--;
|
||||
while(len > 0 && path[len-1]=='/') len--;
|
||||
return path.substr(0, len);
|
||||
}
|
||||
|
||||
struct csync_rename_s {
|
||||
static csync_rename_s *get(CSYNC *ctx) {
|
||||
if (!ctx->rename_info) {
|
||||
ctx->rename_info = new csync_rename_s;
|
||||
}
|
||||
return reinterpret_cast<csync_rename_s *>(ctx->rename_info);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> folder_renamed_to; // map from->to
|
||||
std::map<std::string, std::string> folder_renamed_from; // map to->from
|
||||
|
||||
struct renameop {
|
||||
csync_file_stat_t *st;
|
||||
bool operator<(const renameop &other) const {
|
||||
return strlen(st->destpath) < strlen(other.st->destpath);
|
||||
}
|
||||
};
|
||||
std::vector<renameop> todo;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
void csync_rename_destroy(CSYNC* ctx)
|
||||
{
|
||||
delete reinterpret_cast<csync_rename_s *>(ctx->rename_info);
|
||||
ctx->rename_info = 0;
|
||||
}
|
||||
|
||||
void csync_rename_record(CSYNC* ctx, const char* from, const char* to)
|
||||
{
|
||||
csync_rename_s::get(ctx)->folder_renamed_to[from] = to;
|
||||
csync_rename_s::get(ctx)->folder_renamed_from[to] = from;
|
||||
}
|
||||
|
||||
char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
|
||||
{
|
||||
csync_rename_s* d = csync_rename_s::get(ctx);
|
||||
for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) {
|
||||
std::map< std::string, std::string >::iterator it = d->folder_renamed_to.find(p);
|
||||
if (it != d->folder_renamed_to.end()) {
|
||||
std::string rep = it->second + (path + p.length());
|
||||
return c_strdup(rep.c_str());
|
||||
}
|
||||
}
|
||||
return c_strdup(path);
|
||||
}
|
||||
|
||||
char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path)
|
||||
{
|
||||
csync_rename_s* d = csync_rename_s::get(ctx);
|
||||
for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) {
|
||||
std::map< std::string, std::string >::iterator it = d->folder_renamed_from.find(p);
|
||||
if (it != d->folder_renamed_from.end()) {
|
||||
std::string rep = it->second + (path + p.length());
|
||||
return c_strdup(rep.c_str());
|
||||
}
|
||||
}
|
||||
return c_strdup(path);
|
||||
}
|
||||
|
||||
bool csync_rename_count(CSYNC *ctx) {
|
||||
csync_rename_s* d = csync_rename_s::get(ctx);
|
||||
return d->folder_renamed_from.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,652 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
#include "csync_statedb.h"
|
||||
#include "csync_util.h"
|
||||
#include "csync_misc.h"
|
||||
#include "csync_exclude.h"
|
||||
|
||||
#include "c_string.h"
|
||||
#include "c_jhash.h"
|
||||
#include "csync_time.h"
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.statedb"
|
||||
#include "csync_log.h"
|
||||
#include "csync_rename.h"
|
||||
|
||||
#define BUF_SIZE 16
|
||||
|
||||
#define sqlite_open(A, B) sqlite3_open_v2(A,B, SQLITE_OPEN_READONLY+SQLITE_OPEN_NOMUTEX, NULL)
|
||||
|
||||
#define SQLTM_TIME 150
|
||||
#define SQLTM_COUNT 10
|
||||
|
||||
#define SQLITE_BUSY_HANDLED(F) if(1) { \
|
||||
int n = 0; \
|
||||
do { rc = F ; \
|
||||
if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) { \
|
||||
n++; \
|
||||
csync_sleep(SQLTM_TIME); \
|
||||
} \
|
||||
}while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))); \
|
||||
}
|
||||
|
||||
|
||||
void csync_set_statedb_exists(CSYNC *ctx, int val) {
|
||||
ctx->statedb.exists = val;
|
||||
}
|
||||
|
||||
int csync_get_statedb_exists(CSYNC *ctx) {
|
||||
return ctx->statedb.exists;
|
||||
}
|
||||
|
||||
static int _csync_check_db_integrity(sqlite3 *db) {
|
||||
c_strlist_t *result = NULL;
|
||||
int rc = -1;
|
||||
|
||||
result = csync_statedb_query(db, "PRAGMA quick_check;");
|
||||
if (result != NULL) {
|
||||
/* There is a result */
|
||||
if (result->count > 0) {
|
||||
if (c_streq(result->vector[0], "ok")) {
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
c_strlist_destroy(result);
|
||||
}
|
||||
|
||||
if( sqlite3_threadsafe() == 0 ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "* WARNING: SQLite module is not threadsafe!");
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _csync_statedb_is_empty(sqlite3 *db) {
|
||||
c_strlist_t *result = NULL;
|
||||
int rc = 0;
|
||||
|
||||
result = csync_statedb_query(db, "SELECT COUNT(phash) FROM metadata LIMIT 1 OFFSET 0;");
|
||||
if (result == NULL) {
|
||||
rc = 1;
|
||||
}
|
||||
c_strlist_destroy(result);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void sqlite_profile( void *x, const char* sql, sqlite3_uint64 time)
|
||||
{
|
||||
(void)x;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"_SQL_ %s: %llu", sql, time);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb) {
|
||||
int rc = -1;
|
||||
c_strlist_t *result = NULL;
|
||||
sqlite3 *db = NULL;
|
||||
|
||||
if( !ctx ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->statedb.db) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: DB already open");
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->statedb.lastReturnValue = SQLITE_OK;
|
||||
|
||||
/* Openthe database */
|
||||
if (sqlite_open(statedb, &db) != SQLITE_OK) {
|
||||
const char *errmsg= sqlite3_errmsg(ctx->statedb.db);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: Failed to sqlite3 open statedb - bail out: %s.",
|
||||
errmsg ? errmsg : "<no sqlite3 errormsg>");
|
||||
|
||||
rc = -1;
|
||||
ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (_csync_check_db_integrity(db) != 0) {
|
||||
const char *errmsg= sqlite3_errmsg(db);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: sqlite3 integrity check failed - bail out: %s.",
|
||||
errmsg ? errmsg : "<no sqlite3 errormsg>");
|
||||
rc = -1;
|
||||
ctx->status_code = CSYNC_STATUS_STATEDB_CORRUPTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (_csync_statedb_is_empty(db)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "statedb contents doesn't exist");
|
||||
csync_set_statedb_exists(ctx, 0);
|
||||
} else {
|
||||
csync_set_statedb_exists(ctx, 1);
|
||||
}
|
||||
|
||||
/* Print out the version */
|
||||
//
|
||||
result = csync_statedb_query(db, "SELECT sqlite_version();");
|
||||
if (result && result->count >= 1) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "sqlite3 version \"%s\"", *result->vector);
|
||||
}
|
||||
c_strlist_destroy(result);
|
||||
|
||||
/* optimization for speeding up SQLite */
|
||||
result = csync_statedb_query(db, "PRAGMA synchronous = NORMAL;");
|
||||
c_strlist_destroy(result);
|
||||
result = csync_statedb_query(db, "PRAGMA case_sensitive_like = ON;");
|
||||
c_strlist_destroy(result);
|
||||
|
||||
/* set a busy handler with 5 seconds timeout */
|
||||
sqlite3_busy_timeout(db, 5000);
|
||||
|
||||
#ifndef NDEBUG
|
||||
sqlite3_profile(db, sqlite_profile, 0 );
|
||||
#endif
|
||||
*pdb = db;
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "Success");
|
||||
|
||||
return 0;
|
||||
out:
|
||||
sqlite3_close(db);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int csync_statedb_close(CSYNC *ctx) {
|
||||
int rc = 0;
|
||||
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* deallocate query resources */
|
||||
if( ctx->statedb.by_fileid_stmt ) {
|
||||
sqlite3_finalize(ctx->statedb.by_fileid_stmt);
|
||||
ctx->statedb.by_fileid_stmt = NULL;
|
||||
}
|
||||
if( ctx->statedb.by_hash_stmt ) {
|
||||
sqlite3_finalize(ctx->statedb.by_hash_stmt);
|
||||
ctx->statedb.by_hash_stmt = NULL;
|
||||
}
|
||||
if( ctx->statedb.by_inode_stmt) {
|
||||
sqlite3_finalize(ctx->statedb.by_inode_stmt);
|
||||
ctx->statedb.by_inode_stmt = NULL;
|
||||
}
|
||||
|
||||
ctx->statedb.lastReturnValue = SQLITE_OK;
|
||||
|
||||
int sr = sqlite3_close(ctx->statedb.db);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "sqlite3_close=%d", sr);
|
||||
|
||||
ctx->statedb.db = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define METADATA_COLUMNS "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, contentChecksum, contentChecksumTypeId"
|
||||
|
||||
// This funciton parses a line from the metadata table into the given csync_file_stat
|
||||
// structure which it is also allocating.
|
||||
// Note that this function calls laso sqlite3_step to actually get the info from db and
|
||||
// returns the sqlite return type.
|
||||
static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3_stmt *stmt )
|
||||
{
|
||||
int rc = SQLITE_ERROR;
|
||||
int column_count;
|
||||
int len;
|
||||
|
||||
if( ! stmt ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Fatal: Statement is NULL.");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
column_count = sqlite3_column_count(stmt);
|
||||
|
||||
SQLITE_BUSY_HANDLED( sqlite3_step(stmt) );
|
||||
|
||||
if( rc == SQLITE_ROW ) {
|
||||
if(column_count > 7) {
|
||||
const char *name;
|
||||
|
||||
/* phash, pathlen, path, inode, uid, gid, mode, modtime */
|
||||
len = sqlite3_column_int(stmt, 1);
|
||||
*st = c_malloc(sizeof(csync_file_stat_t) + len + 1);
|
||||
/* clear the whole structure */
|
||||
ZERO_STRUCTP(*st);
|
||||
|
||||
/* The query suceeded so use the phash we pass to the function. */
|
||||
(*st)->phash = sqlite3_column_int64(stmt, 0);
|
||||
|
||||
(*st)->pathlen = sqlite3_column_int(stmt, 1);
|
||||
name = (const char*) sqlite3_column_text(stmt, 2);
|
||||
memcpy((*st)->path, (len ? name : ""), len + 1);
|
||||
(*st)->inode = sqlite3_column_int64(stmt,3);
|
||||
(*st)->mode = sqlite3_column_int(stmt, 6);
|
||||
(*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
|
||||
|
||||
if(*st && column_count > 8 ) {
|
||||
(*st)->type = sqlite3_column_int(stmt, 8);
|
||||
}
|
||||
|
||||
if(column_count > 9 && sqlite3_column_text(stmt, 9)) {
|
||||
(*st)->etag = c_strdup( (char*) sqlite3_column_text(stmt, 9) );
|
||||
}
|
||||
if(column_count > 10 && sqlite3_column_text(stmt,10)) {
|
||||
csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
|
||||
}
|
||||
if(column_count > 11 && sqlite3_column_text(stmt,11)) {
|
||||
strncpy((*st)->remotePerm,
|
||||
(char*) sqlite3_column_text(stmt, 11),
|
||||
REMOTE_PERM_BUF_SIZE);
|
||||
}
|
||||
if(column_count > 12 && sqlite3_column_int64(stmt,12)) {
|
||||
(*st)->size = sqlite3_column_int64(stmt, 12);
|
||||
}
|
||||
if(column_count > 13) {
|
||||
(*st)->has_ignored_files = sqlite3_column_int(stmt, 13);
|
||||
}
|
||||
if(column_count > 15 && sqlite3_column_int(stmt, 15)) {
|
||||
(*st)->checksum = c_strdup( (char*) sqlite3_column_text(stmt, 14));
|
||||
(*st)->checksumTypeId = sqlite3_column_int(stmt, 15);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if( rc != SQLITE_DONE ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: Query results in %d", rc);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* caller must free the memory */
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
|
||||
uint64_t phash)
|
||||
{
|
||||
csync_file_stat_t *st = NULL;
|
||||
int rc;
|
||||
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( ctx->statedb.by_hash_stmt == NULL ) {
|
||||
const char *hash_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE phash=?1";
|
||||
|
||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL));
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( rc != SQLITE_OK ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( ctx->statedb.by_hash_stmt == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sqlite3_bind_int64(ctx->statedb.by_hash_stmt, 1, (long long signed int)phash);
|
||||
|
||||
rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_hash_stmt);
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
|
||||
}
|
||||
sqlite3_reset(ctx->statedb.by_hash_stmt);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
|
||||
const char *file_id ) {
|
||||
csync_file_stat_t *st = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!file_id) {
|
||||
return 0;
|
||||
}
|
||||
if (c_streq(file_id, "")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( ctx->statedb.by_fileid_stmt == NULL ) {
|
||||
const char *query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE fileid=?1";
|
||||
|
||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL));
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( rc != SQLITE_OK ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* bind the query value */
|
||||
sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC);
|
||||
|
||||
rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt);
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
|
||||
}
|
||||
// clear the resources used by the statement.
|
||||
sqlite3_reset(ctx->statedb.by_fileid_stmt);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
/* caller must free the memory */
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
|
||||
uint64_t inode)
|
||||
{
|
||||
csync_file_stat_t *st = NULL;
|
||||
int rc;
|
||||
|
||||
if (!inode) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( ctx->statedb.by_inode_stmt == NULL ) {
|
||||
const char *inode_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE inode=?1";
|
||||
|
||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL));
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( rc != SQLITE_OK ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for inode query.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( ctx->statedb.by_inode_stmt == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sqlite3_bind_int64(ctx->statedb.by_inode_stmt, 1, (long long signed int)inode);
|
||||
|
||||
rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_inode_stmt);
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata by inode: %d!", rc);
|
||||
}
|
||||
sqlite3_reset(ctx->statedb.by_inode_stmt);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
int rc;
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
int64_t cnt = 0;
|
||||
|
||||
if( !path ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Select the entries for anything that starts with (path+'/')
|
||||
* In other words, anything that is between path+'/' and path+'0',
|
||||
* (because '0' follows '/' in ascii)
|
||||
*/
|
||||
const char *below_path_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC";
|
||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL));
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( rc != SQLITE_OK ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stmt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC);
|
||||
|
||||
cnt = 0;
|
||||
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
do {
|
||||
csync_file_stat_t *st = NULL;
|
||||
|
||||
rc = _csync_file_stat_from_metadata_table( &st, stmt);
|
||||
if( st ) {
|
||||
/* When selective sync is used, the database may have subtrees with a parent
|
||||
* whose etag (md5) is _invalid_. These are ignored and shall not appear in the
|
||||
* remote tree.
|
||||
* Sometimes folders that are not ignored by selective sync get marked as
|
||||
* _invalid_, but that is not a problem as the next discovery will retrieve
|
||||
* their correct etags again and we don't run into this case.
|
||||
*/
|
||||
if( c_streq(st->etag, "_invalid_") ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded", st->path);
|
||||
char *skipbase = c_strdup(st->path);
|
||||
skipbase[st->pathlen] = '/';
|
||||
int skiplen = st->pathlen + 1;
|
||||
|
||||
/* Skip over all entries with the same base path. Note that this depends
|
||||
* strongly on the ordering of the retrieved items. */
|
||||
do {
|
||||
csync_file_stat_free(st);
|
||||
rc = _csync_file_stat_from_metadata_table( &st, stmt);
|
||||
if( st && strncmp(st->path, skipbase, skiplen) != 0 ) {
|
||||
break;
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded because the parent is", st->path);
|
||||
} while( rc == SQLITE_ROW );
|
||||
|
||||
/* End of data? */
|
||||
if( rc != SQLITE_ROW || !st ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for exclusion from the tree.
|
||||
* Note that this is only a safety net in case the ignore list changes
|
||||
* without a full remote discovery being triggered. */
|
||||
CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx->excludes, st->path, st->type);
|
||||
if (excluded != CSYNC_NOT_EXCLUDED) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", st->path, excluded);
|
||||
|
||||
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
|
||||
|| excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
|
||||
csync_file_stat_free(st);
|
||||
continue;
|
||||
}
|
||||
|
||||
st->instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
}
|
||||
|
||||
/* store into result list. */
|
||||
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
break;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
} while( rc == SQLITE_ROW );
|
||||
|
||||
ctx->statedb.lastReturnValue = rc;
|
||||
if( rc != SQLITE_DONE ) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* query the statedb, caller must free the memory */
|
||||
c_strlist_t *csync_statedb_query(sqlite3 *db,
|
||||
const char *statement) {
|
||||
int err = SQLITE_OK;
|
||||
int rc = SQLITE_OK;
|
||||
size_t i = 0;
|
||||
size_t busy_count = 0;
|
||||
size_t retry_count = 0;
|
||||
size_t column_count = 0;
|
||||
sqlite3_stmt *stmt;
|
||||
const char *tail = NULL;
|
||||
const char *field = NULL;
|
||||
c_strlist_t *result = NULL;
|
||||
int row = 0;
|
||||
|
||||
do {
|
||||
/* compile SQL program into a virtual machine, reattempteing if busy */
|
||||
do {
|
||||
if (busy_count) {
|
||||
csync_sleep(100);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count);
|
||||
}
|
||||
err = sqlite3_prepare(db, statement, -1, &stmt, &tail);
|
||||
} while (err == SQLITE_BUSY && busy_count ++ < 120);
|
||||
|
||||
if (err != SQLITE_OK) {
|
||||
if (err == SQLITE_BUSY) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear");
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
|
||||
"sqlite3_compile error: %s - on query %s",
|
||||
sqlite3_errmsg(db), statement);
|
||||
break;
|
||||
} else {
|
||||
busy_count = 0;
|
||||
column_count = sqlite3_column_count(stmt);
|
||||
|
||||
/* execute virtual machine by iterating over rows */
|
||||
for(;;) {
|
||||
err = sqlite3_step(stmt);
|
||||
|
||||
if (err == SQLITE_BUSY) {
|
||||
if (busy_count++ > 120) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
|
||||
break;
|
||||
}
|
||||
csync_sleep(100);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err == SQLITE_MISUSE) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!");
|
||||
}
|
||||
|
||||
if (err == SQLITE_DONE) {
|
||||
if (result == NULL) {
|
||||
result = c_strlist_new(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == SQLITE_ERROR) {
|
||||
break;
|
||||
}
|
||||
|
||||
row++;
|
||||
if( result ) {
|
||||
result = c_strlist_expand(result, row*column_count);
|
||||
} else {
|
||||
result = c_strlist_new(column_count);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* iterate over columns */
|
||||
for (i = 0; i < column_count; i++) {
|
||||
field = (const char *) sqlite3_column_text(stmt, i);
|
||||
if (!field)
|
||||
field = "";
|
||||
// CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", field);
|
||||
if (c_strlist_add(result, field) < 0) {
|
||||
c_strlist_destroy(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} /* end infinite for loop */
|
||||
|
||||
/* deallocate vm resources */
|
||||
rc = sqlite3_finalize(stmt);
|
||||
|
||||
if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(db), statement);
|
||||
if (result != NULL) {
|
||||
c_strlist_destroy(result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rc == SQLITE_SCHEMA) {
|
||||
retry_count ++;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement);
|
||||
if (retry_count < 10) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now.");
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement);
|
||||
if (result != NULL) {
|
||||
c_strlist_destroy(result);
|
||||
}
|
||||
result = c_strlist_new(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (rc == SQLITE_SCHEMA && retry_count < 10);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* vim: set ts=8 sw=2 et cindent: */
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync_private.h
|
||||
*
|
||||
* @brief Private interface of csync
|
||||
*
|
||||
* @defgroup csyncstatedbInternals csync statedb internals
|
||||
* @ingroup csyncInternalAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_STATEDB_H
|
||||
#define _CSYNC_STATEDB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
|
||||
void csync_set_statedb_exists(CSYNC *ctx, int val);
|
||||
|
||||
int csync_get_statedb_exists(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Load the statedb.
|
||||
*
|
||||
* This function tries to load the statedb. If it doesn't exists it creates
|
||||
* the sqlite3 database, but doesn't create the tables. This will be done when
|
||||
* csync gets destroyed.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
* @param statedb Path to the statedb file (sqlite3 db).
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred with errno set.
|
||||
*/
|
||||
OCSYNC_EXPORT int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||
|
||||
OCSYNC_EXPORT int csync_statedb_close(CSYNC *ctx);
|
||||
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
||||
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
||||
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
||||
|
||||
/**
|
||||
* @brief Query all files metadata inside and below a path.
|
||||
* @param ctx The csync context.
|
||||
* @param path The path.
|
||||
*
|
||||
* This function queries all metadata of all files inside or below the
|
||||
* given path. The result is a linear string list with a multiple of 9
|
||||
* entries. For each result file there are 9 strings which are phash,
|
||||
* path, inode, uid, gid, mode, modtime, type and md5 (unique id).
|
||||
*
|
||||
* Note that not only the files in the given path are part of the result
|
||||
* but also the files in directories below the given path. Ie. if the
|
||||
* parameter path is /home/kf/test, we have /home/kf/test/file.txt in
|
||||
* the result but also /home/kf/test/homework/another_file.txt
|
||||
*
|
||||
* @return A stringlist containing a multiple of 9 entries.
|
||||
*/
|
||||
int csync_statedb_get_below_path(CSYNC *ctx, const char *path);
|
||||
|
||||
/**
|
||||
* @brief A generic statedb query.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
* @param statement The SQL statement to execute
|
||||
*
|
||||
* @return A stringlist of the entries of a column. An emtpy stringlist if
|
||||
* nothing has been found. NULL on error.
|
||||
*/
|
||||
c_strlist_t *csync_statedb_query(sqlite3 *db, const char *statement);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_STATEDB_H */
|
||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "csync_time.h"
|
||||
#include "vio/csync_vio.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.time"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
# ifdef _POSIX_MONOTONIC_CLOCK
|
||||
# define CSYNC_CLOCK CLOCK_MONOTONIC
|
||||
# else
|
||||
# define CSYNC_CLOCK CLOCK_REALTIME
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
int csync_gettime(struct timespec *tp)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
__int64 wintime;
|
||||
GetSystemTimeAsFileTime((FILETIME*)&wintime);
|
||||
wintime -= 116444736000000000ll; //1jan1601 to 1jan1970
|
||||
tp->tv_sec = wintime / 10000000ll; //seconds
|
||||
tp->tv_nsec = wintime % 10000000ll * 100; //nano-seconds
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
return clock_gettime(CSYNC_CLOCK, tp);
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
if (gettimeofday(&tv, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_nsec = tv.tv_usec * 1000;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef CSYNC_CLOCK
|
||||
|
||||
void csync_sleep(unsigned int msecs)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
Sleep(msecs);
|
||||
#else
|
||||
usleep(msecs * 1000);
|
||||
#endif
|
||||
}
|
||||
@@ -1,852 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "c_jhash.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_exclude.h"
|
||||
#include "csync_statedb.h"
|
||||
#include "csync_update.h"
|
||||
#include "csync_util.h"
|
||||
#include "csync_misc.h"
|
||||
|
||||
#include "vio/csync_vio.h"
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.updater"
|
||||
#include "csync_log.h"
|
||||
#include "csync_rename.h"
|
||||
|
||||
/* calculate the hash of a given uri */
|
||||
static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
|
||||
const char *path;
|
||||
int len;
|
||||
uint64_t h = 0;
|
||||
|
||||
if( ctx && file ) {
|
||||
path = file;
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
if (strlen(path) <= strlen(ctx->local.uri)) {
|
||||
return 0;
|
||||
}
|
||||
path += strlen(ctx->local.uri) + 1;
|
||||
}
|
||||
len = strlen(path);
|
||||
h = c_jhash64((uint8_t *) path, len, 0);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
#ifdef NO_RENAME_EXTENSION
|
||||
/* Return true if the two path have the same extension. false otherwise. */
|
||||
static bool _csync_sameextension(const char *p1, const char *p2) {
|
||||
/* Find pointer to the extensions */
|
||||
const char *e1 = strrchr(p1, '.');
|
||||
const char *e2 = strrchr(p2, '.');
|
||||
|
||||
/* If the found extension contains a '/', it is because the . was in the folder name
|
||||
* => no extensions */
|
||||
if (e1 && strchr(e1, '/')) e1 = NULL;
|
||||
if (e2 && strchr(e2, '/')) e2 = NULL;
|
||||
|
||||
/* If none have extension, it is the same extension */
|
||||
if (!e1 && !e2)
|
||||
return true;
|
||||
|
||||
/* c_streq takes care of the rest */
|
||||
return c_streq(e1, e2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool _last_db_return_error(CSYNC* ctx) {
|
||||
return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW;
|
||||
}
|
||||
|
||||
/*
|
||||
* This static method is needed because the type members of the two structs use
|
||||
* different enum values. A direct comparion is not neccessarily correct.
|
||||
*
|
||||
* tmp is csync_file_stat_t
|
||||
* fs is csync_vio_file_stat_t with this vio type:
|
||||
* enum csync_vio_file_type_e {
|
||||
* CSYNC_VIO_FILE_TYPE_UNKNOWN,
|
||||
* CSYNC_VIO_FILE_TYPE_REGULAR,
|
||||
* CSYNC_VIO_FILE_TYPE_DIRECTORY,
|
||||
* CSYNC_VIO_FILE_TYPE_FIFO,
|
||||
* CSYNC_VIO_FILE_TYPE_SOCKET,
|
||||
* CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE,
|
||||
* CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE,
|
||||
* CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK
|
||||
* };
|
||||
*
|
||||
* csync_file_stat_t can be:
|
||||
* CSYNC_FTW_TYPE_SKIP, CSYNC_FTW_TYPE_FILE
|
||||
* CSYNC_FTW_TYPE_DIR, CSYNC_FTW_TYPE_SLINK
|
||||
*/
|
||||
static bool _csync_filetype_different( const csync_file_stat_t *tmp, const csync_vio_file_stat_t *fs)
|
||||
{
|
||||
if( !(tmp && fs)) return false;
|
||||
|
||||
if( tmp->type == CSYNC_FTW_TYPE_SKIP ) return true;
|
||||
|
||||
if( tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY )
|
||||
return true;
|
||||
if( tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR )
|
||||
return true;
|
||||
if( tmp->type == CSYNC_FTW_TYPE_SLINK && fs->type != CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK )
|
||||
return true;
|
||||
|
||||
return false; // both are NOT different.
|
||||
}
|
||||
|
||||
/* Return true if two mtime are considered equal
|
||||
* We consider mtime that are one hour difference to be equal if they are one hour appart
|
||||
* because on some system (FAT) the date is changing when the daylight saving is changing */
|
||||
static bool _csync_mtime_equal(time_t a, time_t b)
|
||||
{
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
/* 1h of difference +- 1 second because the accuracy of FAT is 2 seconds (#2438) */
|
||||
if (fabs(3600 - fabs(difftime(a, b))) < 2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main function of the discovery/update pass.
|
||||
*
|
||||
* It's called (indirectly) by csync_update(), once for each entity in the
|
||||
* local filesystem and once for each entity in the server data.
|
||||
*
|
||||
* It has two main jobs:
|
||||
* - figure out whether anything happened compared to the sync journal
|
||||
* and set (primarily) the instruction flag accordingly
|
||||
* - build the ctx->local.tree / ctx->remote.tree
|
||||
*
|
||||
* See doc/dev/sync-algorithm.md for an overview.
|
||||
*/
|
||||
static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
const csync_vio_file_stat_t *fs, const int type) {
|
||||
uint64_t h = 0;
|
||||
size_t len = 0;
|
||||
size_t size = 0;
|
||||
const char *path = NULL;
|
||||
csync_file_stat_t *st = NULL;
|
||||
csync_file_stat_t *tmp = NULL;
|
||||
CSYNC_EXCLUDE_TYPE excluded;
|
||||
|
||||
if ((file == NULL) || (fs == NULL)) {
|
||||
errno = EINVAL;
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
path = file;
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
if (strlen(path) <= strlen(ctx->local.uri)) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
path += strlen(ctx->local.uri) + 1;
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
if (type == CSYNC_FTW_TYPE_SKIP) {
|
||||
excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
|
||||
} else {
|
||||
/* Check if file is excluded */
|
||||
excluded = csync_excluded_traversal(ctx->excludes, path, type);
|
||||
}
|
||||
|
||||
if( excluded == CSYNC_NOT_EXCLUDED ) {
|
||||
/* Even if it is not excluded by a pattern, maybe it is to be ignored
|
||||
* because it's a hidden file that should not be synced.
|
||||
* This code should probably be in csync_exclude, but it does not have the fs parameter.
|
||||
* Keep it here for now */
|
||||
if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
|
||||
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
|
||||
}
|
||||
} else {
|
||||
/* File is ignored because it's matched by a user- or system exclude pattern. */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded);
|
||||
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
|
||||
return 1;
|
||||
}
|
||||
if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
|
||||
if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
h = _hash_of_file(ctx, file );
|
||||
if( h == 0 ) {
|
||||
return -1;
|
||||
}
|
||||
size = sizeof(csync_file_stat_t) + len + 1;
|
||||
|
||||
st = c_malloc(size);
|
||||
|
||||
/* Set instruction by default to none */
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
st->etag = NULL;
|
||||
st->child_modified = 0;
|
||||
st->has_ignored_files = 0;
|
||||
if (type == CSYNC_FTW_TYPE_FILE ) {
|
||||
if (fs->mtime == 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
|
||||
}
|
||||
}
|
||||
|
||||
if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
|
||||
st->instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
if (ctx->current_fs) {
|
||||
ctx->current_fs->has_ignored_files = true;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Update detection: Check if a database entry exists.
|
||||
* If not, the file is either new or has been renamed. To see if it is
|
||||
* renamed, the db gets queried by the inode of the file as that one
|
||||
* does not change on rename.
|
||||
*/
|
||||
if (csync_get_statedb_exists(ctx)) {
|
||||
tmp = csync_statedb_get_stat_by_hash(ctx, h);
|
||||
|
||||
if(_last_db_return_error(ctx)) {
|
||||
csync_file_stat_free(st);
|
||||
csync_file_stat_free(tmp);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(tmp && tmp->phash == h ) { /* there is an entry in the database */
|
||||
/* we have an update! */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Database entry found, compare: %" PRId64 " <-> %" PRId64
|
||||
", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
|
||||
", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d",
|
||||
((int64_t) fs->mtime), ((int64_t) tmp->modtime),
|
||||
fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
|
||||
(uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
|
||||
if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||
|
||||
// Preserve the EVAL flag later on if the type has changed.
|
||||
if (_csync_filetype_different(tmp, fs)) {
|
||||
st->child_modified = 1;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
if (ctx->current == LOCAL_REPLICA &&
|
||||
(!_csync_mtime_equal(fs->mtime, tmp->modtime)
|
||||
// zero size in statedb can happen during migration
|
||||
|| (tmp->size != 0 && fs->size != tmp->size))) {
|
||||
|
||||
// Checksum comparison at this stage is only enabled for .eml files,
|
||||
// check #4754 #4755
|
||||
bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
|
||||
if (isEmlFile && fs->size == tmp->size && tmp->checksumTypeId) {
|
||||
if (ctx->callbacks.checksum_hook) {
|
||||
st->checksum = ctx->callbacks.checksum_hook(
|
||||
file, tmp->checksumTypeId,
|
||||
ctx->callbacks.checksum_userdata);
|
||||
}
|
||||
bool checksumIdentical = false;
|
||||
if (st->checksum) {
|
||||
st->checksumTypeId = tmp->checksumTypeId;
|
||||
checksumIdentical = strncmp(st->checksum, tmp->checksum, 1000) == 0;
|
||||
}
|
||||
if (checksumIdentical) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
|
||||
st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve the EVAL flag later on if the type has changed.
|
||||
if (_csync_filetype_different(tmp, fs)) {
|
||||
st->child_modified = 1;
|
||||
}
|
||||
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||
goto out;
|
||||
}
|
||||
bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
|
||||
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|
||||
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
|
||||
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
|
||||
&& !metadata_differ && ctx->read_remote_from_db) {
|
||||
/* If both etag and file id are equal for a directory, read all contents from
|
||||
* the database.
|
||||
* The metadata comparison ensure that we fetch all the file id or permission when
|
||||
* upgrading owncloud
|
||||
*/
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
|
||||
ctx->remote.read_from_db = true;
|
||||
}
|
||||
/* If it was remembered in the db that the remote dir has ignored files, store
|
||||
* that so that the reconciler can make advantage of.
|
||||
*/
|
||||
if( ctx->current == REMOTE_REPLICA ) {
|
||||
st->has_ignored_files = tmp->has_ignored_files;
|
||||
}
|
||||
if (metadata_differ) {
|
||||
/* file id or permissions has changed. Which means we need to update them in the DB. */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
|
||||
st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
} else {
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
} else {
|
||||
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
|
||||
/* tmp might point to malloc mem, so free it here before reusing tmp */
|
||||
csync_file_stat_free(tmp);
|
||||
|
||||
/* check if it's a file and has been renamed */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
|
||||
|
||||
tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
|
||||
|
||||
if(_last_db_return_error(ctx)) {
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* translate the file type between the two stat types csync has. */
|
||||
if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) {
|
||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
} else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) {
|
||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
|
||||
} else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) {
|
||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
|
||||
} else {
|
||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
// Default to NEW unless we're sure it's a rename.
|
||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
|
||||
bool isRename =
|
||||
tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
|
||||
&& (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
|
||||
#ifdef NO_RENAME_EXTENSION
|
||||
&& _csync_sameextension(tmp->path, path)
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
// Verify the checksum where possible
|
||||
if (isRename && tmp->checksumTypeId && ctx->callbacks.checksum_hook
|
||||
&& fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) {
|
||||
st->checksum = ctx->callbacks.checksum_hook(
|
||||
file, tmp->checksumTypeId,
|
||||
ctx->callbacks.checksum_userdata);
|
||||
if (st->checksum) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksum, tmp->checksum);
|
||||
st->checksumTypeId = tmp->checksumTypeId;
|
||||
isRename = strncmp(st->checksum, tmp->checksum, 1000) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRename) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
|
||||
/* inode found so the file has been renamed */
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
|
||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
|
||||
csync_rename_record(ctx, tmp->path, path);
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
/* Remote Replica Rename check */
|
||||
tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
|
||||
|
||||
if(_last_db_return_error(ctx)) {
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
if(tmp ) { /* tmp existing at all */
|
||||
if ( _csync_filetype_different(tmp, fs)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: file types different is not!");
|
||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
goto out;
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file);
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
|
||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
|
||||
csync_rename_record(ctx, tmp->path, path);
|
||||
} else {
|
||||
if( !c_streq(tmp->etag, fs->etag) ) {
|
||||
/* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */
|
||||
/* File with different etag, don't do a rename, but download the file again */
|
||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
/* file not found in statedb */
|
||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
|
||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
|
||||
csync_file_stat_free(st);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unable to open statedb" );
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
/* Set the ignored error string. */
|
||||
if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
|
||||
if( type == CSYNC_FTW_TYPE_SLINK ) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
|
||||
} else {
|
||||
if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
|
||||
} else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
|
||||
st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (st->instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& st->instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& type != CSYNC_FTW_TYPE_DIR) {
|
||||
st->child_modified = 1;
|
||||
}
|
||||
ctx->current_fs = st;
|
||||
|
||||
csync_file_stat_free(tmp);
|
||||
st->inode = fs->inode;
|
||||
st->mode = fs->mode;
|
||||
st->size = fs->size;
|
||||
st->modtime = fs->mtime;
|
||||
st->type = type;
|
||||
st->etag = NULL;
|
||||
if( fs->etag ) {
|
||||
SAFE_FREE(st->etag);
|
||||
st->etag = c_strdup(fs->etag);
|
||||
}
|
||||
csync_vio_set_file_id(st->file_id, fs->file_id);
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
|
||||
SAFE_FREE(st->directDownloadUrl);
|
||||
st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
|
||||
}
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
|
||||
SAFE_FREE(st->directDownloadCookies);
|
||||
st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
|
||||
}
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
|
||||
strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
|
||||
}
|
||||
|
||||
st->phash = h;
|
||||
st->pathlen = len;
|
||||
memcpy(st->path, (len ? path : ""), len + 1);
|
||||
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: %s <<=", st->path,
|
||||
csync_instruction_str(st->instruction));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
|
||||
enum csync_ftw_flags_e flag) {
|
||||
int rc = -1;
|
||||
int type = CSYNC_FTW_TYPE_SKIP;
|
||||
csync_file_stat_t *st = NULL;
|
||||
uint64_t h;
|
||||
|
||||
if (ctx->abort) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
|
||||
ctx->status_code = CSYNC_STATUS_ABORTED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (flag) {
|
||||
case CSYNC_FTW_FLAG_FILE:
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size);
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=UNKNOWN]", file, fs->file_id);
|
||||
}
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size);
|
||||
}
|
||||
type = CSYNC_FTW_TYPE_FILE;
|
||||
break;
|
||||
case CSYNC_FTW_FLAG_DIR: /* enter directory */
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id);
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode);
|
||||
}
|
||||
type = CSYNC_FTW_TYPE_DIR;
|
||||
break;
|
||||
case CSYNC_FTW_FLAG_NSTAT: /* not statable file */
|
||||
/* if file was here before and now is not longer stat-able, still
|
||||
* add it to the db, otherwise not. */
|
||||
h = _hash_of_file( ctx, file );
|
||||
if( h == 0 ) {
|
||||
return 0;
|
||||
}
|
||||
st = csync_statedb_get_stat_by_hash(ctx, h);
|
||||
if( !st ) {
|
||||
return 0;
|
||||
}
|
||||
csync_file_stat_free(st);
|
||||
st = NULL;
|
||||
|
||||
type = CSYNC_FTW_TYPE_SKIP;
|
||||
break;
|
||||
case CSYNC_FTW_FLAG_SLINK:
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file);
|
||||
type = CSYNC_FTW_TYPE_SLINK;
|
||||
break;
|
||||
case CSYNC_FTW_FLAG_DNR:
|
||||
case CSYNC_FTW_FLAG_DP:
|
||||
case CSYNC_FTW_FLAG_SLN:
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = _csync_detect_update(ctx, file, fs, type );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
|
||||
{
|
||||
if( csync_statedb_get_below_path(ctx, uri) < 0 ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* set the current item to an ignored state.
|
||||
* If the item is set to ignored, the update phase continues, ie. its not a hard error */
|
||||
static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status )
|
||||
{
|
||||
if(!ctx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->current_fs) {
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
ctx->current_fs->error_status = status;
|
||||
/* If a directory has ignored files, put the flag on the parent directory as well */
|
||||
if( previous_fs ) {
|
||||
previous_fs->has_ignored_files = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* File tree walker */
|
||||
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
unsigned int depth) {
|
||||
char *filename = NULL;
|
||||
char *d_name = NULL;
|
||||
csync_vio_handle_t *dh = NULL;
|
||||
csync_vio_file_stat_t *dirent = NULL;
|
||||
csync_file_stat_t *previous_fs = NULL;
|
||||
int read_from_db = 0;
|
||||
int rc = 0;
|
||||
int res = 0;
|
||||
|
||||
bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
|
||||
|
||||
read_from_db = ctx->remote.read_from_db;
|
||||
|
||||
// if the etag of this dir is still the same, its content is restored from the
|
||||
// database.
|
||||
if( do_read_from_db ) {
|
||||
if( ! fill_tree_from_db(ctx, uri) ) {
|
||||
errno = ENOENT;
|
||||
ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR;
|
||||
goto error;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((dh = csync_vio_opendir(ctx, uri)) == NULL) {
|
||||
if (ctx->abort) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
|
||||
ctx->status_code = CSYNC_STATUS_ABORTED;
|
||||
goto error;
|
||||
}
|
||||
int asp = 0;
|
||||
/* permission denied */
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
|
||||
if (errno == EACCES) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied.");
|
||||
if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) {
|
||||
goto done;
|
||||
}
|
||||
} else if(errno == ENOENT) {
|
||||
asp = asprintf( &ctx->error_string, "%s", uri);
|
||||
if (asp < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
|
||||
}
|
||||
}
|
||||
// 403 Forbidden can be sent by the server if the file firewall is active.
|
||||
// A file or directory should be ignored and sync must continue. See #3490
|
||||
else if(errno == ERRNO_FORBIDDEN) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)");
|
||||
if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) {
|
||||
goto done;
|
||||
}
|
||||
/* if current_fs is not defined here, better throw an error */
|
||||
}
|
||||
// The server usually replies with the custom "503 Storage not available"
|
||||
// if some path is temporarily unavailable. But in some cases a standard 503
|
||||
// is returned too. Thus we can't distinguish the two and will treat any
|
||||
// 503 as request to ignore the folder. See #3113 #2884.
|
||||
else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
|
||||
if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) {
|
||||
goto done;
|
||||
}
|
||||
/* if current_fs is not defined here, better throw an error */
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ((dirent = csync_vio_readdir(ctx, dh))) {
|
||||
int flen;
|
||||
int flag;
|
||||
|
||||
/* Conversion error */
|
||||
if (dirent->name == NULL && dirent->original_name) {
|
||||
ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
|
||||
ctx->error_string = dirent->original_name; // take ownership
|
||||
dirent->original_name = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
d_name = dirent->name;
|
||||
if (d_name == NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_READDIR_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* skip "." and ".." */
|
||||
if ( (d_name[0] == '.' && d_name[1] == '\0')
|
||||
|| (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uri[0] == '\0') {
|
||||
filename = c_strdup(d_name);
|
||||
flen = strlen(d_name);
|
||||
} else {
|
||||
flen = asprintf(&filename, "%s/%s", uri, d_name);
|
||||
}
|
||||
if (flen < 0 || !filename) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Only for the local replica we have to stat(), for the remote one we have all data already */
|
||||
if (ctx->replica == LOCAL_REPLICA) {
|
||||
res = csync_vio_stat(ctx, filename, dirent);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
|
||||
/* if the filename starts with a . we consider it a hidden file
|
||||
* For windows, the hidden state is also discovered within the vio
|
||||
* local stat function.
|
||||
*/
|
||||
if( d_name[0] == '.' ) {
|
||||
if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */
|
||||
dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
if( res == 0) {
|
||||
switch (dirent->type) {
|
||||
case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
|
||||
flag = CSYNC_FTW_FLAG_SLINK;
|
||||
break;
|
||||
case CSYNC_VIO_FILE_TYPE_DIRECTORY:
|
||||
flag = CSYNC_FTW_FLAG_DIR;
|
||||
break;
|
||||
case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE:
|
||||
case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE:
|
||||
case CSYNC_VIO_FILE_TYPE_SOCKET:
|
||||
flag = CSYNC_FTW_FLAG_SPEC;
|
||||
break;
|
||||
case CSYNC_VIO_FILE_TYPE_FIFO:
|
||||
flag = CSYNC_FTW_FLAG_SPEC;
|
||||
break;
|
||||
default:
|
||||
flag = CSYNC_FTW_FLAG_FILE;
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
flag = CSYNC_FTW_FLAG_NSTAT;
|
||||
}
|
||||
|
||||
previous_fs = ctx->current_fs;
|
||||
|
||||
/* Call walker function for each file */
|
||||
rc = fn(ctx, filename, dirent, flag);
|
||||
/* this function may update ctx->current and ctx->read_from_db */
|
||||
|
||||
if (rc < 0) {
|
||||
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
||||
ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
|
||||
}
|
||||
|
||||
ctx->current_fs = previous_fs;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (flag == CSYNC_FTW_FLAG_DIR && depth && rc == 0
|
||||
&& (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) {
|
||||
rc = csync_ftw(ctx, filename, fn, depth - 1);
|
||||
if (rc < 0) {
|
||||
ctx->current_fs = previous_fs;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ctx->current_fs && !ctx->current_fs->child_modified
|
||||
&& ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
} else {
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) {
|
||||
/* If a directory has ignored files, put the flag on the parent directory as well */
|
||||
previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) {
|
||||
/* If a directory has modified files, put the flag on the parent directory as well */
|
||||
previous_fs->child_modified = ctx->current_fs->child_modified;
|
||||
}
|
||||
|
||||
ctx->current_fs = previous_fs;
|
||||
ctx->remote.read_from_db = read_from_db;
|
||||
SAFE_FREE(filename);
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
}
|
||||
|
||||
csync_vio_closedir(ctx, dh);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db);
|
||||
|
||||
done:
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
SAFE_FREE(filename);
|
||||
return rc;
|
||||
error:
|
||||
ctx->remote.read_from_db = read_from_db;
|
||||
if (dh != NULL) {
|
||||
csync_vio_closedir(ctx, dh);
|
||||
}
|
||||
SAFE_FREE(filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* vim: set ts=8 sw=2 et cindent: */
|
||||
@@ -1,47 +0,0 @@
|
||||
project(cstdlib C)
|
||||
|
||||
set(CSTDLIB_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
CACHE INTERNAL "cstdlib public include directories"
|
||||
)
|
||||
|
||||
set(CSTDLIB_PRIVATE_INCLUDE_DIRS
|
||||
${ICONV_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(CSTDLIB_LIBRARY
|
||||
cstdlib
|
||||
CACHE INTERNAL "cstdlib library"
|
||||
)
|
||||
|
||||
set(CSTDLIB_LINK_LIBRARIES
|
||||
${CSTDLIB_LIBRARY}
|
||||
)
|
||||
|
||||
set(cstdlib_SRCS
|
||||
c_alloc.c
|
||||
c_path.c
|
||||
c_rbtree.c
|
||||
c_string.c
|
||||
c_time.c
|
||||
)
|
||||
|
||||
if(NOT HAVE_ASPRINTF AND NOT HAVE___MINGW_ASPRINTF)
|
||||
list(APPEND cstdlib_SRCS
|
||||
asprintf.c
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CSTDLIB_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(${CSTDLIB_LIBRARY} STATIC ${cstdlib_SRCS})
|
||||
if(NOT WIN32)
|
||||
add_definitions( -fPIC )
|
||||
endif()
|
||||
if(NOT HAVE_FNMATCH AND WIN32)
|
||||
# needed for PathMatchSpec for our fnmatch replacement
|
||||
target_link_libraries(${CSTDLIB_LIBRARY} ${SHLWAPI_LIBRARY})
|
||||
endif()
|
||||
@@ -1,451 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "c_private.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_path.h"
|
||||
#include "c_string.h"
|
||||
|
||||
/*
|
||||
* dirname - parse directory component.
|
||||
*/
|
||||
char *c_dirname (const char *path) {
|
||||
char *newbuf = NULL;
|
||||
unsigned int len;
|
||||
|
||||
if (path == NULL || *path == '\0') {
|
||||
return c_strdup(".");
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
/* Remove trailing slashes */
|
||||
while(len > 0 && path[len - 1] == '/') --len;
|
||||
|
||||
/* We have only slashes */
|
||||
if (len == 0) {
|
||||
return c_strdup("/");
|
||||
}
|
||||
|
||||
/* goto next slash */
|
||||
while(len > 0 && path[len - 1] != '/') --len;
|
||||
|
||||
if (len == 0) {
|
||||
return c_strdup(".");
|
||||
} else if (len == 1) {
|
||||
return c_strdup("/");
|
||||
}
|
||||
|
||||
/* Remove slashes again */
|
||||
while(len > 0 && path[len - 1] == '/') --len;
|
||||
|
||||
newbuf = c_malloc(len + 1);
|
||||
|
||||
strncpy(newbuf, path, len);
|
||||
newbuf[len] = '\0';
|
||||
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
char *c_basename (const char *path) {
|
||||
char *newbuf = NULL;
|
||||
const char *s;
|
||||
unsigned int len;
|
||||
|
||||
if (path == NULL || *path == '\0') {
|
||||
return c_strdup(".");
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
/* Remove trailing slashes */
|
||||
while(len > 0 && path[len - 1] == '/') --len;
|
||||
|
||||
/* We have only slashes */
|
||||
if (len == 0) {
|
||||
return c_strdup("/");
|
||||
}
|
||||
|
||||
while(len > 0 && path[len - 1] != '/') --len;
|
||||
|
||||
if (len > 0) {
|
||||
s = path + len;
|
||||
len = strlen(s);
|
||||
|
||||
while(len > 0 && s[len - 1] == '/') --len;
|
||||
} else {
|
||||
return c_strdup(path);
|
||||
}
|
||||
|
||||
newbuf = c_malloc(len + 1);
|
||||
|
||||
strncpy(newbuf, s, len);
|
||||
newbuf[len] = '\0';
|
||||
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
int c_parse_uri(const char *uri,
|
||||
char **scheme,
|
||||
char **user, char **passwd,
|
||||
char **host, unsigned int *port,
|
||||
char **path) {
|
||||
const char *p, *z;
|
||||
|
||||
if (uri == NULL || *uri == '\0') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p = z = uri;
|
||||
|
||||
/* check for valid scheme; git+ssh, pop3 */
|
||||
while (isalpha((int) *p) || isdigit((int) *p) ||
|
||||
*p == '+' || *p == '-') {
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p++;
|
||||
}
|
||||
|
||||
/* get scheme */
|
||||
if (*p == ':') {
|
||||
if (scheme != NULL) {
|
||||
*scheme = c_strndup(z, p - z);
|
||||
|
||||
if (*scheme == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
z = p;
|
||||
}
|
||||
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p = z;
|
||||
|
||||
/* do we have a hostname */
|
||||
if (p[0] == '/' && p[1] == '/') {
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
z += 2;
|
||||
p = z;
|
||||
|
||||
/* check for user and passwd */
|
||||
while (*p && *p != '@' && *p != '/') {
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^ or ^
|
||||
* z = ^
|
||||
*/
|
||||
p++;
|
||||
}
|
||||
|
||||
/* check for user and password */
|
||||
if (*p == '@') {
|
||||
const char *q;
|
||||
|
||||
q = p;
|
||||
|
||||
/* check if we have a password */
|
||||
while (q > z && *q != ':') {
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
* q = ^
|
||||
*/
|
||||
q--;
|
||||
}
|
||||
|
||||
/* password found */
|
||||
if (*q == ':') {
|
||||
if (user != NULL) {
|
||||
*user = c_strndup(z, q - z);
|
||||
if (*user == NULL) {
|
||||
errno = ENOMEM;
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (passwd != NULL) {
|
||||
*passwd = c_strndup(q + 1, p - (q + 1));
|
||||
if (*passwd == NULL) {
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
if (user != NULL) SAFE_FREE(*user);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* user only */
|
||||
if (user != NULL) {
|
||||
*user = c_strndup(z, p - z);
|
||||
if( *user == NULL) {
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p++;
|
||||
z = p;
|
||||
}
|
||||
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p = z;
|
||||
|
||||
/* check for IPv6 address */
|
||||
if (*p == '[') {
|
||||
/*
|
||||
* uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p++;
|
||||
|
||||
/* check if we have a valid IPv6 address */
|
||||
while (*p && (isxdigit((int) *p) || *p == '.' || *p == ':')) {
|
||||
/*
|
||||
* uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p++;
|
||||
}
|
||||
|
||||
/* valid IPv6 address found */
|
||||
if (*p == ']') {
|
||||
/*
|
||||
* uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
z++;
|
||||
|
||||
if (host != NULL) {
|
||||
*host = c_strndup(z, p - z);
|
||||
if (*host == NULL) {
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
if (user != NULL) SAFE_FREE(*user);
|
||||
if (passwd != NULL) SAFE_FREE(*passwd);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
p++;
|
||||
} else {
|
||||
/* invalid IPv6 address, assume a hostname */
|
||||
p = z;
|
||||
|
||||
while (*p && *p != ':' && *p != '/') {
|
||||
p++;
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^ or ^
|
||||
* z = ^
|
||||
*/
|
||||
}
|
||||
|
||||
if (host != NULL) {
|
||||
*host = c_strndup(z, p - z);
|
||||
if (*host == NULL) {
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
if (user != NULL) SAFE_FREE(*user);
|
||||
if (passwd != NULL) SAFE_FREE(*passwd);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* check for hostname */
|
||||
while (*p && *p != ':' && *p != '/') {
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^ ^
|
||||
* z = ^
|
||||
*/
|
||||
p++;
|
||||
}
|
||||
|
||||
if (host != NULL) {
|
||||
*host = c_strndup(z, p - z);
|
||||
if (*host == NULL) {
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
if (user != NULL) SAFE_FREE(*user);
|
||||
if (passwd != NULL) SAFE_FREE(*passwd);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check for port */
|
||||
if (*p == ':') {
|
||||
char **e = NULL;
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
z = ++p;
|
||||
|
||||
/* get only the digits */
|
||||
while (isdigit((int) *p)) {
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
* z = ^
|
||||
*/
|
||||
e = (char **) &p;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (port != NULL) {
|
||||
*port = strtoul(z, e, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* uri = scheme://user:password@host:port/path
|
||||
* p = ^
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the path with the leading slash */
|
||||
if (*p == '/') {
|
||||
if (path != NULL) {
|
||||
*path = c_strdup(p);
|
||||
if (*path == NULL) {
|
||||
if (scheme != NULL) SAFE_FREE(*scheme);
|
||||
if (user != NULL) SAFE_FREE(*user);
|
||||
if (passwd != NULL) SAFE_FREE(*passwd);
|
||||
if (host != NULL) SAFE_FREE(*host);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function takes a path and converts it to a UNC representation of the
|
||||
* string. That means that it prepends a \\?\ (unless already UNC) and converts
|
||||
* all slashes to backslashes.
|
||||
*
|
||||
* Note the following:
|
||||
* - The string must be absolute.
|
||||
* - it needs to contain a drive character to be a valid UNC
|
||||
* - A conversion is only done if the path len is larger than 245. Otherwise
|
||||
* the windows API functions work with the normal "unixoid" representation too.
|
||||
*
|
||||
* This function allocates memory that must be freed by the caller.
|
||||
*/
|
||||
const char *c_path_to_UNC(const char *str)
|
||||
{
|
||||
int len = 0;
|
||||
char *longStr = NULL;
|
||||
|
||||
len = strlen(str);
|
||||
longStr = c_malloc(len+5);
|
||||
*longStr = '\0';
|
||||
|
||||
// prepend \\?\ and convert '/' => '\' to support long names
|
||||
if( str[0] == '/' || str[0] == '\\' ) {
|
||||
// Don't prepend if already UNC
|
||||
if( !(len > 1 && (str[1] == '/' || str[1] == '\\')) ) {
|
||||
strcpy( longStr, "\\\\?");
|
||||
}
|
||||
} else {
|
||||
strcpy( longStr, "\\\\?\\"); // prepend string by this four magic chars.
|
||||
}
|
||||
strncat( longStr, str, len );
|
||||
|
||||
/* replace all occurences of / with the windows native \ */
|
||||
char *c = longStr;
|
||||
for (; *c; ++c) {
|
||||
if(*c == '/') {
|
||||
*c = '\\';
|
||||
}
|
||||
}
|
||||
return longStr;
|
||||
}
|
||||
|
||||
mbchar_t* c_utf8_path_to_locale(const char *str)
|
||||
{
|
||||
if( str == NULL ) {
|
||||
return NULL;
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
const char *unc_str = c_path_to_UNC(str);
|
||||
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
|
||||
SAFE_FREE(unc_str);
|
||||
return dst;
|
||||
#else
|
||||
return c_utf8_string_to_locale(str);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_path.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc path functions
|
||||
*
|
||||
* @defgroup cynPathInternals cynapses libc path functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_PATH_H
|
||||
#define _C_PATH_H
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_private.h"
|
||||
|
||||
/**
|
||||
* @brief Parse directory component.
|
||||
*
|
||||
* dirname breaks a null-terminated pathname string into a directory component.
|
||||
* In the usual case, c_dirname() returns the string up to, but not including,
|
||||
* the final '/'. Trailing '/' characters are not counted as part of the
|
||||
* pathname. The caller must free the memory.
|
||||
*
|
||||
* @param path The path to parse.
|
||||
*
|
||||
* @return The dirname of path or NULL if we can't allocate memory. If path
|
||||
* does not contain a slash, c_dirname() returns the string ".". If
|
||||
* path is the string "/", it returns the string "/". If path is
|
||||
* NULL or an empty string, "." is returned.
|
||||
*/
|
||||
char *c_dirname(const char *path);
|
||||
|
||||
/**
|
||||
* @brief basename - parse filename component.
|
||||
*
|
||||
* basename breaks a null-terminated pathname string into a filename component.
|
||||
* c_basename() returns the component following the final '/'. Trailing '/'
|
||||
* characters are not counted as part of the pathname.
|
||||
*
|
||||
* @param path The path to parse.
|
||||
*
|
||||
* @return The filename of path or NULL if we can't allocate memory. If path
|
||||
* is a the string "/", basename returns the string "/". If path is
|
||||
* NULL or an empty string, "." is returned.
|
||||
*/
|
||||
char *c_basename (const char *path);
|
||||
|
||||
/**
|
||||
* @brief parse a uri and split it into components.
|
||||
*
|
||||
* parse_uri parses an uri in the format
|
||||
*
|
||||
* [<scheme>:][//[<user>[:<password>]@]<host>[:<port>]]/[<path>]
|
||||
*
|
||||
* into its compoments. If you only want a special component,
|
||||
* pass NULL for all other components. All components will be allocated if they have
|
||||
* been found.
|
||||
*
|
||||
* @param uri The uri to parse.
|
||||
* @param scheme String for the scheme component
|
||||
* @param user String for the username component
|
||||
* @param passwd String for the password component
|
||||
* @param host String for the password component
|
||||
* @param port Integer for the port
|
||||
* @param path String for the path component with a leading slash.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int c_parse_uri(const char *uri, char **scheme, char **user, char **passwd,
|
||||
char **host, unsigned int *port, char **path);
|
||||
|
||||
/**
|
||||
* @brief Parts of a path.
|
||||
*
|
||||
* @param directory '\0' terminated path including the final '/'
|
||||
*
|
||||
* @param filename '\0' terminated string
|
||||
*
|
||||
* @param extension '\0' terminated string
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char * directory;
|
||||
char * filename;
|
||||
char * extension;
|
||||
} C_PATHINFO;
|
||||
|
||||
/**
|
||||
* @brief c_path_to_UNC converts a unixoid path to UNC format.
|
||||
*
|
||||
* It converts the '/' to '\' and prepends \\?\ to the path.
|
||||
*
|
||||
* A proper windows path has to have a drive letter, otherwise it is not
|
||||
* valid UNC.
|
||||
*
|
||||
* @param str The path to convert
|
||||
*
|
||||
* @return a pointer to the converted string. Caller has to free it.
|
||||
*/
|
||||
const char *c_path_to_UNC(const char *str);
|
||||
|
||||
/**
|
||||
* @brief c_utf8_path_to_locale converts a unixoid path to the locale aware format
|
||||
*
|
||||
* On windows, it converts to UNC and multibyte.
|
||||
* On Mac, it converts to the correct utf8 using iconv.
|
||||
* On Linux, it returns utf8
|
||||
*
|
||||
* @param str The path to convert
|
||||
*
|
||||
* @return a pointer to the converted string. Caller has to free it using the
|
||||
* function c_free_locale_string.
|
||||
*/
|
||||
mbchar_t* c_utf8_path_to_locale(const char *str);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_PATH_H */
|
||||
@@ -1,743 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2003-2004 by Andrew Suffield <asuffield@debian.org>
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code was originally released under GPL but Andrew Suffield agreed to
|
||||
* change it to LGPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* static function don't have NULL pointer checks, segfaults are intended.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "c_alloc.h"
|
||||
#include "c_rbtree.h"
|
||||
|
||||
#define NIL &_sentinel /* all leafs are sentinels */
|
||||
static c_rbnode_t _sentinel = {NULL, NIL, NIL, NULL, NULL, BLACK};
|
||||
|
||||
void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare) {
|
||||
assert(rbtree);
|
||||
assert(key_compare);
|
||||
assert(data_compare);
|
||||
|
||||
c_rbtree_t *tree = NULL;
|
||||
|
||||
tree = c_malloc(sizeof(*tree));
|
||||
tree->root = NIL;
|
||||
tree->key_compare = key_compare;
|
||||
tree->data_compare = data_compare;
|
||||
tree->size = 0;
|
||||
|
||||
*rbtree = tree;
|
||||
}
|
||||
|
||||
static c_rbnode_t *_rbtree_subtree_dup(const c_rbnode_t *node, c_rbtree_t *new_tree, c_rbnode_t *new_parent) {
|
||||
c_rbnode_t *new_node = NULL;
|
||||
|
||||
new_node = (c_rbnode_t*) c_malloc(sizeof(c_rbnode_t));
|
||||
|
||||
new_node->tree = new_tree;
|
||||
new_node->data = node->data;
|
||||
new_node->color = node->color;
|
||||
new_node->parent = new_parent;
|
||||
|
||||
if (node->left == NIL) {
|
||||
new_node->left = NIL;
|
||||
} else {
|
||||
new_node->left = _rbtree_subtree_dup(node->left, new_tree, new_node);
|
||||
}
|
||||
|
||||
if (node->right == NIL) {
|
||||
new_node->right = NIL;
|
||||
} else {
|
||||
new_node->right = _rbtree_subtree_dup(node->right, new_tree, new_node);
|
||||
}
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree) {
|
||||
c_rbtree_t *new_tree = NULL;
|
||||
|
||||
new_tree = (c_rbtree_t*) c_malloc(sizeof(c_rbtree_t));
|
||||
|
||||
new_tree->key_compare = tree->key_compare;
|
||||
new_tree->data_compare = tree->data_compare;
|
||||
new_tree->size = tree->size;
|
||||
new_tree->root = _rbtree_subtree_dup(tree->root, new_tree, NULL);
|
||||
|
||||
return new_tree;
|
||||
}
|
||||
|
||||
static int _rbtree_subtree_free(c_rbnode_t *node) {
|
||||
assert(node);
|
||||
|
||||
if (node->left != NIL) {
|
||||
if (_rbtree_subtree_free(node->left) < 0) {
|
||||
/* TODO: set errno? ECANCELED? */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->right != NIL) {
|
||||
if (_rbtree_subtree_free(node->right) < 0) {
|
||||
/* TODO: set errno? ECANCELED? */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_rbtree_free(c_rbtree_t *tree) {
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tree->root != NIL) {
|
||||
_rbtree_subtree_free(tree->root);
|
||||
}
|
||||
|
||||
SAFE_FREE(tree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rbtree_subtree_walk(c_rbnode_t *node, void *data, c_rbtree_visit_func *visitor) {
|
||||
assert(node);
|
||||
assert(data);
|
||||
assert(visitor);
|
||||
|
||||
if (node == NIL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_rbtree_subtree_walk(node->left, data, visitor) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*visitor)(node->data, data) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_rbtree_subtree_walk(node->right, data, visitor) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor) {
|
||||
if (tree == NULL || data == NULL || visitor == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_rbtree_subtree_walk(tree->root, data, visitor) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static c_rbnode_t *_rbtree_subtree_head(c_rbnode_t *node) {
|
||||
assert(node);
|
||||
|
||||
if (node == NIL) {
|
||||
return node;
|
||||
}
|
||||
|
||||
while (node->left != NIL) {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static c_rbnode_t *_rbtree_subtree_tail(c_rbnode_t *node) {
|
||||
assert(node);
|
||||
|
||||
if (node == NIL) {
|
||||
return node;
|
||||
}
|
||||
|
||||
while (node->right != NIL) {
|
||||
node = node->right;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_head(c_rbtree_t *tree) {
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = _rbtree_subtree_head(tree->root);
|
||||
|
||||
return node != NIL ? node : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree) {
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = _rbtree_subtree_tail(tree->root);
|
||||
|
||||
return node != NIL ? node : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node) {
|
||||
c_rbnode_t *parent = NULL;
|
||||
|
||||
if (node == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node->right != NIL) {
|
||||
c_rbnode_t *next = NULL;
|
||||
next = _rbtree_subtree_head(node->right);
|
||||
|
||||
return next != NIL ? next : NULL;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
while (parent && node == parent->right) {
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
|
||||
return parent != NULL ? parent : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node) {
|
||||
c_rbnode_t *parent = NULL;
|
||||
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node->left != NIL) {
|
||||
c_rbnode_t *prev = NULL;
|
||||
prev = _rbtree_subtree_tail(node->left);
|
||||
return prev != NIL ? prev : NULL;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
while (parent && node == parent->left) {
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
|
||||
return parent != NULL ? parent : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key) {
|
||||
int cmp = 0;
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
node = tree->root;
|
||||
|
||||
while (node != NIL) {
|
||||
cmp = tree->key_compare(key, node->data);
|
||||
if (cmp == 0) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (cmp < 0) {
|
||||
node = node->left;
|
||||
} else {
|
||||
node = node->right;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _rbtree_subtree_left_rotate(c_rbnode_t *x) {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
assert(x);
|
||||
|
||||
y = x->right;
|
||||
|
||||
/* establish x-right link */
|
||||
x->right = y->left;
|
||||
|
||||
if (y->left != NIL) {
|
||||
y->left->parent = x;
|
||||
}
|
||||
|
||||
/* establish y->parent link */
|
||||
if (y != NIL) {
|
||||
y->parent = x->parent;
|
||||
}
|
||||
|
||||
if (x->parent) {
|
||||
if (x == x->parent->left) {
|
||||
x->parent->left = y;
|
||||
} else {
|
||||
x->parent->right = y;
|
||||
}
|
||||
} else {
|
||||
x->tree->root = y;
|
||||
}
|
||||
|
||||
/* link x and y */
|
||||
y->left = x;
|
||||
if (x != NIL) {
|
||||
x->parent = y;
|
||||
}
|
||||
}
|
||||
|
||||
/* rotat node x to the right */
|
||||
static void _rbtree_subtree_right_rotate(c_rbnode_t *x) {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
assert(x);
|
||||
|
||||
y = x->left;
|
||||
|
||||
/* establish x->left link */
|
||||
x->left = y->right;
|
||||
|
||||
if (y->right != NIL) {
|
||||
y->right->parent = x;
|
||||
}
|
||||
|
||||
/* establish y->parent link */
|
||||
if (y != NIL) {
|
||||
y->parent = x->parent;
|
||||
}
|
||||
|
||||
if (x->parent) {
|
||||
if (x == x->parent->right) {
|
||||
x->parent->right = y;
|
||||
} else {
|
||||
x->parent->left = y;
|
||||
}
|
||||
} else {
|
||||
x->tree->root = y;
|
||||
}
|
||||
|
||||
/* link x and y */
|
||||
y->right = x;
|
||||
if (x != NIL) {
|
||||
x->parent = y;
|
||||
}
|
||||
}
|
||||
|
||||
int c_rbtree_insert(c_rbtree_t *tree, void *data) {
|
||||
int cmp = 0;
|
||||
c_rbnode_t *current = NULL;
|
||||
c_rbnode_t *parent = NULL;
|
||||
c_rbnode_t *x = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First we do a classic binary tree insert */
|
||||
current = tree->root;
|
||||
parent = NULL;
|
||||
|
||||
while (current != NIL) {
|
||||
cmp = tree->data_compare(data, current->data);
|
||||
parent = current;
|
||||
if (cmp == 0) {
|
||||
return 1;
|
||||
} else if (cmp < 0) {
|
||||
current = current->left;
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
}
|
||||
|
||||
x = (c_rbnode_t *) c_malloc(sizeof(c_rbnode_t));
|
||||
|
||||
x->tree = tree;
|
||||
x->data = data;
|
||||
x->parent = parent;
|
||||
x->left = NIL;
|
||||
x->right = NIL;
|
||||
x->color = RED;
|
||||
|
||||
if (parent) {
|
||||
/* Note that cmp still contains the comparison of data with
|
||||
* parent->data, from the last pass through the loop above
|
||||
*/
|
||||
if (cmp < 0) {
|
||||
parent->left = x;
|
||||
} else {
|
||||
parent->right = x;
|
||||
}
|
||||
} else {
|
||||
tree->root = x;
|
||||
}
|
||||
|
||||
/* Insert fixup - check red-black properties */
|
||||
while (x != tree->root && x->parent->color == RED) {
|
||||
/* we have a violation */
|
||||
if (x->parent == x->parent->parent->left) {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
y = x->parent->parent->right;
|
||||
if (y->color == RED) {
|
||||
x->parent->color = BLACK;
|
||||
y->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
x = x->parent->parent;
|
||||
} else {
|
||||
/* uncle is back */
|
||||
if (x == x->parent->right) {
|
||||
/* make x a left child */
|
||||
x = x->parent;
|
||||
_rbtree_subtree_left_rotate(x);
|
||||
}
|
||||
x->parent->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
_rbtree_subtree_right_rotate(x->parent->parent);
|
||||
}
|
||||
} else {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
y = x->parent->parent->left;
|
||||
if (y->color == RED) {
|
||||
x->parent->color = BLACK;
|
||||
y->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
x = x->parent->parent;
|
||||
} else {
|
||||
/* uncle is back */
|
||||
if (x == x->parent->left) {
|
||||
x = x->parent;
|
||||
_rbtree_subtree_right_rotate(x);
|
||||
}
|
||||
x->parent->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
_rbtree_subtree_left_rotate(x->parent->parent);
|
||||
}
|
||||
}
|
||||
} /* end while */
|
||||
tree->root->color = BLACK;
|
||||
|
||||
tree->size++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_rbtree_node_delete(c_rbnode_t *node) {
|
||||
c_rbtree_t *tree;
|
||||
c_rbnode_t *y;
|
||||
c_rbnode_t *x;
|
||||
|
||||
if (node == NULL || node == NIL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree = node->tree;
|
||||
|
||||
if (node->left == NIL || node->right == NIL) {
|
||||
/* y has a NIL node as a child */
|
||||
y = node;
|
||||
} else {
|
||||
/* find tree successor with a NIL node as a child */
|
||||
y = node;
|
||||
while(y->left != NIL) {
|
||||
y = y->left;
|
||||
}
|
||||
}
|
||||
|
||||
/* x is y's only child */
|
||||
if (y->left != NIL) {
|
||||
x = y->left;
|
||||
} else {
|
||||
x = y->right;
|
||||
}
|
||||
|
||||
/* remove y from the parent chain */
|
||||
x->parent = y->parent;
|
||||
|
||||
if (y->parent) {
|
||||
if (y == y->parent->left) {
|
||||
y->parent->left = x;
|
||||
} else {
|
||||
y->parent->right = x;
|
||||
}
|
||||
} else {
|
||||
y->tree->root = x;
|
||||
}
|
||||
|
||||
/* If y is not the node we're deleting, splice it in place of that
|
||||
* node
|
||||
*
|
||||
* The traditional code would call for us to simply copy y->data, but
|
||||
* that would invalidate the wrong pointer - there might be external
|
||||
* references to this node, and we must preserve its address.
|
||||
*/
|
||||
if (y != node) {
|
||||
/* Update y */
|
||||
y->parent = node->parent;
|
||||
y->left = node->left;
|
||||
y->right = node->right;
|
||||
|
||||
/* Update the children and the parent */
|
||||
if (y->left != NIL) {
|
||||
y->left->parent = y;
|
||||
}
|
||||
if (y->right != NIL) {
|
||||
y->right->parent = y;
|
||||
}
|
||||
if (y->parent != NULL) {
|
||||
if (node == y->parent->left) {
|
||||
y->parent->left = y;
|
||||
} else {
|
||||
y->parent->right = y;
|
||||
}
|
||||
} else {
|
||||
y->tree->root = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (y->color == BLACK) {
|
||||
while (x != y->tree->root && x->color == BLACK) {
|
||||
if (x == x->parent->left) {
|
||||
c_rbnode_t *w = NULL;
|
||||
|
||||
w = x->parent->right;
|
||||
|
||||
if (w->color == RED) {
|
||||
w->color = BLACK;
|
||||
x->parent->color = RED;
|
||||
_rbtree_subtree_left_rotate(x->parent);
|
||||
w = x->parent->right;
|
||||
}
|
||||
|
||||
if (w->left->color == BLACK && w->right->color == BLACK) {
|
||||
w->color = RED;
|
||||
x = x->parent;
|
||||
} else {
|
||||
if (w->right->color == BLACK) {
|
||||
w->left->color = BLACK;
|
||||
w->color = RED;
|
||||
_rbtree_subtree_right_rotate(w);
|
||||
w = x->parent->right;
|
||||
}
|
||||
w->color = x->parent->color;
|
||||
x->parent->color = BLACK;
|
||||
w->right->color = BLACK;
|
||||
_rbtree_subtree_left_rotate(x->parent);
|
||||
x = y->tree->root;
|
||||
}
|
||||
} else {
|
||||
c_rbnode_t *w = NULL;
|
||||
|
||||
w = x->parent->left;
|
||||
if (w->color == RED) {
|
||||
w->color = BLACK;
|
||||
x->parent->color = RED;
|
||||
_rbtree_subtree_right_rotate(x->parent);
|
||||
w = x->parent->left;
|
||||
}
|
||||
|
||||
if (w->right->color == BLACK && w->left->color == BLACK) {
|
||||
w->color = RED;
|
||||
x = x->parent;
|
||||
} else {
|
||||
if (w->left->color == BLACK) {
|
||||
w->right->color = BLACK;
|
||||
w->color = RED;
|
||||
_rbtree_subtree_left_rotate(w);
|
||||
w = x->parent->left;
|
||||
}
|
||||
w->color = x->parent->color;
|
||||
x->parent->color = BLACK;
|
||||
w->left->color = BLACK;
|
||||
_rbtree_subtree_right_rotate(x->parent);
|
||||
x = y->tree->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
x->color = BLACK;
|
||||
} /* end if: y->color == BLACK */
|
||||
|
||||
/* node has now been spliced out of the tree */
|
||||
SAFE_FREE(y);
|
||||
tree->size--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rbtree_subtree_check_black_height(c_rbnode_t *node) {
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
assert(node);
|
||||
|
||||
if (node == NIL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
left = _rbtree_subtree_check_black_height(node->left);
|
||||
right = _rbtree_subtree_check_black_height(node->right);
|
||||
if (left != right) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return left + (node->color == BLACK);
|
||||
}
|
||||
|
||||
int c_rbtree_check_sanity(c_rbtree_t *tree) {
|
||||
c_rbnode_t *node = NULL;
|
||||
c_rbnode_t *prev = NULL;
|
||||
c_rbnode_t *next = NULL;
|
||||
c_rbnode_t *tail = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! tree->key_compare || ! tree->data_compare) {
|
||||
errno = EINVAL;
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Iterate the tree */
|
||||
tail = c_rbtree_tail(tree);
|
||||
for (node = c_rbtree_head(tree); node; node = next) {
|
||||
if (node->tree != tree) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* We should never see a nil while iterating */
|
||||
if (node == NIL) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* node == tree-root iff node->parent == NIL */
|
||||
if (node == tree->root) {
|
||||
if (node->parent != NULL) {
|
||||
return -6;
|
||||
}
|
||||
} else {
|
||||
if (node->parent == NULL) {
|
||||
return -7;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invertability of the iterate functions */
|
||||
if (prev != c_rbtree_node_prev(node)) {
|
||||
return -8;
|
||||
}
|
||||
|
||||
/* Check the iteration sequence */
|
||||
if (prev) {
|
||||
if (tree->data_compare(prev->data, node->data) > 0) {
|
||||
return -9;
|
||||
}
|
||||
|
||||
/* And the other way around, to make sure data_compare is stable */
|
||||
if (tree->data_compare(node->data, prev->data) < 0) {
|
||||
return -10;
|
||||
}
|
||||
}
|
||||
|
||||
/* The binary tree property */
|
||||
if (node->left != NIL) {
|
||||
if (tree->data_compare(node->left->data, node->data) > 0) {
|
||||
return -11;
|
||||
}
|
||||
|
||||
if (tree->data_compare(node->data, node->left->data) < 0) {
|
||||
return -11;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->right != NIL) {
|
||||
if (tree->data_compare(node->data, node->right->data) > 0) {
|
||||
return -12;
|
||||
}
|
||||
|
||||
if (tree->data_compare(node->right->data, node->data) < 0) {
|
||||
return -13;
|
||||
}
|
||||
}
|
||||
|
||||
/* Red-black tree property 3: red nodes have black children */
|
||||
if (node->color == RED) {
|
||||
if (node->left->color == RED) {
|
||||
return -14;
|
||||
}
|
||||
if (node->right->color == RED) {
|
||||
return -15;
|
||||
}
|
||||
}
|
||||
|
||||
/* next == NULL if node == tail */
|
||||
next = c_rbtree_node_next(node);
|
||||
if (next) {
|
||||
if (node == tail) {
|
||||
return -16;
|
||||
}
|
||||
} else {
|
||||
if (node != tail) {
|
||||
return -17;
|
||||
}
|
||||
}
|
||||
|
||||
prev = node;
|
||||
size++;
|
||||
} /* end for loop */
|
||||
|
||||
if (size != tree->size) {
|
||||
return -18;
|
||||
}
|
||||
|
||||
if (_rbtree_subtree_check_black_height(tree->root) < 0) {
|
||||
return -19;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2003-2004 by Andrew Suffield <asuffield@debian.org>
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_rbtree.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc red-black tree implementation
|
||||
*
|
||||
* A red-black tree is a type of self-balancing binary search tree. It is
|
||||
* complex, but has good worst-case running time for its operations and is
|
||||
* efficient in practice: it can search, insert, and delete in O(log n)
|
||||
* time, where n is the number of elements in the tree.
|
||||
*
|
||||
* In red-black trees, the leaf nodes are not relevant and do not contain
|
||||
* data. Therefore we use a sentinal node to save memory. All references
|
||||
* from internal nodes to leaf nodes instead point to the sentinel node.
|
||||
*
|
||||
* In a red-black tree each node has a color attribute, the value of which
|
||||
* is either red or black. In addition to the ordinary requirements imposed
|
||||
* on binary search trees, the following additional requirements of any
|
||||
* valid red-black tree apply:
|
||||
*
|
||||
* 1. A node is either red or black.
|
||||
* 2. The root is black.
|
||||
* 3. All leaves are black, even when the parent is black
|
||||
* (The leaves are the null children.)
|
||||
* 4. Both children of every red node are black.
|
||||
* 5. Every simple path from a node to a descendant leaf contains the same
|
||||
* number of black nodes, either counting or not counting the null black
|
||||
* nodes. (Counting or not counting the null black nodes does not affect
|
||||
* the structure as long as the choice is used consistently.).
|
||||
*
|
||||
* These constraints enforce a critical property of red-black trees: that the
|
||||
* longest path from the root to a leaf is no more than twice as long as the
|
||||
* shortest path from the root to a leaf in that tree. The result is that the
|
||||
* tree is roughly balanced. Since operations such as inserting, deleting, and
|
||||
* finding values requires worst-case time proportional to the height of the
|
||||
* tree, this theoretical upper bound on the height allows red-black trees to
|
||||
* be efficient in the worst-case, unlike ordinary binary search trees.
|
||||
*
|
||||
* http://en.wikipedia.org/wiki/Red-black_tree
|
||||
*
|
||||
* @defgroup cynRBTreeInternals cynapses libc red-black tree functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef _C_RBTREE_H
|
||||
#define _C_RBTREE_H
|
||||
|
||||
/* Forward declarations */
|
||||
struct c_rbtree_s; typedef struct c_rbtree_s c_rbtree_t;
|
||||
struct c_rbnode_s; typedef struct c_rbnode_s c_rbnode_t;
|
||||
|
||||
/**
|
||||
* Define the two colors for the red-black tree
|
||||
*/
|
||||
enum xrbcolor_e { BLACK = 0, RED }; typedef enum xrbcolor_e xrbcolor_t;
|
||||
|
||||
/**
|
||||
* @brief Callback function to compare a key with the data from a
|
||||
* red-black tree node.
|
||||
*
|
||||
* @param key key as a generic pointer
|
||||
* @param data data as a generic pointer
|
||||
*
|
||||
* @return It returns an integer less than, equal to, or greater than zero
|
||||
* depending on the key or data you use. The function is similar
|
||||
* to strcmp().
|
||||
*/
|
||||
typedef int c_rbtree_compare_func(const void *key, const void *data);
|
||||
|
||||
/**
|
||||
* @brief Visit function for the c_rbtree_walk() function.
|
||||
*
|
||||
* This function will be called by c_rbtree_walk() for every node. It is up to
|
||||
* the developer what the function does. The fist parameter is a node object
|
||||
* the second can be of any kind.
|
||||
*
|
||||
* @param obj The node data that will be passed by c_rbtree_walk().
|
||||
* @param data Generic data pointer.
|
||||
*
|
||||
* @return 0 on success, < 0 on error. You should set errno.
|
||||
*
|
||||
*/
|
||||
typedef int c_rbtree_visit_func(void *, void *);
|
||||
|
||||
/**
|
||||
* Structure that represents a red-black tree
|
||||
*/
|
||||
struct c_rbtree_s {
|
||||
c_rbnode_t *root;
|
||||
c_rbtree_compare_func *key_compare;
|
||||
c_rbtree_compare_func *data_compare;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure that represents a node of a red-black tree
|
||||
*/
|
||||
struct c_rbnode_s {
|
||||
c_rbtree_t *tree;
|
||||
c_rbnode_t *left;
|
||||
c_rbnode_t *right;
|
||||
c_rbnode_t *parent;
|
||||
void *data;
|
||||
xrbcolor_t color;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create the red-black tree
|
||||
*
|
||||
* @param rbtree The pointer to assign the allocated memory.
|
||||
*
|
||||
* @param key_compare Callback function to compare a key with the data
|
||||
* inside a reb-black tree node.
|
||||
*
|
||||
* @param data_compare Callback function to compare a key as data with thee
|
||||
* data inside a red-black tree node.
|
||||
*/
|
||||
void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a red-black tree.
|
||||
*
|
||||
* @param tree Tree to duplicate.
|
||||
*
|
||||
* @return Pointer to a new allocated duplicated rbtree. NULL if an error
|
||||
* occurred.
|
||||
*/
|
||||
c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Free the structure of a red-black tree.
|
||||
*
|
||||
* You should call c_rbtree_destroy() before you call this function.
|
||||
*
|
||||
* @param tree The tree to free.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int c_rbtree_free(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Destroy the content and the nodes of an red-black tree.
|
||||
*
|
||||
* This is far from the most efficient way to walk a tree, but it is
|
||||
* the *safest* way to destroy a tree - the destructor can do almost
|
||||
* anything (as long as it does not create an infinite loop) to the
|
||||
* tree structure without risk.
|
||||
*
|
||||
* If for some strange reason you need a faster destructor (think
|
||||
* twice - speed and memory deallocation don't mix well) then consider
|
||||
* stashing an llist of dataects and destroying that instead, and just
|
||||
* using c_rbtree_free() on your tree.
|
||||
*
|
||||
* @param T The tree to destroy.
|
||||
* @param DESTRUCTOR The destructor to call on a node to destroy.
|
||||
*/
|
||||
#define c_rbtree_destroy(T, DESTRUCTOR) \
|
||||
do { \
|
||||
if (T) { \
|
||||
c_rbnode_t *_c_rbtree_temp; \
|
||||
while ((_c_rbtree_temp = c_rbtree_head(T))) { \
|
||||
(DESTRUCTOR)(_c_rbtree_temp->data); \
|
||||
if (_c_rbtree_temp == c_rbtree_head(T)) { \
|
||||
c_rbtree_node_delete(_c_rbtree_temp); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
SAFE_FREE(T); \
|
||||
} while (0);
|
||||
|
||||
/**
|
||||
* @brief Inserts a node into a red black tree.
|
||||
*
|
||||
* @param tree The red black tree to insert the node.
|
||||
* @param data The data to insert into the tree.
|
||||
*
|
||||
* @return 0 on success, 1 if a duplicate has been found and < 0 if an error
|
||||
* occurred with errno set.
|
||||
* EINVAL if a null pointer has been passed as the tree.
|
||||
* ENOMEM if there is no memory left.
|
||||
*/
|
||||
int c_rbtree_insert(c_rbtree_t *tree, void *data);
|
||||
|
||||
/**
|
||||
* @brief Find a node in a red-black tree.
|
||||
*
|
||||
* c_rbtree_find() is searching for the given key in a red-black tree and
|
||||
* returns the node if the key has been found.
|
||||
*
|
||||
* @param tree The tree to search.
|
||||
* @param key The key to search for.
|
||||
*
|
||||
* @return If the key was found the node will be returned. On error NULL
|
||||
* will be returned.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key);
|
||||
|
||||
/**
|
||||
* @brief Get the head of the red-black tree.
|
||||
*
|
||||
* @param tree The tree to get the head for.
|
||||
*
|
||||
* @return The head node. NULL if an error occurred.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_head(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Get the tail of the red-black tree.
|
||||
*
|
||||
* @param tree The tree to get the tail for.
|
||||
*
|
||||
* @return The tail node. NULL if an error occurred.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Get the size of the red-black tree.
|
||||
*
|
||||
* @param T The tree to get the size from.
|
||||
*
|
||||
* @return The size of the red-black tree.
|
||||
*/
|
||||
#define c_rbtree_size(T) (T) == NULL ? 0 : ((T)->size)
|
||||
|
||||
/**
|
||||
* @brief Walk over a red-black tree.
|
||||
*
|
||||
* Walk over a red-black tree calling a visitor function for each node found.
|
||||
*
|
||||
* @param tree Tree to walk.
|
||||
* @param data Data which should be passed to the visitor function.
|
||||
* @param visitor Visitor function. This will be called for each node passed.
|
||||
*
|
||||
* @return 0 on sucess, less than 0 if an error occurred.
|
||||
*/
|
||||
int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor);
|
||||
|
||||
/**
|
||||
* @brief Delete a node in a red-black tree.
|
||||
*
|
||||
* @param node Node which should be deleted.
|
||||
*
|
||||
* @return 0 on success, -1 if an error occurred.
|
||||
*/
|
||||
int c_rbtree_node_delete(c_rbnode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Get the next node.
|
||||
*
|
||||
* @param node The node of which you want the next node.
|
||||
*
|
||||
* @return The next node, NULL if an error occurred.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Get the previous node.
|
||||
*
|
||||
* @param node The node of which you want the previous node.
|
||||
*
|
||||
* @return The previous node, NULL if an error occurred.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Get the data of a node.
|
||||
*
|
||||
* @param N The node to get the data from.
|
||||
*
|
||||
* @return The data, NULL if an error occurred.
|
||||
*/
|
||||
#define c_rbtree_node_data(N) ((N) ? ((N)->data) : NULL)
|
||||
|
||||
/**
|
||||
* @brief Perform a sanity check for a red-black tree.
|
||||
*
|
||||
* This is mostly for testing purposes.
|
||||
*
|
||||
* @param tree The tree to check.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int c_rbtree_check_sanity(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_RBTREE_H */
|
||||
@@ -1,327 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "c_string.h"
|
||||
#include "c_path.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_macro.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
|
||||
# ifdef HAVE_ICONV_H
|
||||
# include <iconv.h>
|
||||
# endif
|
||||
# ifdef HAVE_SYS_ICONV_H
|
||||
# include <sys/iconv.h>
|
||||
# endif
|
||||
|
||||
typedef struct {
|
||||
iconv_t to;
|
||||
iconv_t from;
|
||||
} iconv_conversions;
|
||||
|
||||
CSYNC_THREAD iconv_conversions _iconvs = { NULL, NULL };
|
||||
|
||||
int c_setup_iconv(const char* to) {
|
||||
_iconvs.to = iconv_open(to, "UTF-8");
|
||||
_iconvs.from = iconv_open("UTF-8", to);
|
||||
|
||||
if (_iconvs.to == (iconv_t)-1 || _iconvs.from == (iconv_t)-1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_close_iconv() {
|
||||
int ret_to = 0;
|
||||
int ret_from = 0;
|
||||
if( _iconvs.to != (iconv_t) NULL ) {
|
||||
ret_to = iconv_close(_iconvs.to);
|
||||
}
|
||||
if( _iconvs.from != (iconv_t) NULL ) {
|
||||
ret_from = iconv_close(_iconvs.from);
|
||||
}
|
||||
|
||||
if (ret_to == -1 || ret_from == -1)
|
||||
return -1;
|
||||
|
||||
_iconvs.to = (iconv_t) 0;
|
||||
_iconvs.from = (iconv_t) 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum iconv_direction { iconv_from_native, iconv_to_native };
|
||||
|
||||
static char *c_iconv(const char* str, enum iconv_direction dir)
|
||||
{
|
||||
#ifdef HAVE_ICONV_CONST
|
||||
const char *in = str;
|
||||
#else
|
||||
char *in = discard_const(str);
|
||||
#endif
|
||||
size_t size;
|
||||
size_t outsize;
|
||||
char *out;
|
||||
char *out_in;
|
||||
size_t ret;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(_iconvs.from == NULL && _iconvs.to == NULL) {
|
||||
#ifdef __APPLE__
|
||||
c_setup_iconv("UTF-8-MAC");
|
||||
#else
|
||||
return c_strdup(str);
|
||||
#endif
|
||||
}
|
||||
|
||||
size = strlen(in);
|
||||
outsize = size*2;
|
||||
out = c_malloc(outsize);
|
||||
out_in = out;
|
||||
|
||||
if (dir == iconv_to_native) {
|
||||
ret = iconv(_iconvs.to, &in, &size, &out, &outsize);
|
||||
} else {
|
||||
ret = iconv(_iconvs.from, &in, &size, &out, &outsize);
|
||||
}
|
||||
|
||||
if (ret == (size_t)-1) {
|
||||
SAFE_FREE(out_in);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out_in;
|
||||
}
|
||||
#endif /* defined(HAVE_ICONV) && defined(WITH_ICONV) */
|
||||
|
||||
int c_strncasecmp(const char *a, const char *b, size_t n) {
|
||||
#ifdef _WIN32
|
||||
return _strnicmp(a, b, n);
|
||||
#else
|
||||
return strncasecmp(a, b, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
int c_streq(const char *a, const char *b) {
|
||||
register const char *s1 = a;
|
||||
register const char *s2 = b;
|
||||
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*s1 == *s2++) {
|
||||
if (*s1++ == '\0') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
c_strlist_t *c_strlist_new(size_t size) {
|
||||
c_strlist_t *strlist = NULL;
|
||||
|
||||
if (size == 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlist = c_malloc(sizeof(c_strlist_t));
|
||||
if (strlist == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlist->vector = (char **) c_malloc(size * sizeof(char *));
|
||||
strlist->count = 0;
|
||||
strlist->size = size;
|
||||
|
||||
return strlist;
|
||||
}
|
||||
|
||||
c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size) {
|
||||
if (strlist == NULL || size == 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strlist->size >= size) {
|
||||
return strlist;
|
||||
}
|
||||
|
||||
strlist->vector = (char **) c_realloc(strlist->vector, size * sizeof(char *));
|
||||
if (strlist->vector == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlist->size = size;
|
||||
|
||||
return strlist;
|
||||
}
|
||||
|
||||
int c_strlist_add(c_strlist_t *strlist, const char *string) {
|
||||
if (strlist == NULL || string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlist->count < strlist->size) {
|
||||
strlist->vector[strlist->count] = c_strdup(string);
|
||||
if (strlist->vector[strlist->count] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
strlist->count++;
|
||||
} else {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_strlist_add_grow(c_strlist_t **strlist, const char *string) {
|
||||
if (*strlist == NULL) {
|
||||
*strlist = c_strlist_new(32);
|
||||
if (*strlist == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*strlist)->count == (*strlist)->size) {
|
||||
c_strlist_t *list = c_strlist_expand(*strlist, 2 * (*strlist)->size);
|
||||
if (list == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*strlist = list;
|
||||
}
|
||||
|
||||
return c_strlist_add(*strlist, string);
|
||||
}
|
||||
|
||||
void c_strlist_clear(c_strlist_t *strlist) {
|
||||
size_t i = 0;
|
||||
|
||||
if (strlist == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < strlist->count; i++) {
|
||||
SAFE_FREE(strlist->vector[i]);
|
||||
}
|
||||
|
||||
strlist->count = 0;
|
||||
}
|
||||
|
||||
void c_strlist_destroy(c_strlist_t *strlist) {
|
||||
|
||||
if (strlist == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
c_strlist_clear(strlist);
|
||||
SAFE_FREE(strlist->vector);
|
||||
SAFE_FREE(strlist);
|
||||
}
|
||||
|
||||
/* Convert a wide multibyte String to UTF8 */
|
||||
char* c_utf8_from_locale(const mbchar_t *wstr)
|
||||
{
|
||||
char *dst = NULL;
|
||||
#ifdef _WIN32
|
||||
char *mdst = NULL;
|
||||
int size_needed;
|
||||
size_t len;
|
||||
#endif
|
||||
|
||||
if (wstr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
len = wcslen(wstr);
|
||||
/* Call once to get the required size. */
|
||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
|
||||
if (size_needed > 0) {
|
||||
mdst = c_malloc(size_needed + 1);
|
||||
|
||||
memset(mdst, 0, size_needed + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, len, mdst, size_needed, NULL, NULL);
|
||||
dst = mdst;
|
||||
}
|
||||
#else
|
||||
#ifdef WITH_ICONV
|
||||
dst = c_iconv(wstr, iconv_from_native);
|
||||
#else
|
||||
dst = (char*) wstr;
|
||||
#endif
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* Convert a an UTF8 string to multibyte */
|
||||
mbchar_t* c_utf8_string_to_locale(const char *str)
|
||||
{
|
||||
mbchar_t *dst = NULL;
|
||||
#ifdef _WIN32
|
||||
size_t len;
|
||||
int size_needed;
|
||||
#endif
|
||||
|
||||
if (str == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
len = strlen(str);
|
||||
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
|
||||
if (size_needed > 0) {
|
||||
int size_char = (size_needed + 1) * sizeof(mbchar_t);
|
||||
dst = c_malloc(size_char);
|
||||
memset((void*)dst, 0, size_char);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str, -1, dst, size_needed);
|
||||
}
|
||||
#else
|
||||
#ifdef WITH_ICONV
|
||||
dst = c_iconv(str, iconv_to_native);
|
||||
#else
|
||||
dst = (_TCHAR*) str;
|
||||
#endif
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_string.h
|
||||
*
|
||||
* @brief Interface of the cynapses string implementations
|
||||
*
|
||||
* @defgroup cynStringInternals cynapses libc string functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef _C_STR_H
|
||||
#define _C_STR_H
|
||||
|
||||
#include "c_private.h"
|
||||
#include "c_macro.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct c_strlist_s; typedef struct c_strlist_s c_strlist_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for a stringlist
|
||||
*
|
||||
* Using a for loop you can access the strings saved in the vector.
|
||||
*
|
||||
* c_strlist_t strlist;
|
||||
* int i;
|
||||
* for (i = 0; i < strlist->count; i++) {
|
||||
* printf("value: %s", strlist->vector[i];
|
||||
* }
|
||||
*/
|
||||
struct c_strlist_s {
|
||||
/** The string vector */
|
||||
char **vector;
|
||||
/** The count of the strings saved in the vector */
|
||||
size_t count;
|
||||
/** Size of strings allocated */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare to strings case insensitively.
|
||||
*
|
||||
* @param a First string to compare.
|
||||
* @param b Second string to compare.
|
||||
* @param n Max comparison length.
|
||||
*
|
||||
* @return see strncasecmp
|
||||
*/
|
||||
int c_strncasecmp(const char *a, const char *b, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Compare to strings if they are equal.
|
||||
*
|
||||
* @param a First string to compare.
|
||||
* @param b Second string to compare.
|
||||
*
|
||||
* @return 1 if they are equal, 0 if not.
|
||||
*/
|
||||
int c_streq(const char *a, const char *b);
|
||||
|
||||
/**
|
||||
* @brief Create a new stringlist.
|
||||
*
|
||||
* @param size Size to allocate.
|
||||
*
|
||||
* @return Pointer to the newly allocated stringlist. NULL if an error occured.
|
||||
*/
|
||||
c_strlist_t *c_strlist_new(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Expand the stringlist
|
||||
*
|
||||
* @param strlist Stringlist to expand
|
||||
* @param size New size of the strlinglist to expand
|
||||
*
|
||||
* @return Pointer to the expanded stringlist. NULL if an error occured.
|
||||
*/
|
||||
c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Add a string to the stringlist.
|
||||
*
|
||||
* Duplicates the string and stores it in the stringlist.
|
||||
*
|
||||
* @param strlist Stringlist to add the string.
|
||||
* @param string String to add.
|
||||
*
|
||||
* @return 0 on success, less than 0 and errno set if an error occured.
|
||||
* ENOBUFS if the list is full.
|
||||
*/
|
||||
int c_strlist_add(c_strlist_t *strlist, const char *string);
|
||||
|
||||
/**
|
||||
* @brief Add a string to the stringlist, growing it if necessary
|
||||
*
|
||||
* Duplicates the string and stores it in the stringlist.
|
||||
* It also initializes the stringlist if it starts out as null.
|
||||
*
|
||||
* @param strlist Stringlist to add the string.
|
||||
* @param string String to add.
|
||||
*
|
||||
* @return 0 on success, less than 0 and errno set if an error occured.
|
||||
*/
|
||||
int c_strlist_add_grow(c_strlist_t **strlist, const char *string);
|
||||
|
||||
/**
|
||||
* @brief Removes all strings from the list.
|
||||
*
|
||||
* Frees the strings.
|
||||
*
|
||||
* @param strlist Stringlist to clear
|
||||
*/
|
||||
void c_strlist_clear(c_strlist_t *strlist);
|
||||
|
||||
/**
|
||||
* @brief Destroy the memory of the stringlist.
|
||||
*
|
||||
* Frees the strings and the stringlist.
|
||||
*
|
||||
* @param strlist Stringlist to destroy
|
||||
*/
|
||||
void c_strlist_destroy(c_strlist_t *strlist);
|
||||
|
||||
/**
|
||||
* @brief Convert a platform locale string to utf8.
|
||||
*
|
||||
* This function is part of the multi platform abstraction of basic file
|
||||
* operations to handle various platform encoding correctly.
|
||||
*
|
||||
* Instead of using the standard file operations the multi platform aliases
|
||||
* defined in c_private.h have to be used instead.
|
||||
*
|
||||
* To convert path names returned by these functions to the internally used
|
||||
* utf8 format this function has to be used. The returned string has to
|
||||
* be freed by c_free_locale_string(). On some platforms this method allocates
|
||||
* memory and on others not but it has never to be cared about.
|
||||
*
|
||||
* @param str The multibyte encoded string to convert
|
||||
*
|
||||
* @return The malloced converted string or NULL on error.
|
||||
*
|
||||
* @see c_free_locale_string()
|
||||
* @see c_utf8_to_locale()
|
||||
*
|
||||
*/
|
||||
char* c_utf8_from_locale(const mbchar_t *str);
|
||||
|
||||
/**
|
||||
* @brief Convert a utf8 encoded string to platform specific locale.
|
||||
*
|
||||
* This function is part of the multi platform abstraction of basic file
|
||||
* operations to handle various platform encoding correctly.
|
||||
*
|
||||
* Instead of using the standard file operations the multi platform aliases
|
||||
* defined in c_private.h have to be used instead.
|
||||
*
|
||||
* To convert strings as input for the cross platform functions from the
|
||||
* internally used utf8 format, this function has to be used.
|
||||
* The returned string has to be freed by c_free_locale_string(). On some
|
||||
* platforms this method allocates memory and on others not but it has never
|
||||
* sto be cared about.
|
||||
*
|
||||
* If the string to convert is a path, consider using c_utf8_path_to_locale().
|
||||
*
|
||||
* @param str The utf8 string to convert.
|
||||
*
|
||||
* @return The malloced converted multibyte string or NULL on error.
|
||||
*
|
||||
* @see c_free_locale_string()
|
||||
* @see c_utf8_from_locale()
|
||||
*
|
||||
*/
|
||||
mbchar_t* c_utf8_string_to_locale(const char *wstr);
|
||||
|
||||
#if defined(_WIN32) || defined(WITH_ICONV)
|
||||
|
||||
/**
|
||||
* @brief Free buffer malloced by c_utf8_from_locale or c_utf8_to_locale().
|
||||
*
|
||||
* This function is part of the multi platform abstraction of basic file
|
||||
* operations to handle various platform encoding correctly.
|
||||
*
|
||||
* Instead of using the standard file operations the multi platform aliases
|
||||
* defined in c_private.h have to be used instead.
|
||||
*
|
||||
* This function frees the memory that was allocated by a previous call to
|
||||
* c_utf8_to_locale() or c_utf8_from_locale().
|
||||
*
|
||||
* @param buf The buffer to free.
|
||||
*
|
||||
* @see c_utf8_from_locale(), c_utf8_to_locale()
|
||||
*
|
||||
*/
|
||||
#define c_free_locale_string(x) SAFE_FREE(x)
|
||||
#else
|
||||
#define c_free_locale_string(x) (void)x
|
||||
#endif
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_STR_H */
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* c_time - time functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _C_TIME_H
|
||||
#define _C_TIME_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* @brief Calculate time difference
|
||||
*
|
||||
* The c_tspecdiff function returns the time elapsed between time time1 and time
|
||||
* time0 represented as timespec.
|
||||
*
|
||||
* @param time1 The time.
|
||||
* @param time0 The time.
|
||||
*
|
||||
* @return time elapsed between time1 and time0.
|
||||
*/
|
||||
struct timespec c_tspecdiff(struct timespec time1, struct timespec time0);
|
||||
|
||||
/**
|
||||
* @brief Calculate time difference.
|
||||
*
|
||||
* The function returns the time elapsed between time clock1 and time
|
||||
* clock0 represented as double (in seconds and milliseconds).
|
||||
*
|
||||
* @param clock1 The time.
|
||||
* @param clock0 The time.
|
||||
*
|
||||
* @return time elapsed between clock1 and clock0 in seconds and
|
||||
* milliseconds.
|
||||
*/
|
||||
double c_secdiff(struct timespec clock1, struct timespec clock0);
|
||||
|
||||
int c_utimes(const char *uri, const struct timeval *times);
|
||||
|
||||
#endif /* _C_TIME_H */
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
ZERO_STRUCTP(file_stat);
|
||||
return file_stat;
|
||||
}
|
||||
|
||||
csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) {
|
||||
csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new();
|
||||
memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t));
|
||||
if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||
file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
|
||||
}
|
||||
if (file_stat_cpy->directDownloadCookies) {
|
||||
file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies);
|
||||
}
|
||||
if (file_stat_cpy->directDownloadUrl) {
|
||||
file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl);
|
||||
}
|
||||
file_stat_cpy->name = c_strdup(file_stat_cpy->name);
|
||||
return file_stat_cpy;
|
||||
}
|
||||
|
||||
void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
|
||||
/* FIXME: free rest */
|
||||
if (file_stat == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||
SAFE_FREE(file_stat->etag);
|
||||
}
|
||||
SAFE_FREE(file_stat->directDownloadUrl);
|
||||
SAFE_FREE(file_stat->directDownloadCookies);
|
||||
SAFE_FREE(file_stat->name);
|
||||
SAFE_FREE(file_stat->original_name);
|
||||
SAFE_FREE(file_stat);
|
||||
}
|
||||
|
||||
void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* src ) {
|
||||
|
||||
csync_vio_set_file_id( dst->file_id, src );
|
||||
if( c_streq( dst->file_id, "" )) {
|
||||
return;
|
||||
}
|
||||
dst->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID;
|
||||
}
|
||||
|
||||
void csync_vio_set_file_id( char* dst, const char *src ) {
|
||||
if( src && dst ) {
|
||||
if( strlen(src) > FILE_ID_BUF_SIZE ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src);
|
||||
strcpy(dst, "");
|
||||
} else {
|
||||
strcpy(dst, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
project(tests C)
|
||||
|
||||
set(TORTURE_LIBRARY torture)
|
||||
|
||||
include_directories(
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMOCKA_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
include_directories(${CHECK_INCLUDE_DIRS})
|
||||
# create test library
|
||||
add_library(${TORTURE_LIBRARY} STATIC torture.c cmdline.c)
|
||||
target_link_libraries(${TORTURE_LIBRARY} ${CMOCKA_LIBRARIES} ${CSYNC_LIBRARY} ${CSTDLIB_LIBRARY})
|
||||
|
||||
set(TEST_TARGET_LIBRARIES ${TORTURE_LIBRARY})
|
||||
|
||||
# create tests
|
||||
|
||||
# std
|
||||
add_cmocka_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_path std_tests/check_std_c_path.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_rbtree std_tests/check_std_c_rbtree.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_str std_tests/check_std_c_str.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_time std_tests/check_std_c_time.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# csync tests
|
||||
# This will be rewritten soon anyway.
|
||||
#add_cmocka_test(check_logger log_tests/check_log.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
add_cmocka_test(check_csync_create csync_tests/check_csync_create.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_log csync_tests/check_csync_log.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_exclude csync_tests/check_csync_exclude.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_statedb_load csync_tests/check_csync_statedb_load.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_util csync_tests/check_csync_util.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_misc csync_tests/check_csync_misc.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# csync tests which require init
|
||||
add_cmocka_test(check_csync_init csync_tests/check_csync_init.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_statedb_query csync_tests/check_csync_statedb_query.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_csync_commit csync_tests/check_csync_commit.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# vio
|
||||
add_cmocka_test(check_vio_file_stat vio_tests/check_vio_file_stat.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_vio vio_tests/check_vio.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_vio_ext vio_tests/check_vio_ext.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# sync
|
||||
add_cmocka_test(check_csync_update csync_tests/check_csync_update.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# encoding
|
||||
add_cmocka_test(check_encoding_functions encoding_tests/check_encoding.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_module(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
csync_init(csync, "foo");
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_commit(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_commit(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
|
||||
}
|
||||
|
||||
static void check_csync_commit_dummy(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_commit(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
|
||||
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_commit, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_commit_dummy, setup_module, teardown),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
@@ -1,419 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "config_csync.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#define CSYNC_TEST 1
|
||||
#include "csync_exclude.c"
|
||||
|
||||
#define EXCLUDE_LIST_FILE SOURCEDIR"/../sync-exclude.lst"
|
||||
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_init(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes));
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* and add some unicode stuff */
|
||||
rc = _csync_exclude_add(&(csync->excludes), "*.💩");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = _csync_exclude_add(&(csync->excludes), "пятницы.*");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = _csync_exclude_add(&(csync->excludes), "*/*.out");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = _csync_exclude_add(&(csync->excludes), "latex*/*.run.xml");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = _csync_exclude_add(&(csync->excludes), "latex/*/*.tex.tmp");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_exclude_add(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
_csync_exclude_add(&(csync->excludes), "/tmp/check_csync1/*");
|
||||
assert_string_equal(csync->excludes->vector[0], "/tmp/check_csync1/*");
|
||||
}
|
||||
|
||||
static void check_csync_exclude_load(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes) );
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
assert_string_equal(csync->excludes->vector[0], "*~");
|
||||
assert_int_not_equal(csync->excludes->count, 0);
|
||||
}
|
||||
|
||||
static void check_csync_excluded(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "krawel_krawel", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".htaccess/cache-maximegalon/cache1.txt", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "mozilla/.htaccess", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
/*
|
||||
* Test for patterns in subdirs. '.beagle' is defined as a pattern and has
|
||||
* to be found in top dir as well as in directories underneath.
|
||||
*/
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".apdisk", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "foo/.apdisk", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "foo/bar/.apdisk", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".java", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
/* Files in the ignored dir .java will also be ignored. */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".apdisk/totally_amazing.jar", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
/* and also in subdirs */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "projects/.apdisk/totally_amazing.jar", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
/* csync-journal is ignored in general silently. */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".csync_journal.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".csync_journal.db.ctmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "subdir/.csync_journal.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
|
||||
/* also the new form of the database name */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "subdir/.sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
|
||||
|
||||
/* pattern ]*.directory - ignore and remove */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/a_folder/my.~directory", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
|
||||
|
||||
/* Not excluded because the pattern .netscape/cache requires directory. */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, ".netscape/cache", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
/* Not excluded */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "unicode/中文.hé", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
/* excluded */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "unicode/пятницы.txt", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "unicode/中文.💩", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
/* path wildcards */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "foobar/my_manuscript.out", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "latex_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "word_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "latex/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "latex/songbook/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
#ifdef _WIN32
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_space ", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_dot.", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "AUX", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "file_invalid_char<", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void check_csync_excluded_traversal(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
_csync_exclude_add( &(csync->excludes), "/exclude" );
|
||||
|
||||
/* Check toplevel dir, the pattern only works for toplevel dir. */
|
||||
rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
/* check for a file called exclude. Must still work */
|
||||
rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
/* Add an exclude for directories only: excl/ */
|
||||
_csync_exclude_add( &(csync->excludes), "excl/" );
|
||||
rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
_csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
|
||||
}
|
||||
|
||||
static void check_csync_pathes(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
_csync_exclude_add( &(csync->excludes), "/exclude" );
|
||||
|
||||
/* Check toplevel dir, the pattern only works for toplevel dir. */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
/* check for a file called exclude. Must still work */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
/* Add an exclude for directories only: excl/ */
|
||||
_csync_exclude_add( &(csync->excludes), "excl/" );
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
_csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
|
||||
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
|
||||
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
|
||||
}
|
||||
|
||||
static void check_csync_is_windows_reserved_word() {
|
||||
assert_true(csync_is_windows_reserved_word("CON"));
|
||||
assert_true(csync_is_windows_reserved_word("con"));
|
||||
assert_true(csync_is_windows_reserved_word("CON."));
|
||||
assert_true(csync_is_windows_reserved_word("con."));
|
||||
assert_true(csync_is_windows_reserved_word("CON.ference"));
|
||||
assert_false(csync_is_windows_reserved_word("CONference"));
|
||||
assert_false(csync_is_windows_reserved_word("conference"));
|
||||
assert_false(csync_is_windows_reserved_word("conf.erence"));
|
||||
assert_false(csync_is_windows_reserved_word("co"));
|
||||
assert_true(csync_is_windows_reserved_word("A:"));
|
||||
assert_true(csync_is_windows_reserved_word("a:"));
|
||||
assert_true(csync_is_windows_reserved_word("z:"));
|
||||
assert_true(csync_is_windows_reserved_word("Z:"));
|
||||
assert_true(csync_is_windows_reserved_word("M:"));
|
||||
assert_true(csync_is_windows_reserved_word("m:"));
|
||||
}
|
||||
|
||||
static void check_csync_excluded_performance(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
|
||||
const int N = 10000;
|
||||
int totalRc = 0;
|
||||
int i = 0;
|
||||
|
||||
// Being able to use QElapsedTimer for measurement would be nice...
|
||||
{
|
||||
struct timeval before, after;
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
totalRc += csync_excluded_no_ctx(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
|
||||
totalRc += csync_excluded_no_ctx(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
|
||||
}
|
||||
assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
|
||||
|
||||
gettimeofday(&after, 0);
|
||||
|
||||
const double total = (after.tv_sec - before.tv_sec)
|
||||
+ (after.tv_usec - before.tv_usec) / 1.0e6;
|
||||
const double perCallMs = total / 2 / N * 1000;
|
||||
printf("csync_excluded: %f ms per call\n", perCallMs);
|
||||
}
|
||||
|
||||
{
|
||||
struct timeval before, after;
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
totalRc += csync_excluded_traversal(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
|
||||
totalRc += csync_excluded_traversal(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
|
||||
}
|
||||
assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
|
||||
|
||||
gettimeofday(&after, 0);
|
||||
|
||||
const double total = (after.tv_sec - before.tv_sec)
|
||||
+ (after.tv_usec - before.tv_usec) / 1.0e6;
|
||||
const double perCallMs = total / 2 / N * 1000;
|
||||
printf("csync_excluded_traversal: %f ms per call\n", perCallMs);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_csync_exclude_expand_escapes(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
const char *str = csync_exclude_expand_escapes(
|
||||
"keep \\' \\\" \\? \\\\ \\a \\b \\f \\n \\r \\t \\v \\z");
|
||||
assert_true(0 == strcmp(
|
||||
str, "keep ' \" ? \\ \a \b \f \n \r \t \v \\z"));
|
||||
SAFE_FREE(str);
|
||||
|
||||
str = csync_exclude_expand_escapes("");
|
||||
assert_true(0 == strcmp(str, ""));
|
||||
SAFE_FREE(str);
|
||||
|
||||
str = csync_exclude_expand_escapes("\\");
|
||||
assert_true(0 == strcmp(str, "\\"));
|
||||
SAFE_FREE(str);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_exclude_add, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_exclude_load, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_excluded_traversal, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
|
||||
cmocka_unit_test(check_csync_exclude_expand_escapes),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_module(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_init(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
|
||||
csync_init(csync, "");
|
||||
|
||||
assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
|
||||
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_init, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_init, setup_module, teardown),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "csync.h"
|
||||
#include "csync_log.c"
|
||||
#include "c_private.h"
|
||||
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_log_callback(int verbosity,
|
||||
const char *function,
|
||||
const char *buffer,
|
||||
void *userdata)
|
||||
{
|
||||
int rc;
|
||||
|
||||
assert_true(verbosity >= 0);
|
||||
assert_non_null(function);
|
||||
assert_false(function[0] == '\0');
|
||||
assert_non_null(buffer);
|
||||
assert_false(buffer[0] == '\0');
|
||||
|
||||
(void) userdata; /* unused */
|
||||
|
||||
rc = system("touch /tmp/check_csync1/cb_called");
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_set_log_level(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state;
|
||||
|
||||
rc = csync_set_log_level(-5);
|
||||
assert_int_equal(rc, -1);
|
||||
|
||||
rc = csync_set_log_level(5);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_get_log_level();
|
||||
assert_int_equal(rc, 5);
|
||||
}
|
||||
|
||||
static void check_set_auth_callback(void **state)
|
||||
{
|
||||
csync_log_callback log_fn;
|
||||
int rc;
|
||||
|
||||
(void) state;
|
||||
|
||||
rc = csync_set_log_callback(NULL);
|
||||
assert_int_equal(rc, -1);
|
||||
|
||||
rc = csync_set_log_callback(check_log_callback);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
log_fn = csync_get_log_callback();
|
||||
assert_non_null(log_fn);
|
||||
assert_true(log_fn == &check_log_callback);
|
||||
}
|
||||
|
||||
static void check_logging(void **state)
|
||||
{
|
||||
int rc;
|
||||
csync_stat_t sb;
|
||||
mbchar_t *path;
|
||||
path = c_utf8_path_to_locale("/tmp/check_csync1/cb_called");
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_non_null(path);
|
||||
|
||||
rc = csync_set_log_level(1);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_set_log_callback(check_log_callback);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_log(1, __func__, "rc = %d", rc);
|
||||
|
||||
rc = _tstat(path, &sb);
|
||||
|
||||
c_free_locale_string(path);
|
||||
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_set_log_level),
|
||||
cmocka_unit_test(check_set_auth_callback),
|
||||
cmocka_unit_test_setup_teardown(check_logging, setup, teardown),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#define CSYNC_TEST 1
|
||||
#include "csync_statedb.c"
|
||||
|
||||
#define TESTDB "/tmp/check_csync1/test.db"
|
||||
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
csync->statedb.file = c_strdup( TESTDB );
|
||||
*state = csync;
|
||||
|
||||
sqlite3 *db = NULL;
|
||||
rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
rc = sqlite3_close(db);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_statedb_load(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
sqlite3_close(csync->statedb.db);
|
||||
}
|
||||
|
||||
static void check_csync_statedb_close(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
csync_stat_t sb;
|
||||
time_t modtime;
|
||||
mbchar_t *testdb = c_utf8_path_to_locale(TESTDB);
|
||||
int rc;
|
||||
|
||||
/* statedb not written */
|
||||
csync_statedb_load(csync, TESTDB, &csync->statedb.db);
|
||||
|
||||
rc = _tstat(testdb, &sb);
|
||||
assert_int_equal(rc, 0);
|
||||
modtime = sb.st_mtime;
|
||||
|
||||
rc = csync_statedb_close(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = _tstat(testdb, &sb);
|
||||
assert_int_equal(rc, 0);
|
||||
assert_int_equal(modtime, sb.st_mtime);
|
||||
|
||||
csync_statedb_load(csync, TESTDB, &csync->statedb.db);
|
||||
|
||||
rc = _tstat(testdb, &sb);
|
||||
assert_int_equal(rc, 0);
|
||||
modtime = sb.st_mtime;
|
||||
|
||||
/* wait a sec or the modtime will be the same */
|
||||
sleep(1);
|
||||
|
||||
/* statedb written */
|
||||
rc = csync_statedb_close(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = _tstat(testdb, &sb);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
c_free_locale_string(testdb);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_load, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_close, setup, teardown),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "torture.h"
|
||||
|
||||
#define CSYNC_TEST 1
|
||||
#include "csync_statedb.c"
|
||||
|
||||
#define TESTDB "/tmp/check_csync1/test.db"
|
||||
#define TESTDBTMP "/tmp/check_csync1/test.db.ctmp"
|
||||
|
||||
|
||||
|
||||
static int setup(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int rc = 0;
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
csync_init(csync, TESTDB);
|
||||
|
||||
sqlite3 *db = NULL;
|
||||
rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
rc = sqlite3_close(db);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_db(void **state)
|
||||
{
|
||||
char *errmsg;
|
||||
int rc = 0;
|
||||
sqlite3 *db = NULL;
|
||||
|
||||
const char *sql = "CREATE TABLE IF NOT EXISTS metadata ("
|
||||
"phash INTEGER(8),"
|
||||
"pathlen INTEGER,"
|
||||
"path VARCHAR(4096),"
|
||||
"inode INTEGER,"
|
||||
"uid INTEGER,"
|
||||
"gid INTEGER,"
|
||||
"mode INTEGER,"
|
||||
"modtime INTEGER(8),"
|
||||
"type INTEGER,"
|
||||
"md5 VARCHAR(32),"
|
||||
"PRIMARY KEY(phash)"
|
||||
");";
|
||||
|
||||
const char *sql2 = "INSERT INTO metadata"
|
||||
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5) VALUES"
|
||||
"(42, 42, 'Its funny stuff', 23, 42, 43, 55, 66, 2, 54);";
|
||||
|
||||
|
||||
setup(state);
|
||||
rc = sqlite3_open( TESTDB, &db);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
rc = sqlite3_exec( db, sql, NULL, NULL, &errmsg );
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
rc = sqlite3_exec( db, sql2, NULL, NULL, &errmsg );
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc = 0;
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void check_csync_statedb_query_statement(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
c_strlist_t *result;
|
||||
|
||||
result = csync_statedb_query(csync->statedb.db, "");
|
||||
assert_null(result);
|
||||
if (result != NULL) {
|
||||
c_strlist_destroy(result);
|
||||
}
|
||||
|
||||
result = csync_statedb_query(csync->statedb.db, "SELECT;");
|
||||
assert_null(result);
|
||||
if (result != NULL) {
|
||||
c_strlist_destroy(result);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_csync_statedb_drop_tables(void **state)
|
||||
{
|
||||
// CSYNC *csync = *state;
|
||||
int rc = 0;
|
||||
(void) state;
|
||||
|
||||
// rc = csync_statedb_drop_tables(csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
// rc = csync_statedb_create_tables(csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
// rc = csync_statedb_drop_tables(csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_csync_statedb_insert_metadata(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
csync_file_stat_t *st;
|
||||
int i, rc = 0;
|
||||
|
||||
// rc = csync_statedb_create_tables(csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
st = c_malloc(sizeof(csync_file_stat_t) + 30 );
|
||||
snprintf(st->path, 29, "file_%d" , i );
|
||||
st->phash = i;
|
||||
|
||||
rc = c_rbtree_insert(csync->local.tree, (void *) st);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
// rc = csync_statedb_insert_metadata(csync, csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_csync_statedb_write(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
csync_file_stat_t *st;
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
st = c_malloc(sizeof(csync_file_stat_t) + 30);
|
||||
snprintf(st->path, 29, "file_%d" , i );
|
||||
st->phash = i;
|
||||
|
||||
rc = c_rbtree_insert(csync->local.tree, (void *) st);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
// rc = csync_statedb_write(csync, csync->statedb.db);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
|
||||
static void check_csync_statedb_get_stat_by_hash_not_found(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
csync_file_stat_t *tmp;
|
||||
|
||||
tmp = csync_statedb_get_stat_by_hash(csync, (uint64_t) 666);
|
||||
assert_null(tmp);
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
|
||||
static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
csync_file_stat_t *tmp;
|
||||
|
||||
tmp = csync_statedb_get_stat_by_inode(csync, (ino_t) 666);
|
||||
assert_null(tmp);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "config_csync.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
static void setup(void) {
|
||||
csync_log_init();
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
csync_log_fini();
|
||||
}
|
||||
|
||||
START_TEST (log_create)
|
||||
{
|
||||
fail_unless((csync_log_init() == 0), NULL);
|
||||
fail_unless((csync_log_fini() == 0), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (log_load)
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, (size_t) 256 - 1, "%s/%s", SOURCEDIR, "config/ocsync_log.conf");
|
||||
fail_unless(csync_log_load(buf) == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (log_prio)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTSET, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", "test");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (log_null)
|
||||
{
|
||||
char *z = NULL;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", z);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *log_suite(void) {
|
||||
Suite *s = suite_create("Logger");
|
||||
|
||||
create_case(s, "log_create", log_create);
|
||||
create_case_fixture(s, "log_load", log_load, setup, teardown);
|
||||
create_case_fixture(s, "log_prio", log_prio, setup, teardown);
|
||||
create_case_fixture(s, "log_null", log_null, setup, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = log_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "std/c_path.h"
|
||||
|
||||
static void check_c_basename(void **state)
|
||||
{
|
||||
char *bname;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
bname = c_basename("/usr/lib");
|
||||
assert_string_equal(bname, "lib");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename("/usr//");
|
||||
assert_string_equal(bname, "usr");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename("usr");
|
||||
assert_string_equal(bname, "usr");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename("///");
|
||||
assert_string_equal(bname, "/");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename("/");
|
||||
assert_string_equal(bname, "/");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename(".");
|
||||
assert_string_equal(bname, ".");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename("..");
|
||||
assert_string_equal(bname, "..");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename("");
|
||||
assert_string_equal(bname, ".");
|
||||
free(bname);
|
||||
|
||||
bname = c_basename(NULL);
|
||||
assert_string_equal(bname, ".");
|
||||
free(bname);
|
||||
}
|
||||
|
||||
static void check_c_basename_uri(void **state)
|
||||
{
|
||||
char *bname = NULL;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
bname = c_basename("smb://server/share/dir/");
|
||||
assert_string_equal(bname, "dir");
|
||||
free(bname);
|
||||
}
|
||||
|
||||
static void check_c_dirname(void **state)
|
||||
{
|
||||
char *dname;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
dname = c_dirname("/usr/lib");
|
||||
assert_string_equal(dname, "/usr");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname("/usr//");
|
||||
assert_string_equal(dname, "/");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname("usr");
|
||||
assert_string_equal(dname, ".");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname("/");
|
||||
assert_string_equal(dname, "/");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname("///");
|
||||
assert_string_equal(dname, "/");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname(".");
|
||||
assert_string_equal(dname, ".");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname("..");
|
||||
assert_string_equal(dname, ".");
|
||||
free(dname);
|
||||
|
||||
dname = c_dirname(NULL);
|
||||
assert_string_equal(dname, ".");
|
||||
free(dname);
|
||||
}
|
||||
|
||||
static void check_c_dirname_uri(void **state)
|
||||
{
|
||||
char *dname;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
dname = c_dirname("smb://server/share/dir");
|
||||
assert_string_equal(dname, "smb://server/share");
|
||||
free(dname);
|
||||
}
|
||||
|
||||
static void check_c_parse_uri(void **state)
|
||||
{
|
||||
const char *test_scheme = "git+ssh";
|
||||
const char *test_user = "gladiac";
|
||||
const char *test_passwd = "secret";
|
||||
const char *test_host = "git.csync.org";
|
||||
const char *test_path = "/srv/git/csync.git";
|
||||
|
||||
char *scheme = NULL;
|
||||
char *user = NULL;
|
||||
char *passwd = NULL;
|
||||
char *host = NULL;
|
||||
unsigned int port;
|
||||
char *path = NULL;
|
||||
char uri[1024] = {0};
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = snprintf(uri, sizeof(uri), "%s://%s:%s@%s:22%s",
|
||||
test_scheme, test_user, test_passwd, test_host, test_path);
|
||||
assert_true(rc);
|
||||
|
||||
rc = c_parse_uri(uri, &scheme, &user, &passwd, &host, &port, &path);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
assert_string_equal(test_scheme, scheme);
|
||||
assert_string_equal(test_user, user);
|
||||
assert_string_equal(test_passwd, passwd);
|
||||
assert_string_equal(test_host, host);
|
||||
assert_int_equal(port, 22);
|
||||
assert_string_equal(test_path, path);
|
||||
|
||||
free(scheme);
|
||||
free(user);
|
||||
free(passwd);
|
||||
free(host);
|
||||
free(path);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_c_basename),
|
||||
unit_test(check_c_basename_uri),
|
||||
unit_test(check_c_dirname),
|
||||
unit_test(check_c_dirname_uri),
|
||||
unit_test(check_c_parse_uri),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "std/c_alloc.h"
|
||||
#include "std/c_rbtree.h"
|
||||
|
||||
typedef struct test_s {
|
||||
int key;
|
||||
int number;
|
||||
} test_t;
|
||||
|
||||
static int data_cmp(const void *key, const void *data) {
|
||||
test_t *a, *b;
|
||||
|
||||
a = (test_t *) key;
|
||||
b = (test_t *) data;
|
||||
|
||||
if (a->key < b->key) {
|
||||
return -1;
|
||||
} else if (a->key > b->key) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int key_cmp(const void *key, const void *data) {
|
||||
int a;
|
||||
test_t *b;
|
||||
|
||||
a = POINTER_TO_INT(key);
|
||||
b = (test_t *) data;
|
||||
|
||||
if (a < b->key) {
|
||||
return -1;
|
||||
} else if (a > b->key) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int visitor(void *obj, void *data) {
|
||||
test_t *a;
|
||||
test_t *b;
|
||||
|
||||
a = (test_t *) obj;
|
||||
b = (test_t *) data;
|
||||
|
||||
if (a->key == b->key) {
|
||||
a->number = 42;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void destructor(void *data) {
|
||||
test_t *freedata = NULL;
|
||||
|
||||
freedata = (test_t *) data;
|
||||
SAFE_FREE(freedata);
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
c_rbtree_t *tree = NULL;
|
||||
|
||||
c_rbtree_create(&tree, key_cmp, data_cmp);
|
||||
|
||||
*state = tree;
|
||||
}
|
||||
|
||||
static void setup_complete_tree(void **state) {
|
||||
c_rbtree_t *tree = NULL;
|
||||
int i = 0;
|
||||
int rc;
|
||||
|
||||
c_rbtree_create(&tree, key_cmp, data_cmp);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
test_t *testdata = NULL;
|
||||
|
||||
testdata = c_malloc(sizeof(test_t));
|
||||
assert_non_null(testdata);
|
||||
|
||||
testdata->key = i;
|
||||
|
||||
rc = c_rbtree_insert(tree, (void *) testdata);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
*state = tree;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
c_rbtree_t *tree = *state;
|
||||
|
||||
c_rbtree_destroy(tree, destructor);
|
||||
c_rbtree_free(tree);
|
||||
|
||||
*state = NULL;
|
||||
}
|
||||
|
||||
static void check_c_rbtree_create_free(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = NULL;
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
c_rbtree_create(&tree, key_cmp, data_cmp);
|
||||
assert_int_equal(tree->size, 0);
|
||||
|
||||
rc = c_rbtree_free(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_free_null(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_rbtree_free(NULL);
|
||||
assert_int_equal(rc, -1);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_insert_delete(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = NULL;
|
||||
c_rbnode_t *node = NULL;
|
||||
test_t *testdata = NULL;
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
c_rbtree_create(&tree, key_cmp, data_cmp);
|
||||
|
||||
testdata = malloc(sizeof(test_t));
|
||||
testdata->key = 42;
|
||||
|
||||
rc = c_rbtree_insert(tree, (void *) testdata);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
node = c_rbtree_head(tree);
|
||||
assert_non_null(node);
|
||||
|
||||
testdata = c_rbtree_node_data(node);
|
||||
SAFE_FREE(testdata);
|
||||
rc = c_rbtree_node_delete(node);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
c_rbtree_free(tree);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_insert_random(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
int i = 0, rc;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
test_t *testdata = NULL;
|
||||
|
||||
testdata = malloc(sizeof(test_t));
|
||||
assert_non_null(testdata);
|
||||
|
||||
testdata->key = i;
|
||||
|
||||
rc = c_rbtree_insert(tree, testdata);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
}
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_insert_duplicate(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
test_t *testdata;
|
||||
int rc;
|
||||
|
||||
testdata = malloc(sizeof(test_t));
|
||||
assert_non_null(testdata);
|
||||
|
||||
testdata->key = 42;
|
||||
|
||||
rc = c_rbtree_insert(tree, (void *) testdata);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* add again */
|
||||
testdata = malloc(sizeof(test_t));
|
||||
assert_non_null(testdata);
|
||||
|
||||
testdata->key = 42;
|
||||
|
||||
/* check for duplicate */
|
||||
rc = c_rbtree_insert(tree, (void *) testdata);
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
free(testdata);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_find(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
int rc, i = 42;
|
||||
c_rbnode_t *node;
|
||||
test_t *testdata;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* find the node with the key 42 */
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
assert_non_null(node);
|
||||
|
||||
testdata = (test_t *) c_rbtree_node_data(node);
|
||||
assert_int_equal(testdata->key, 42);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_delete(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
int rc, i = 42;
|
||||
c_rbnode_t *node = NULL;
|
||||
test_t *freedata = NULL;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
assert_non_null(node);
|
||||
|
||||
freedata = (test_t *) c_rbtree_node_data(node);
|
||||
free(freedata);
|
||||
rc = c_rbtree_node_delete(node);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_walk(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
int rc, i = 42;
|
||||
test_t *testdata;
|
||||
c_rbnode_t *node;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
testdata = (test_t *) c_malloc(sizeof(test_t));
|
||||
testdata->key = 42;
|
||||
|
||||
rc = c_rbtree_walk(tree, testdata, visitor);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* find the node with the key 42 */
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
assert_non_null(node);
|
||||
free(testdata);
|
||||
|
||||
testdata = (test_t *) c_rbtree_node_data(node);
|
||||
assert_int_equal(testdata->number, 42);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_walk_null(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
int rc, i = 42;
|
||||
test_t *testdata;
|
||||
c_rbnode_t *node;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
testdata = (test_t *) malloc(sizeof(test_t));
|
||||
testdata->key = 42;
|
||||
|
||||
rc = c_rbtree_walk(NULL, testdata, visitor);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
rc = c_rbtree_walk(tree, NULL, visitor);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
rc = c_rbtree_walk(tree, testdata, NULL);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
/* find the node with the key 42 */
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
assert_non_null(node);
|
||||
|
||||
free(testdata);
|
||||
}
|
||||
|
||||
static void check_c_rbtree_dup(void **state)
|
||||
{
|
||||
c_rbtree_t *tree = *state;
|
||||
c_rbtree_t *duptree = NULL;
|
||||
int rc = -1;
|
||||
|
||||
duptree = c_rbtree_dup(tree);
|
||||
assert_non_null(duptree);
|
||||
|
||||
rc = c_rbtree_check_sanity(duptree);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
c_rbtree_free(duptree);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void check_c_rbtree_x)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_c_rbtree_create_free),
|
||||
unit_test(check_c_rbtree_free_null),
|
||||
unit_test(check_c_rbtree_insert_delete),
|
||||
unit_test_setup_teardown(check_c_rbtree_insert_random, setup, teardown),
|
||||
unit_test_setup_teardown(check_c_rbtree_insert_duplicate, setup, teardown),
|
||||
unit_test_setup_teardown(check_c_rbtree_find, setup_complete_tree, teardown),
|
||||
unit_test_setup_teardown(check_c_rbtree_delete, setup_complete_tree, teardown),
|
||||
unit_test_setup_teardown(check_c_rbtree_walk, setup_complete_tree, teardown),
|
||||
unit_test_setup_teardown(check_c_rbtree_walk_null, setup_complete_tree, teardown),
|
||||
unit_test_setup_teardown(check_c_rbtree_dup, setup_complete_tree, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "std/c_string.h"
|
||||
|
||||
static void check_c_streq_equal(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_true(c_streq("test", "test"));
|
||||
}
|
||||
|
||||
static void check_c_streq_not_equal(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_false(c_streq("test", "test2"));
|
||||
}
|
||||
|
||||
static void check_c_streq_null(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_false(c_streq(NULL, "test"));
|
||||
assert_false(c_streq("test", NULL));
|
||||
assert_false(c_streq(NULL, NULL));
|
||||
}
|
||||
|
||||
static void check_c_strlist_new(void **state)
|
||||
{
|
||||
c_strlist_t *strlist = NULL;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
strlist = c_strlist_new(42);
|
||||
assert_non_null(strlist);
|
||||
assert_int_equal(strlist->size, 42);
|
||||
assert_int_equal(strlist->count, 0);
|
||||
|
||||
c_strlist_destroy(strlist);
|
||||
}
|
||||
|
||||
static void check_c_strlist_add(void **state)
|
||||
{
|
||||
int rc;
|
||||
size_t i = 0;
|
||||
c_strlist_t *strlist = NULL;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
strlist = c_strlist_new(42);
|
||||
assert_non_null(strlist);
|
||||
assert_int_equal(strlist->size, 42);
|
||||
assert_int_equal(strlist->count, 0);
|
||||
|
||||
for (i = 0; i < strlist->size; i++) {
|
||||
rc = c_strlist_add(strlist, (char *) "foobar");
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
assert_int_equal(strlist->count, 42);
|
||||
assert_string_equal(strlist->vector[0], "foobar");
|
||||
assert_string_equal(strlist->vector[41], "foobar");
|
||||
|
||||
c_strlist_destroy(strlist);
|
||||
}
|
||||
|
||||
static void check_c_strlist_expand(void **state)
|
||||
{
|
||||
c_strlist_t *strlist;
|
||||
size_t i = 0;
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
strlist = c_strlist_new(42);
|
||||
assert_non_null(strlist);
|
||||
assert_int_equal(strlist->size, 42);
|
||||
assert_int_equal(strlist->count, 0);
|
||||
|
||||
strlist = c_strlist_expand(strlist, 84);
|
||||
assert_non_null(strlist);
|
||||
assert_int_equal(strlist->size, 84);
|
||||
|
||||
for (i = 0; i < strlist->size; i++) {
|
||||
rc = c_strlist_add(strlist, (char *) "foobar");
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
c_strlist_destroy(strlist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_c_streq_equal),
|
||||
unit_test(check_c_streq_not_equal),
|
||||
unit_test(check_c_streq_null),
|
||||
unit_test(check_c_strlist_new),
|
||||
unit_test(check_c_strlist_add),
|
||||
unit_test(check_c_strlist_expand),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "csync_time.h"
|
||||
#include "std/c_time.h"
|
||||
|
||||
static void check_c_tspecdiff(void **state)
|
||||
{
|
||||
struct timespec start, finish, diff;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
csync_gettime(&start);
|
||||
csync_gettime(&finish);
|
||||
|
||||
diff = c_tspecdiff(finish, start);
|
||||
|
||||
assert_int_equal(diff.tv_sec, 0);
|
||||
assert_true(diff.tv_nsec >= 0);
|
||||
}
|
||||
|
||||
static void check_c_tspecdiff_five(void **state)
|
||||
{
|
||||
struct timespec start, finish, diff;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
csync_gettime(&start);
|
||||
sleep(5);
|
||||
csync_gettime(&finish);
|
||||
|
||||
diff = c_tspecdiff(finish, start);
|
||||
|
||||
assert_int_equal(diff.tv_sec, 5);
|
||||
assert_true(diff.tv_nsec > 0);
|
||||
}
|
||||
|
||||
static void check_c_secdiff(void **state)
|
||||
{
|
||||
struct timespec start, finish;
|
||||
double diff;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
csync_gettime(&start);
|
||||
csync_gettime(&finish);
|
||||
|
||||
diff = c_secdiff(finish, start);
|
||||
|
||||
assert_true(diff >= 0.00 && diff < 1.00);
|
||||
}
|
||||
|
||||
static void check_c_secdiff_three(void **state)
|
||||
{
|
||||
struct timespec start, finish;
|
||||
double diff;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
csync_gettime(&start);
|
||||
sleep(3);
|
||||
csync_gettime(&finish);
|
||||
|
||||
diff = c_secdiff(finish, start);
|
||||
|
||||
assert_true(diff > 3.00 && diff < 4.00);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_c_tspecdiff),
|
||||
unit_test(check_c_tspecdiff_five),
|
||||
unit_test(check_c_secdiff),
|
||||
unit_test(check_c_secdiff_three),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
|
||||
2
doc/.gitignore
vendored
Normal file
2
doc/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
conf.py
|
||||
Makefile
|
||||
@@ -4,7 +4,6 @@ if(SPHINX_FOUND)
|
||||
set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees")
|
||||
# HTML output directory
|
||||
set(SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html")
|
||||
set(SPHINX_MAN_DIR "${CMAKE_CURRENT_BINARY_DIR}/man1")
|
||||
set(SPHINX_PDF_DIR "${CMAKE_CURRENT_BINARY_DIR}/latex")
|
||||
set(SPHINX_QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/qthelp")
|
||||
set(SPHINX_HTMLHELP_DIR "${CMAKE_CURRENT_BINARY_DIR}/htmlhelp")
|
||||
@@ -12,20 +11,20 @@ if(SPHINX_FOUND)
|
||||
# assets
|
||||
set(LATEX_LOGO "${CMAKE_CURRENT_SOURCE_DIR}/logo-blue.pdf")
|
||||
|
||||
install(DIRECTORY ${SPHINX_HTML_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_MAN_DIR} DESTINATION ${CMAKE_INSTALL_MANDIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
|
||||
set(APPLICATION_DOC_DIR "${CMAKE_INSTALL_DOCDIR}/${PACKAGE}")
|
||||
install(DIRECTORY ${SPHINX_HTML_DIR} DESTINATION ${APPLICATION_DOC_DIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${APPLICATION_DOC_DIR} OPTIONAL)
|
||||
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${APPLICATION_DOC_DIR} OPTIONAL)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" conf.py @ONLY)
|
||||
|
||||
if(WITH_DOC)
|
||||
add_custom_target(doc ALL DEPENDS doc-html doc-man COMMENT "Building documentation...")
|
||||
add_custom_target(doc ALL DEPENDS doc-html COMMENT "Building documentation...")
|
||||
else(WITH_DOC)
|
||||
add_custom_target(doc DEPENDS doc-html doc-man COMMENT "Building documentation...")
|
||||
add_custom_target(doc DEPENDS doc-html COMMENT "Building documentation...")
|
||||
endif(WITH_DOC)
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ocdoc/_shared_assets")
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/docs-themes")
|
||||
add_dependencies(doc doc-html-org)
|
||||
add_dependencies(doc doc-html-com)
|
||||
endif()
|
||||
@@ -39,7 +38,13 @@ if(SPHINX_FOUND)
|
||||
-D latex_logo=${LATEX_LOGO}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SPHINX_PDF_DIR} )
|
||||
add_custom_target(doc-pdf $(MAKE) -C ${SPHINX_PDF_DIR} all-pdf
|
||||
|
||||
set(MAKE "make" CACHE FILEPATH "make to be used for documentation generation if not using make as generator anyway")
|
||||
if(CMAKE_GENERATOR MATCHES "Makefiles")
|
||||
set(MAKE "$(MAKE)")
|
||||
endif()
|
||||
|
||||
add_custom_target(doc-pdf ${MAKE} -C ${SPHINX_PDF_DIR} all-pdf
|
||||
DEPENDS doc-latex )
|
||||
add_dependencies(doc doc-pdf)
|
||||
endif(PDFLATEX_FOUND)
|
||||
@@ -71,11 +76,6 @@ if(SPHINX_FOUND)
|
||||
-D html_theme=owncloud_com
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SPHINX_HTML_DIR}/com )
|
||||
add_custom_target( doc-man ${SPHINX_EXECUTABLE}
|
||||
-q -c . -b man
|
||||
-d ${SPHINX_CACHE_DIR}/man
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${SPHINX_MAN_DIR} )
|
||||
|
||||
## Building CHM files requires HTML Help Workshop. Since it requires wine
|
||||
## with special dependencies, it's impossible to write a cmake check for it.
|
||||
|
||||
@@ -14,6 +14,11 @@ Configuration File
|
||||
.. index:: config file
|
||||
.. include:: conffile.rst
|
||||
|
||||
Environment Variables
|
||||
---------------------
|
||||
.. index:: env vars
|
||||
.. include:: envvars.rst
|
||||
|
||||
ownCloud Command Line Client
|
||||
----------------------------
|
||||
.. index:: owncloudcmd
|
||||
|
||||
@@ -138,44 +138,170 @@ under the original file name.
|
||||
|
||||
Example: Assume there is a conflict in message.txt because its contents have
|
||||
changed both locally and remotely since the last sync run. The local file with
|
||||
the local changes will be renamed to message_conflict-20160101-153110.txt and
|
||||
the remote file will be downloaded and saved as message.txt.
|
||||
the local changes will be renamed to "message (conflicted copy 2016-01-01 153110).txt"
|
||||
and the remote file will be downloaded and saved as message.txt.
|
||||
|
||||
Conflict files are always created on the client and never on the server.
|
||||
|
||||
Checksum Algorithm Negotiation
|
||||
------------------------------
|
||||
|
||||
In ownCloud 10.0 we implemented a checksum feature which checks the file integrity on upload and download by computing a checksum after the file transfer finishes.
|
||||
The client queries the server capabilities after login to decide which checksum algorithm to use.
|
||||
Currently, SHA1 is hard-coded in the official server release and can't be changed by the end-user.
|
||||
Note that the server additionally also supports MD5 and Adler-32, but the desktop client will always use the checksum algorithm announced in the capabilities:
|
||||
|
||||
::
|
||||
|
||||
GET http://localhost:8000/ocs/v1.php/cloud/capabilities?format=json
|
||||
|
||||
::
|
||||
|
||||
json
|
||||
{
|
||||
"ocs":{
|
||||
"meta":{
|
||||
"status":"ok",
|
||||
"statuscode":100,
|
||||
"message":"OK",
|
||||
"totalitems":"",
|
||||
"itemsperpage":""
|
||||
},
|
||||
"data":{
|
||||
"version":{
|
||||
"major":10,
|
||||
"minor":0,
|
||||
"micro":0,
|
||||
"string":"10.0.0 beta",
|
||||
"edition":"Community"
|
||||
},
|
||||
"capabilities":{
|
||||
"core":{
|
||||
"pollinterval":60,
|
||||
"webdav-root":"remote.php/webdav"
|
||||
},
|
||||
"dav":{
|
||||
"chunking":"1.0"
|
||||
},
|
||||
"files_sharing":{
|
||||
"api_enabled":true,
|
||||
"public":{
|
||||
"enabled":true,
|
||||
"password":{
|
||||
"enforced":false
|
||||
},
|
||||
"expire_date":{
|
||||
"enabled":false
|
||||
},
|
||||
"send_mail":false,
|
||||
"upload":true
|
||||
},
|
||||
"user":{
|
||||
"send_mail":false
|
||||
},
|
||||
"resharing":true,
|
||||
"group_sharing":true,
|
||||
"federation":{
|
||||
"outgoing":true,
|
||||
"incoming":true
|
||||
}
|
||||
},
|
||||
"checksums":{
|
||||
"supportedTypes":[
|
||||
"SHA1"
|
||||
],
|
||||
"preferredUploadType":"SHA1"
|
||||
},
|
||||
"files":{
|
||||
"bigfilechunking":true,
|
||||
"blacklisted_files":[
|
||||
".htaccess"
|
||||
],
|
||||
"undelete":true,
|
||||
"versioning":true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Upload
|
||||
~~~~~~
|
||||
|
||||
A checksum is calculated with the previously negotiated algorithm by the client and sent along with the file in an HTTP Header.
|
||||
```OC-Checksum: [algorithm]:[checksum]```
|
||||
|
||||
.. image:: ./images/checksums/client-activity.png
|
||||
|
||||
During file upload, the server computes SHA1, MD5, and Adler-32 checksums and compares one of them to the checksum supplied by the client.
|
||||
|
||||
On mismatch, the server returns HTTP Status code 400 (Bad Request) thus signaling the client that the upload failed.
|
||||
The server then discards the upload, and the client blacklists the file:
|
||||
|
||||
.. image:: ./images/checksums/testing-checksums.png
|
||||
|
||||
::
|
||||
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
|
||||
<s:exception>Sabre\DAV\Exception\BadRequest</s:exception>
|
||||
<s:message>The computed checksum does not match the one received from the
|
||||
client.</s:message>
|
||||
</d:error>
|
||||
|
||||
The client retries the upload using exponential back-off.
|
||||
On success (matching checksum) the computed checksums are stored by the server in ``oc_filecache`` alongside the file.
|
||||
|
||||
Chunked Upload
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Mostly same as above.
|
||||
The checksum of the full file is sent with every chunk of the file.
|
||||
But the server only compares the checksum after receiving the checksum sent with the last chunk.
|
||||
|
||||
Download
|
||||
~~~~~~~~
|
||||
|
||||
The server sends the checksum in an HTTP header with the file. (same format as above).
|
||||
If no checksum is found in ``oc_filecache`` (freshly mounted external storage) it is computed and stored in ``oc_filecache`` on the first download.
|
||||
The checksum is then provided on all subsequent downloads but not on the first.
|
||||
|
||||
.. _ignored-files-label:
|
||||
|
||||
Ignored Files
|
||||
-------------
|
||||
|
||||
The ownCloud Client supports the ability to exclude or ignore certain files
|
||||
from the synchronization process. Some system wide file patterns that are used
|
||||
to exclude or ignore files are included with the client by default and the
|
||||
ownCloud Client provides the ability to add custom patterns.
|
||||
The ownCloud Client supports the ability to exclude or ignore certain files from the synchronization process.
|
||||
Some system wide file patterns that are used to exclude or ignore files are included with the client by default and the ownCloud Client provides the ability to add custom patterns.
|
||||
|
||||
By default, the ownCloud Client ignores the following files:
|
||||
|
||||
* Files matched by one of the patterns defined in the Ignored Files Editor
|
||||
* Files containing characters that do not work on certain file systems ``(`\, /, :, ?, *, ", >, <, |`)``.
|
||||
* Files starting with ``._sync_xxxxxxx.db`` and the old format ``.csync_journal.db``,
|
||||
as these files are reserved for journalling.
|
||||
* Files matched by one of the patterns defined in the Ignored Files Editor.
|
||||
* Files starting with ``._sync_*.db*``, ``.sync_*.db*``, ``.csync_journal.db*``, ``.owncloudsync.log*``, as these files are reserved for journalling.
|
||||
* Files with a name longer than 254 characters.
|
||||
* The file ``Desktop.ini`` in the root of a synced folder.
|
||||
* Files matching the pattern ``*_conflict-*`` unless conflict file uploading is enabled.
|
||||
* Files matching the pattern ``*(conflicted copy*`` unless conflict file uploading is enabled.
|
||||
* Windows only: Files containing characters that do not work on typical Windows filesystems ``(`\, /, :, ?, *, ", >, <, |`)``.
|
||||
* Windows only: Files with a trailing space or dot.
|
||||
* Windows only: Filenames that are reserved on Windows.
|
||||
|
||||
If a pattern selected using a checkbox in the `ignoredFilesEditor-label` (or if
|
||||
a line in the exclude file starts with the character ``]`` directly followed by
|
||||
the file pattern), files matching the pattern are considered *fleeting meta
|
||||
data*. These files are ignored and *removed* by the client if found in the
|
||||
synchronized folder. This is suitable for meta files created by some
|
||||
applications that have no sustainable meaning.
|
||||
data*.
|
||||
|
||||
If a pattern ends with the forwardslash (``/``) character, only directories are
|
||||
matched. The pattern is only applied for directory components of filenames
|
||||
selected using the checkbox.
|
||||
These files are ignored and *removed* by the client if found in the
|
||||
synchronized folder.
|
||||
This is suitable for meta files created by some applications that have no sustainable meaning.
|
||||
|
||||
To match filenames against the exclude patterns, the unix standard C library
|
||||
function fnmatch is used. This process checks the filename against the
|
||||
specified pattern using standard shell wildcard pattern matching. For more
|
||||
information, please refer to `The opengroup website
|
||||
If a pattern ends with the forward slash (``/``) character, only directories are matched.
|
||||
The pattern is only applied for directory components of filenames selected using the checkbox.
|
||||
|
||||
To match filenames against the exclude patterns, the UNIX standard C library
|
||||
function ``fnmatch`` is used.
|
||||
This process checks the filename against the specified pattern using standard shell wildcard pattern matching.
|
||||
For more information, please refer to `The opengroup website
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01>`_.
|
||||
|
||||
The path that is checked is the relative path under the sync root directory.
|
||||
@@ -212,9 +338,9 @@ In the communication between client and server a couple of custom WebDAV propert
|
||||
were introduced. They are either needed for sync functionality or help have a positive
|
||||
effect on synchronization performance.
|
||||
|
||||
This chapter describes additional xml elements which the server returns in response
|
||||
This chapter describes additional XML elements which the server returns in response
|
||||
to a successful PROPFIND request on a file or directory. The elements are returned in
|
||||
the namespace oc.
|
||||
the namespace ``oc``.
|
||||
|
||||
Server Side Permissions
|
||||
------------------------
|
||||
@@ -223,27 +349,27 @@ The XML element ``<oc:permissions>`` represents the permission- and sharing stat
|
||||
item. It is a list of characters, and each of the chars has a meaning as outlined
|
||||
in the table below:
|
||||
|
||||
+----+----------------+-------------------------------------------+
|
||||
|Code| Resource | Description |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| S | File or Folder | is shared |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| R | File or Folder | can share (includes reshare) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| M | File or Folder | is mounted (like on DropBox, Samba, etc.) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| W | File | can write file |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| C | Folder |can create file in folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| K | Folder | can create folder (mkdir) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| D | File or Folder |can delete file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| N | File or Folder | can rename file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| V | File or Folder | can move file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
+------+----------------+-------------------------------------------+
|
||||
| Code | Resource | Description |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| S | File or Folder | is shared |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| R | File or Folder | can share (includes re-share) |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| M | File or Folder | is mounted (like on Dropbox, Samba, etc.) |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| W | File | can write file |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| C | Folder | can create file in folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| K | Folder | can create folder (mkdir) |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| D | File or Folder | can delete file or folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| N | File or Folder | can rename file or folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| V | File or Folder | can move file or folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
@@ -59,7 +59,7 @@ the auto-updater entirely. The following sections describe how to disable the
|
||||
auto-update mechanism for different operating systems.
|
||||
|
||||
Preventing Automatic Updates in Windows Environments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Users may disable automatic updates by adding this line to the [General]
|
||||
section of their ``owncloud.cfg`` files::
|
||||
@@ -119,7 +119,7 @@ Preventing Automatic Updates in Linux Environments
|
||||
|
||||
Because the Linux client does not provide automatic updating functionality, there is no
|
||||
need to remove the automatic-update check. However, if you want to disable it edit your desktop
|
||||
client configuration file, ``$HOME/.local/share/data/ownCloud/owncloud.cfg``.
|
||||
client configuration file, ``$HOME/.config/ownCloud/owncloud.cfg``.
|
||||
Add this line to the [General] section::
|
||||
|
||||
skipUpdateCheck=true
|
||||
|
||||
@@ -11,7 +11,15 @@ desktop client.
|
||||
.. note:: Build instructions are subject to change as development proceeds.
|
||||
Please check the version for which you want to build.
|
||||
|
||||
These instructions are updated to work with version 2.2 of the ownCloud Client.
|
||||
These instructions are updated to work with version |version| of the ownCloud Client.
|
||||
|
||||
|
||||
Compiling via ownBrander
|
||||
------------------------
|
||||
|
||||
If you don't want to go through the trouble of doing all the compile work manually,
|
||||
you can use `ownBrander`_ to create installer images for all platforms.
|
||||
|
||||
|
||||
Getting Source Code
|
||||
-------------------
|
||||
@@ -30,10 +38,10 @@ you the exact sources from which the binary packages are built. These are
|
||||
hosted on the `ownCloud repository from OBS`_. Go to the `Index of
|
||||
repositories`_ to see all the Linux client repos.
|
||||
|
||||
1. At the `bottom of the page for each distribution
|
||||
1. The source RPMs for CentOS, RHEL, Fedora, SLES, and openSUSE are at the `bottom of the page for each distribution
|
||||
<https://software.opensuse.org/download/package?project=isv:ownCloud:desktop&
|
||||
package=owncloud-client>`_ is a "Grab binary packages directly" section.
|
||||
These contain source RPMs for CentOS, RHEL, Fedora, SLES, and openSUSE.
|
||||
package=owncloud-client>`
|
||||
the sources for DEB and Ubuntu based distributions are at e.g. http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_16.04/
|
||||
|
||||
To get the .deb source packages add the source
|
||||
repo for your Debian or Ubuntu version, like this example for Debian 8
|
||||
@@ -51,8 +59,8 @@ distribution. Make sure the repositories for source packages are enabled.
|
||||
|
||||
3. Follow the :ref:`generic-build-instructions`, starting with step 2.
|
||||
|
||||
Mac OS X
|
||||
--------
|
||||
macOS
|
||||
-----
|
||||
|
||||
In addition to needing XCode (along with the command line tools), developing in
|
||||
the Mac OS X environment requires extra dependencies. You can install these
|
||||
@@ -77,40 +85,34 @@ To set up your build environment for development using HomeBrew_:
|
||||
|
||||
brew tap owncloud/owncloud
|
||||
|
||||
5. Install a Qt5 version with qtwebkit support::
|
||||
5. Install a Qt5 version, ideally from from 5.10.1::
|
||||
|
||||
brew install qt5 --with-qtwebkit
|
||||
brew install qt5
|
||||
|
||||
6. Install any missing dependencies::
|
||||
|
||||
brew install $(brew deps owncloud-client)
|
||||
|
||||
7. Add Qt from brew to the path::
|
||||
7. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
make sure you make the same install prefix as later while building the client e.g.
|
||||
``-DCMAKE_INSTALL_PREFIX=/Path/to/client/../install``
|
||||
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
||||
8. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
|
||||
Where ``x.y`` is the current version of Qt 5 that brew has installed
|
||||
on your machine.
|
||||
8. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
make sure you make the same install prefix as later while building the client e.g. -
|
||||
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
|
||||
9. Install the Packages_ package creation tool.
|
||||
|
||||
9. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
10. In the build directory, run ``admin/osx/create_mac.sh <CMAKE_INSTALL_DIR> <build dir> <installer sign identity>``.
|
||||
If you have a developer signing certificate, you can specify
|
||||
its Common Name as a third parameter (use quotes) to have the package
|
||||
signed automatically.
|
||||
|
||||
10. Install the Packages_ package creation tool.
|
||||
|
||||
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
<install_dir>``. If you have a developer signing certificate, you can specify
|
||||
its Common Name as a third parameter (use quotes) to have the package
|
||||
signed automatically.
|
||||
|
||||
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
|
||||
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
|
||||
as a ``pkg`` installer. Do not call "make package" at any time when
|
||||
compiling for OS X, as this will build a disk image, and will not
|
||||
work correctly.
|
||||
|
||||
Windows Development Build
|
||||
-----------------------
|
||||
-------------------------
|
||||
|
||||
If you want to test some changes and deploy them locally, you can build natively
|
||||
on Windows using MinGW. If you want to generate an installer for deployment, please
|
||||
@@ -152,7 +154,7 @@ follow `Windows Installer Build (Cross-Compile)`_ instead.
|
||||
|
||||
7. Build the client::
|
||||
|
||||
cmake -G "MinGW Makefiles" ../client
|
||||
cmake -G "MinGW Makefiles" -DNO_SHIBBOLETH=1 ../client
|
||||
mingw32-make
|
||||
|
||||
.. note:: You can try using ninja to build in parallel using
|
||||
@@ -210,7 +212,7 @@ In order to make setup simple, you can use the provided Dockerfile to build your
|
||||
-in ${unsigned_file} \
|
||||
-out ${installer_file}
|
||||
|
||||
for ``-in``, use the URL to the time stamping server provided by your CA along with the Authenticode certificate. Alternatively,
|
||||
For ``-in``, use the URL to the time stamping server provided by your CA along with the Authenticode certificate. Alternatively,
|
||||
you may use the official Microsoft ``signtool`` utility on Microsoft Windows.
|
||||
|
||||
If you're familiar with docker, you can use the version of ``osslsigncode`` that is part of the docker image.
|
||||
@@ -220,16 +222,14 @@ In order to make setup simple, you can use the provided Dockerfile to build your
|
||||
Generic Build Instructions
|
||||
--------------------------
|
||||
|
||||
Compared to previous versions, building the desktop sync client has become easier. Unlike
|
||||
earlier versions, CSync, which is the sync engine library of the client, is now
|
||||
part of the client source repository and not a separate module.
|
||||
|
||||
To build the most up-to-date version of the client:
|
||||
|
||||
1. Clone the latest versions of the client from Git_ as follows::
|
||||
|
||||
git clone git://github.com/owncloud/client.git
|
||||
cd client
|
||||
# master this default, but you can also check out a tag like v2.4.1
|
||||
git checkout master
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
@@ -240,22 +240,17 @@ To build the most up-to-date version of the client:
|
||||
|
||||
3. Configure the client build::
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE="Debug" ..
|
||||
cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/../install/ -DNO_SHIBBOLETH=1 ..``
|
||||
|
||||
.. note:: You must use absolute paths for the ``include`` and ``library``
|
||||
directories.
|
||||
.. note:: You must use absolute paths for the ``include`` and ``library``
|
||||
directories.
|
||||
|
||||
.. note:: On Mac OS X, you need to specify ``-DCMAKE_INSTALL_PREFIX=target``,
|
||||
where ``target`` is a private location, i.e. in parallel to your build
|
||||
dir by specifying ``../install``.
|
||||
|
||||
..note:: qtkeychain must be compiled with the same prefix e.g CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/
|
||||
.. note:: On Mac OS X, you need to specify ``-DCMAKE_INSTALL_PREFIX=target``,
|
||||
where ``target`` is a private location, i.e. in parallel to your build
|
||||
dir by specifying ``../install``.
|
||||
|
||||
.. note:: Example:: cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1
|
||||
.. note:: qtkeychain must be compiled with the same prefix e.g ``-DCMAKE_INSTALL_PREFIX=/Users/path/to/client/../install/``
|
||||
|
||||
.. note:: Example:: cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -D_OPENSSL_VERSION=1.0.2a -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1
|
||||
|
||||
qtkeychain must be compiled with the same prefix e.g CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ .
|
||||
|
||||
4. Call ``make``.
|
||||
|
||||
@@ -268,11 +263,10 @@ The following are known cmake parameters:
|
||||
|
||||
* ``QTKEYCHAIN_LIBRARY=/path/to/qtkeychain.dylib -DQTKEYCHAIN_INCLUDE_DIR=/path/to/qtkeychain/``:
|
||||
Used for stored credentials. When compiling with Qt5, the library is called ``qt5keychain.dylib.``
|
||||
You need to compile QtKeychain with the same Qt version.
|
||||
You need to compile QtKeychain with the same Qt version. If you install QtKeychain into the CMAKE_PREFIX_PATH then you don't need to specify the path manually.
|
||||
* ``WITH_DOC=TRUE``: Creates doc and manpages through running ``make``; also adds install statements,
|
||||
providing the ability to install using ``make install``.
|
||||
* ``CMAKE_PREFIX_PATH=/path/to/Qt5.2.0/5.2.0/yourarch/lib/cmake/``: Builds using Qt5.
|
||||
* ``BUILD_WITH_QT4=ON``: Builds using Qt4 (even if Qt5 is found).
|
||||
* ``CMAKE_PREFIX_PATH=/path/to/Qt5.10.1/5.10.1/yourarch/lib/cmake/``: Builds using that Qt version.
|
||||
* ``CMAKE_INSTALL_PREFIX=path``: Set an install prefix. This is mandatory on Mac OS
|
||||
|
||||
.. _ownCloud repository from OBS: http://software.opensuse.org/download/package?
|
||||
@@ -289,3 +283,4 @@ The following are known cmake parameters:
|
||||
.. _QtKeychain: https://github.com/frankosterfeld/qtkeychain
|
||||
.. _Packages: http://s.sudre.free.fr/Software/Packages/about.html
|
||||
.. _Index of repositories: http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/
|
||||
.. _ownBrander: https://doc.owncloud.org/branded_clients/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
from datetime import datetime
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
@@ -28,7 +29,7 @@ import sys, os
|
||||
extensions = ['sphinx.ext.todo']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/ocdoc/_shared_assets/templates']
|
||||
templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/docs-themes/templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
@@ -41,7 +42,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'ownCloud Client Manual'
|
||||
copyright = u'2013-2016, The ownCloud developers'
|
||||
copyright = u'2013-{:%Y}, The ownCloud developers'.format(datetime.now())
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
@@ -95,7 +96,7 @@ pygments_style = 'sphinx'
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/ocdoc/_shared_assets/themes']
|
||||
html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/docs-themes/themes']
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
@@ -120,7 +121,7 @@ html_short_title = "Client Manual"
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/ocdoc/_shared_assets/static']
|
||||
html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/docs-themes/static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
@@ -250,7 +251,7 @@ texinfo_documents = [
|
||||
epub_title = u'ownCloud Client Manual'
|
||||
epub_author = u'The ownCloud developers'
|
||||
epub_publisher = u'The ownCloud developers'
|
||||
epub_copyright = u'2013-2016, The ownCloud developers'
|
||||
epub_copyright = u'2013-{:%Y}, The ownCloud developers'.format(datetime.now())
|
||||
|
||||
# The language of the text. It defaults to the language option
|
||||
# or en if the language is not set.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
The ownCloud Client reads a configuration file. You can locate this configuration file as follows:
|
||||
|
||||
On Linux distributions:
|
||||
``$HOME/.local/share/data/ownCloud/owncloud.cfg``
|
||||
``$HOME/.config/ownCloud/owncloud.cfg``
|
||||
|
||||
On Microsoft Windows systems:
|
||||
``%LOCALAPPDATA%\ownCloud\owncloud.cfg``
|
||||
``%APPDATA%\ownCloud\owncloud.cfg``
|
||||
|
||||
On MAC OS X systems:
|
||||
``$HOME/Library/Application Support/ownCloud/owncloud.cfg``
|
||||
``$HOME/Library/Preferences/ownCloud/owncloud.cfg``
|
||||
|
||||
|
||||
The configuration file contains settings using the Microsoft Windows .ini file
|
||||
@@ -27,6 +27,8 @@ Some interesting values that can be set on the configuration file are:
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``forceSyncInterval`` | ``7200000`` | The duration of no activity after which a synchronization run shall be triggered automatically. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``fullLocalDiscoveryInterval`` | ``3600000`` | The interval after which the next synchronization will perform a full local discovery. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``notificationRefreshInterval`` | ``300000`` | Specifies the default interval of checking for new server notifications in milliseconds. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -44,6 +46,13 @@ Some interesting values that can be set on the configuration file are:
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``timeout`` | ``300`` | The timeout for network connections in seconds. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``moveToTrash`` | ``false`` | If non-locally deleted files should be moved to trash instead of deleting them completely. |
|
||||
| | | This option only works on linux |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``showExperimentalOptions`` | ``false`` | Whether to show experimental options that are still undergoing testing in the user interface. |
|
||||
| | | Turning this on does not enable experimental behavior on its own. It does enable user inferface |
|
||||
| | | options that can be used to opt in to experimental features. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
@@ -62,4 +71,4 @@ Some interesting values that can be set on the configuration file are:
|
||||
| | | ``2`` for No Proxy. |
|
||||
+ + +--------------------------------------------------------------------------------------------------------+
|
||||
| | | ``3`` for HTTP(S) Proxy. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
61
doc/conflicts.rst
Normal file
61
doc/conflicts.rst
Normal file
@@ -0,0 +1,61 @@
|
||||
=========
|
||||
Conflicts
|
||||
=========
|
||||
|
||||
.. index:: conflicts
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ownCloud desktop client uploads local changes and downloads remote changes.
|
||||
When a file has changed on the local side and on the remote between synchronization
|
||||
runs the client will be unable to resolve the situation on its own. It will
|
||||
create a conflict file with the local version, download the remote version and
|
||||
notify the user that a conflict occured which needs attention.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Imagine there is a file called ``mydata.txt`` your synchronized folder. It has
|
||||
not changed for a while and contains the text "contents" locally and remotely.
|
||||
Now, nearly at the same time you update it locally to say "local contents" while
|
||||
the file on the server gets updated to contain "remote contents" by someone else.
|
||||
|
||||
When attempting to upload your local changes the desktop client will notice that
|
||||
the server version has also changed. It creates a conflict and you will now have
|
||||
two files on your local machine:
|
||||
|
||||
- ``mydata.txt`` containing "remote contents"
|
||||
- ``mydata (conflicted copy 2018-04-10 093612).txt`` containing "local contents"
|
||||
|
||||
In this situation the file ``mydata.txt`` has the remote changes (and will continue
|
||||
to be updated with further remote changes when they happen), but your local
|
||||
adjustments have not been sent to the server (unless the server enables conflict
|
||||
uploading, see below).
|
||||
|
||||
The desktop client notifies you of this situation via system notifications, the
|
||||
system tray icon and a yellow "unresolved conflicts" badge in the account settings
|
||||
window. Clicking this badge shows a list that includes the unresolved conflicts
|
||||
and clicking one of them opens an explorer window pointing at the relevant file.
|
||||
|
||||
To resolve this conflict, open both files, compare the differences and copy your
|
||||
local changes from the "conflicted copy" file into the base file where applicable.
|
||||
In this example you might change ``mydata.txt`` to say "local and remote contents"
|
||||
and delete the file with "conflicted copy" in its name. With that, the conflict
|
||||
is resolved.
|
||||
|
||||
Uploading conflicts (experimental)
|
||||
----------------------------------
|
||||
|
||||
By default the conflict file (the file with "conflicted copy" in its name that
|
||||
contains your local conflicting changes) is not uploaded to the server. The idea
|
||||
is that you, the author of the changes, are the best person for resolving the
|
||||
conflict and showing the conflict to other users might create confusion.
|
||||
|
||||
However, in some scenarios it makes a lot of sense to upload these conflicting
|
||||
changes such that local work can become visible even if the conflict won't be
|
||||
resolved immediately.
|
||||
|
||||
In the future there might be a server-wide switch for this behavior. For now it
|
||||
can already be tested by setting the environment variable
|
||||
``OWNCLOUD_UPLOAD_CONFLICT_FILES=1``.
|
||||
@@ -34,7 +34,7 @@ The discovery phase collects file and directory metadata from the local and remo
|
||||
Afterwards, we have two trees that tell us what happened relative to the journal. But there may still be conflicts if something happened to an entity both locally and on the remote.
|
||||
|
||||
- Input: file system, server data, journal
|
||||
- Output: two c_rbtree_t*, representing the local and remote trees
|
||||
- Output: two FileMap (std::map<QByteArray, std::unique_ptr<csync_file_stat_t>>), representing the local and remote trees
|
||||
|
||||
- Note on remote discovery: Since a change to a file on the server causes the etags of all parent folders to change, folders with an unchanged etag can be read from the journal directly and don't need to be walked into.
|
||||
|
||||
@@ -52,12 +52,12 @@ The reconcile phase compares and adjusts the local and remote trees (in both dir
|
||||
|
||||
Afterwards, there are still two trees, but conflicts are marked in them.
|
||||
|
||||
- Input: c_rbtree_t* for the local and remote trees, journal (for some rename-related queries)
|
||||
- Output: changes c_rbtree_t* in-place
|
||||
- Input: FileMap for the local and remote trees, journal (for some rename-related queries)
|
||||
- Output: changes FileMap in-place
|
||||
|
||||
- Details
|
||||
- csync_reconcile() runs csync_reconcile_updates() for the local and remote trees, one after the other.
|
||||
- csync_reconcile_updates() uses c_rbtree_walk() to iterate through the entries, calling _csync_merge_algorithm_visitor() for each.
|
||||
- csync_reconcile_updates() iterates through the entries, calling _csync_merge_algorithm_visitor() for each.
|
||||
- _csync_merge_algorithm_visitor() checks whether the other tree also has an entry for that node and merges the actions, detecting conflicts. This is the main function of this pass.
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ The post-reconcile phase merges the two trees into one set of SyncFileItems.
|
||||
|
||||
Afterwards, there is a list of items that can tell the propagator what needs to be done.
|
||||
|
||||
- Input: c_rbtree_t* for the local and remote trees
|
||||
- Input: FileMap for the local and remote trees
|
||||
- Output: QMap<QString, SyncFileItemPtr>
|
||||
|
||||
- Note that some "propagations", specifically cheap metadata-only updates, are already done at this stage.
|
||||
|
||||
1
doc/docs-themes
Submodule
1
doc/docs-themes
Submodule
Submodule doc/docs-themes added at 90bd26b118
11
doc/envvars.rst
Normal file
11
doc/envvars.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
The behavior of the client can also be controlled using environment variables. The value of the environment variables overrides the values in the configuration file.
|
||||
|
||||
The environment variables are:
|
||||
|
||||
- `OWNCLOUD_CHUNK_SIZE` (default: 5242880; 5 MiB) – Specifies the chunk size of uploaded files in bytes. Increasing this value may help with synchronization problems in certain configurations.
|
||||
- `OWNCLOUD_TIMEOUT` (default: 300 s) – The timeout for network connections in seconds.
|
||||
- `OWNCLOUD_CRITICAL_FREE_SPACE_BYTES` (default: 50\*1000\*1000 bytes) - The minimum disk space needed for operation. A fatal error is raised if less free space is available.
|
||||
- `OWNCLOUD_FREE_SPACE_BYTES` (default: 250\*1000\*1000 bytes) - Downloads that would reduce the free space below this value are skipped. More information available under the "Low Disk Space" section.
|
||||
- `OWNCLOUD_MAX_PARALLEL` (default: 6) - Maximum number of parallel jobs.
|
||||
- `OWNCLOUD_BLACKLIST_TIME_MIN` (default: 25 s) - Minimum timeout for blacklisted files.
|
||||
- `OWNCLOUD_BLACKLIST_TIME_MAX` (default: 24\*60\*60 s; one day) - Maximum timeout for blacklisted files.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user