Comparar commits
639 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 7e63849fcb | |||
| de53732629 | |||
| dc3accacfc | |||
| 1b9c49e8f5 | |||
| ed15842eb9 | |||
| c24c3d559d | |||
| 6dcd79ded6 | |||
| 0905bcdaea | |||
| d6fdda8efa | |||
| faedaa5e09 | |||
| 661c7f0558 | |||
| a7efe144fc | |||
| b68a28de8d | |||
| 72a7b7ca42 | |||
| 166ef85a51 | |||
| 1f60c61f87 | |||
| 30ef794fa1 | |||
| 47fbfbc006 | |||
| e131c142ff | |||
| 1b99ff2e91 | |||
| 3e85d47a57 | |||
| e709d75d56 | |||
| cb5cfb8cf6 | |||
| ebd2a15711 | |||
| d3a0608bd5 | |||
| c25b599bbb | |||
| a5ff9e58e3 | |||
| 9b96899d75 | |||
| b046cca010 | |||
| edf0a99a8a | |||
| a4640b202f | |||
| 5ef2e88f00 | |||
| 352f168313 | |||
| 85d3de1589 | |||
| 588a88fb63 | |||
| cd9e88ad22 | |||
| 29b39acfbe | |||
| 7427be0062 | |||
| e7546903cc | |||
| 78e3a7e897 | |||
| 1a21b8698e | |||
| 280906eab9 | |||
| 9d7425b201 | |||
| 7eb43d7f7e | |||
| d76e0ec6d8 | |||
| 4a83f976e1 | |||
| 23572aaf77 | |||
| 48655ff1ec | |||
| ffbf34cb97 | |||
| fad690be11 | |||
| 355a644020 | |||
| 5e6e4e7464 | |||
| 76fde49282 | |||
| 4ef7d0410d | |||
| a1b4984d14 | |||
| adbe5ecf55 | |||
| ba32571039 | |||
| 084146756b | |||
| e1f5a49c21 | |||
| 143320341e | |||
| e286bb1b64 | |||
| d433f0e08e | |||
| 107149d601 | |||
| fa9b36f829 | |||
| 6775292d63 | |||
| 6835429a28 | |||
| 22135f9f57 | |||
| 0fd06a225c | |||
| 473dcb0947 | |||
| e306f4611c | |||
| c6f4f44619 | |||
| 0865c63745 | |||
| b81c3a6a67 | |||
| cc56e5639d | |||
| 3ce5b358ae | |||
| e968284618 | |||
| c7723179d8 | |||
| 1872f3f94a | |||
| 3b7887ca35 | |||
| d781e63fab | |||
| d1237cdda3 | |||
| 030e3a5d4a | |||
| 4fa4a6a5ed | |||
| 23fb07240b | |||
| 3912dba33a | |||
| d8c479ab1e | |||
| bec67455c1 | |||
| ba6a37a601 | |||
| 03f5091e73 | |||
| 6b6ff08821 | |||
| 35a0ee4893 | |||
| 3519391119 | |||
| 775a1c9ad8 | |||
| ac95844ebd | |||
| c5b90d9507 | |||
| d631f2e070 | |||
| 5bae2ed5ef | |||
| 5af2a657ca | |||
| 71231026a0 | |||
| dfca67b63a | |||
| 7dc6a3b89f | |||
| f985111b62 | |||
| e8d734b1c2 | |||
| a38864fcb4 | |||
| 47bab51474 | |||
| d0d5b2b4ee | |||
| 36967122db | |||
| 3fd67b9fb6 | |||
| 5bef1aa402 | |||
| de9ea19e7e | |||
| 4ac2b764a4 | |||
| 0614cda337 | |||
| 9e895b9b3e | |||
| f501211c63 | |||
| 77ac1b46dd | |||
| 745c21623c | |||
| b91c116518 | |||
| d090a3330a | |||
| d04e7841e2 | |||
| d7a4726544 | |||
| 19d2677db1 | |||
| a139d1a279 | |||
| 13e624c38f | |||
| acb155503b | |||
| 4cb80b08a2 | |||
| cd85b7c6d7 | |||
| 109056e676 | |||
| 51a1bea5de | |||
| 68f99bcc27 | |||
| 276985f6c3 | |||
| 7523db354d | |||
| 4919c9e7b1 | |||
| 045498c71a | |||
| 49f8143f00 | |||
| bea7241910 | |||
| 61b4da944c | |||
| 6fe1868693 | |||
| 9641c7a1e7 | |||
| 3e59a9b316 | |||
| 679ac0d26a | |||
| 2e3a3bcf84 | |||
| ad437a49f9 | |||
| 6b2282bf0d | |||
| 42aed56a5a | |||
| ca9ec46253 | |||
| a92eec160a | |||
| cc91c42dfa | |||
| d22d0e7e30 | |||
| 4998303c42 | |||
| ceef2f2d46 | |||
| 8b18600d7e | |||
| 6cc63462b3 | |||
| a1dc4069c9 | |||
| 86846af59d | |||
| 5bfa02602d | |||
| 9be23984eb | |||
| eb8de8e3c0 | |||
| ec7333a4bf | |||
| e485c5c008 | |||
| 6451eb3ade | |||
| 01528427b5 | |||
| cec4d7b9ff | |||
| efa7821dd2 | |||
| 89f55cf9df | |||
| 52552a4204 | |||
| 2f3db04e87 | |||
| 2d6e473a40 | |||
| 92027e8692 | |||
| 2723cd225e | |||
| acd151102c | |||
| 77e790d2ee | |||
| 899c675f0a | |||
| fb76487e76 | |||
| 0c0a3ca0a5 | |||
| 5377d1e283 | |||
| 676ad530e7 | |||
| fbcb01ed27 | |||
| c2b006e857 | |||
| 0e7ccea588 | |||
| c16deb3e44 | |||
| 019544fcfd | |||
| 5f0167b19e | |||
| 29d3c33eb2 | |||
| 469eca1f5f | |||
| 0864d67a9a | |||
| e9503664f5 | |||
| 58cee61624 | |||
| d23d07f99b | |||
| d70db810dd | |||
| 842129f99d | |||
| 36d61ef3a9 | |||
| f1f27221a7 | |||
| eb012d26ee | |||
| 9ee8187083 | |||
| b0c45cfc89 | |||
| 90cea69692 | |||
| 155bdfbffe | |||
| 0e2782d369 | |||
| 6b3d0e69aa | |||
| f30aee6d4e | |||
| 82f86eb019 | |||
| 9573c5e64d | |||
| 15f2b911d9 | |||
| f5aff70398 | |||
| e3a4c3989a | |||
| 3e954bc17f | |||
| 2527569bb8 | |||
| 1e197531cb | |||
| 8b876576eb | |||
| a2287c9657 | |||
| 34c59ba9ed | |||
| c8014a0afd | |||
| 456d82715e | |||
| 8ca3eb7883 | |||
| c110745330 | |||
| 19521863a0 | |||
| c256896165 | |||
| ef922f60fa | |||
| 733ea90e6b | |||
| a4e1fa9dcf | |||
| 1a1684ca2a | |||
| 9c8572e335 | |||
| e675a34fbb | |||
| 5f47c01346 | |||
| 10644d3568 | |||
| 9ee3144358 | |||
| cf48ea2e00 | |||
| db24f60ae3 | |||
| 6026148692 | |||
| a2222228c9 | |||
| 9e2d3f5bc7 | |||
| fe984b61d7 | |||
| ffac3f6213 | |||
| 4f1feab845 | |||
| f738cfd7fe | |||
| e6be670e49 | |||
| 46ce2f4722 | |||
| 166a0f60ca | |||
| a9019ccbad | |||
| 0a4806af44 | |||
| e33b89c222 | |||
| 6b899be895 | |||
| 641785298f | |||
| 092c935422 | |||
| 273590fdfc | |||
| 0960058842 | |||
| 1f78ea0fd1 | |||
| 72d8175032 | |||
| 2fd9767892 | |||
| 69a1e46d0c | |||
| e020a5327e | |||
| 1b04489887 | |||
| 36a19703db | |||
| f3a345a23b | |||
| 826459eae7 | |||
| c2c36b85cb | |||
| 7b2f8ae6f7 | |||
| d600fdc89b | |||
| 8c5ea8dc90 | |||
| 0eddcd6384 | |||
| 9f2ae5dd17 | |||
| 766d9ae1ac | |||
| 21128ed762 | |||
| 5000d40619 | |||
| 16e28567a6 | |||
| 3bef42db6b | |||
| 27d23edacc | |||
| 0d321050a6 | |||
| fc7aaf792b | |||
| f6355e15a3 | |||
| d80d5a8ee4 | |||
| e0a36ab313 | |||
| 9d3e78ed54 | |||
| b6079bfe4f | |||
| f75106fd8e | |||
| 57fe7b800f | |||
| 089ecf8222 | |||
| e1a48e3c33 | |||
| c2fa9b5bbf | |||
| 86522cbbf0 | |||
| d54f8adac5 | |||
| d35ecafa0b | |||
| 2ca807280a | |||
| 5d13f9290f | |||
| c84140d293 | |||
| 91b6b88883 | |||
| f36d4562a1 | |||
| 67ecca492b | |||
| 84c925dc58 | |||
| e1a01c75d9 | |||
| 6a4adbc87e | |||
| 89974ab1d4 | |||
| 8d0c313486 | |||
| aab0cdf12a | |||
| a89520043e | |||
| 6382a142cd | |||
| 838c072ccc | |||
| 02c403e360 | |||
| ed6a708460 | |||
| 0c9dcdafc2 | |||
| 5f2b1999f6 | |||
| bd2bcad3ba | |||
| 598a7cec5d | |||
| 46d934bd95 | |||
| e8c8943a30 | |||
| f1e2e42d99 | |||
| 95c479aa07 | |||
| 035442b6da | |||
| 98efb07535 | |||
| bc04f79959 | |||
| e10c97573f | |||
| 383479fbfd | |||
| fca5f1b210 | |||
| 0cea3d85f5 | |||
| 85b8ab178e | |||
| ea9d17b41d | |||
| b7eb37dc03 | |||
| 98bfa8d5de | |||
| ff701bd473 | |||
| 31aaf956f5 | |||
| a221ac1e4d | |||
| 2b274e9460 | |||
| da26e59770 | |||
| 3c24d5a148 | |||
| c222793525 | |||
| 28018e8590 | |||
| 4c79ce2ae6 | |||
| aa5d3055be | |||
| 3e1690ff7a | |||
| 826a675f32 | |||
| 323ebf9bf2 | |||
| e4bf3ec19a | |||
| f2721aff1d | |||
| 29bd8658bb | |||
| 8b9ca63eeb | |||
| 6f1b03c560 | |||
| 3bd3ffb8e2 | |||
| a810d69daa | |||
| 8496817db2 | |||
| 3d06f4b7c9 | |||
| b228488eb7 | |||
| b7809ded23 | |||
| dfb121236c | |||
| f286493c90 | |||
| c2cb729fee | |||
| 904cd46f75 | |||
| 7fd00b2cd5 | |||
| 2d110540ee | |||
| 907918dca3 | |||
| 5ffaf3a90f | |||
| 1040e7b57b | |||
| 65c49e1de6 | |||
| 4abaee7736 | |||
| 3cdcd8dea0 | |||
| cb19ebc9e3 | |||
| 37adaa7872 | |||
| 9d93afb2a1 | |||
| d5a481f132 | |||
| 1d09f6b60f | |||
| 98268d102f | |||
| 9e895a6ecc | |||
| 7c75a39bc1 | |||
| 524220d090 | |||
| af9c4d0e2f | |||
| 7c24ed769e | |||
| c97d8aa8fd | |||
| 65110f7a91 | |||
| c33abd468d | |||
| 584b205bd5 | |||
| f0dc3b2deb | |||
| 84ede3f01f | |||
| 2daf895e43 | |||
| 3b651b2da9 | |||
| 6fd930908c | |||
| 62125a442d | |||
| 2d54fb2ff9 | |||
| e46fad52bb | |||
| b75f50d62c | |||
| 14457e93e6 | |||
| c41f6ed76b | |||
| 818b5854ce | |||
| 79abb8b4e3 | |||
| fad387b6b8 | |||
| a1558100b8 | |||
| 4f3f642da6 | |||
| 86eab48981 | |||
| d2bde5489f | |||
| 9c0ecad420 | |||
| 85b5fdb3d3 | |||
| f2c6669224 | |||
| d8f9bf3a0b | |||
| d5fa8faa91 | |||
| 39e93768ea | |||
| c1eb9244d1 | |||
| d1a1b95926 | |||
| ee2a67e332 | |||
| 6ecda6e7f4 | |||
| 7362575d64 | |||
| 6a9b6c1167 | |||
| 8e00fd66de | |||
| ef035ea7f9 | |||
| 77b5c5e963 | |||
| 687549c455 | |||
| b28123bed9 | |||
| 677c34fbf8 | |||
| 2ff7b63551 | |||
| b541fea793 | |||
| efb6b8c2c9 | |||
| e974771796 | |||
| 82ef1bcfe0 | |||
| b7ff4a76e8 | |||
| 465639af82 | |||
| 7f59dec0bb | |||
| 583f9586aa | |||
| 2507ba9818 | |||
| 88cd5421bf | |||
| 7b26e6b8f9 | |||
| 573d942969 | |||
| 1a454ec6b2 | |||
| 02df088843 | |||
| ce4daaaae2 | |||
| cd9335e043 | |||
| 775ad25be3 | |||
| 7e43fe599c | |||
| 20531e57a8 | |||
| 3e64840e33 | |||
| e6db2ee960 | |||
| be34bfb276 | |||
| e2e16aeaaa | |||
| 6fbeb60d86 | |||
| a46a69f250 | |||
| bb5c2cbfa5 | |||
| 60904496d2 | |||
| 94c9a2cca1 | |||
| 3187a22300 | |||
| 9626021a63 | |||
| b72a19ad64 | |||
| 2ae37c6beb | |||
| f8f376ac03 | |||
| 632d231435 | |||
| fc868d89f3 | |||
| 5a57e4a7a6 | |||
| 70a1671dc1 | |||
| 7de70516f1 | |||
| 50bd4b8f4f | |||
| 4a7f3cb486 | |||
| b7663d00b9 | |||
| b307f2b65c | |||
| 6c94d56b53 | |||
| 73a6939b70 | |||
| 88e5a9411a | |||
| c51a80bffa | |||
| 87f4f70abb | |||
| 19a52b9e6b | |||
| 4ea70ebd18 | |||
| d58c392d93 | |||
| b9a6970282 | |||
| a58ef9c586 | |||
| cef24da44c | |||
| 23c7f10b79 | |||
| 5ac434a740 | |||
| 9e514d6cc7 | |||
| 4d109e43fa | |||
| b575ded464 | |||
| a83c5598e8 | |||
| 03a90bf03f | |||
| ff7b2381e9 | |||
| 24cd8041a8 | |||
| 3eaadfe52f | |||
| ebcec44202 | |||
| 7b0b7fde51 | |||
| fa9ec12ae7 | |||
| 54aa4dce46 | |||
| 7c19f748b7 | |||
| 5aa82944a4 | |||
| 0d9cf26890 | |||
| eadecc5802 | |||
| 39bde6f3e4 | |||
| a4837e9291 | |||
| 5672557a84 | |||
| 0b31f2601d | |||
| f3cfd2b70b | |||
| 78caa1a712 | |||
| a5850d4515 | |||
| c39eb315dd | |||
| 6c8e88e2ed | |||
| 3465024898 | |||
| eeea255104 | |||
| 8e2af57b57 | |||
| 7c671756e6 | |||
| f3f387c36b | |||
| b53ce78eb6 | |||
| 0c6788f03d | |||
| bc4753e938 | |||
| 6bd4de19a8 | |||
| 927a8b5071 | |||
| aefbca0787 | |||
| a4310f0f5c | |||
| cb64ba22b3 | |||
| 653b42216f | |||
| 0884ad6517 | |||
| 37fc4e4332 | |||
| 9cc90159f1 | |||
| 4ceee86c66 | |||
| b9ea7c3414 | |||
| 3033e693be | |||
| a1bc01d3b1 | |||
| 3ec9cd1d9e | |||
| b21e3e0fdc | |||
| 20d0c835b6 | |||
| 3335c733d7 | |||
| 4da55b69df | |||
| b7085987b8 | |||
| a1b44cd82a | |||
| 11b44358f6 | |||
| 4979181e85 | |||
| 651cc25e3f | |||
| 699d1ba13b | |||
| 3c575a2f37 | |||
| bd7ec19644 | |||
| a338b9f269 | |||
| 81ff4e02c5 | |||
| 8a1a2eb5b3 | |||
| 0c646b974f | |||
| e661bf2324 | |||
| 2abb5c95bb | |||
| c3ef1a996f | |||
| 7a2a439426 | |||
| ce26afb262 | |||
| 56e1737c61 | |||
| dff57362f9 | |||
| 3f3a679f81 | |||
| cde9017340 | |||
| 05a7c18635 | |||
| 3a77074b97 | |||
| 446e7cbd93 | |||
| b4d26ba952 | |||
| 622017adcf | |||
| 088a4f0bbe | |||
| ba96fb89a5 | |||
| 70ae11fcad | |||
| 86fd982b00 | |||
| bdb304f8ec | |||
| 001075daf0 | |||
| 2a98aa7130 | |||
| 9904fb200e | |||
| 6822ae5bec | |||
| 440a804836 | |||
| 9b66dd7166 | |||
| 7601783553 | |||
| 6e9df8673f | |||
| c0b0bd5b63 | |||
| 28d86cee17 | |||
| 32bb8295a2 | |||
| 5d71ad83ec | |||
| ab24980001 | |||
| 07dea72c37 | |||
| a734be347b | |||
| 1443ddc7c9 | |||
| 191177ff22 | |||
| 43a2aec92b | |||
| 681243277e | |||
| c848097c6b | |||
| 096e2cf233 | |||
| 7181aedb4b | |||
| edfd75949d | |||
| 7fb134b4e0 | |||
| 87e3553c85 | |||
| 6f3aaecb78 | |||
| 40e3653722 | |||
| 5a4f50a0ff | |||
| 3342ebfcc5 | |||
| b4900d60b7 | |||
| 92309013da | |||
| 4895589e4d | |||
| cb50fae0a7 | |||
| 05d199881e | |||
| 147cf798a6 | |||
| d40c56eda5 | |||
| 6dade0b114 | |||
| 5de44407bf | |||
| 2df741e456 | |||
| 8b5f71f49e | |||
| 77791ccb34 | |||
| a6e4f9939c | |||
| 523cdff1cf | |||
| c4d6277ce3 | |||
| 73cc3a4fd4 | |||
| d655074f85 | |||
| 85a173e174 | |||
| 87b4693a9d | |||
| 28c12a3ca0 | |||
| 70196eb48c | |||
| 9b249716a3 | |||
| a4b46db91e | |||
| ebc44fa494 | |||
| 355a8a0a27 | |||
| 66f041f74c | |||
| 6d02d76cfd | |||
| 48efbcb8ca | |||
| ab050f9093 | |||
| bf9cffe4b3 | |||
| 43f727cf69 | |||
| 256331fbaa | |||
| 32e6585ae6 | |||
| d072e4a678 | |||
| b99c8fe28b | |||
| 5a3120bd52 | |||
| 9ea69be6ab | |||
| 86680a53e0 | |||
| 801cb42d57 | |||
| 51f8a59a9a | |||
| ebbe5acf2b | |||
| 6ccd9e872d | |||
| da69756bb0 | |||
| 1787da8a9d | |||
| f0f82d02ff | |||
| ff20cd4d57 | |||
| 9ab812f89b | |||
| de82d8fcdb | |||
| af2b712dc6 | |||
| a507558dee | |||
| e73c3199c0 | |||
| d88ab4653b | |||
| 9a2450c4c1 | |||
| 3c1f5e662f | |||
| 100ee69ddd | |||
| d45d6ca9da | |||
| 2608c7007e | |||
| 06a88ea9a4 | |||
| 0194ebb222 | |||
| dc654ac846 | |||
| 370fd5062c | |||
| 00d20b4a42 | |||
| a2b238e2e5 | |||
| 0e2c16e827 | |||
| b9fdae6d67 | |||
| c34115610e | |||
| 275ad1e157 |
+19
-2
@@ -1,6 +1,9 @@
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(VERSION 2.8.0)
|
||||
if(POLICY CMP0020)
|
||||
cmake_policy(SET CMP0020 NEW)
|
||||
endif()
|
||||
|
||||
project(client)
|
||||
|
||||
@@ -55,9 +58,12 @@ if( UNIX AND NOT APPLE )
|
||||
endif()
|
||||
####
|
||||
|
||||
# Enable Q_ASSERT etc. in all builds
|
||||
add_definitions( -DQT_FORCE_ASSERTS )
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
include(GetGitRevisionDescription)
|
||||
|
||||
@@ -66,7 +72,7 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
# 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.
|
||||
if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
|
||||
if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate)
|
||||
string(REPLACE "\n" "" sha1_candidate ${sha1_candidate})
|
||||
if (NOT ${sha1_candidate} STREQUAL "$Format:%H$")
|
||||
@@ -136,6 +142,13 @@ if(OWNCLOUD_RESTORE_RENAME)
|
||||
add_definitions(-DOWNCLOUD_RESTORE_RENAME=1)
|
||||
endif()
|
||||
|
||||
# Disable shibboleth.
|
||||
# So the client can be built without QtWebKit
|
||||
option(NO_SHIBBOLETH "Build without Shibboleth support. Allow to build the client without QtWebKit" OFF)
|
||||
if(NO_SHIBBOLETH)
|
||||
message("Compiling without shibboleth")
|
||||
add_definitions(-DNO_SHIBBOLETH=1)
|
||||
endif()
|
||||
|
||||
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" )
|
||||
@@ -159,6 +172,9 @@ 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\))
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(ZLIB)
|
||||
@@ -173,6 +189,7 @@ add_definitions(-DUNICODE)
|
||||
add_definitions(-D_UNICODE)
|
||||
if( WIN32 )
|
||||
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
||||
add_definitions( -DNOMINMAX )
|
||||
endif( WIN32 )
|
||||
|
||||
# Handle Translations, pick all client_* files from trans directory.
|
||||
|
||||
+78
-1
@@ -1,9 +1,86 @@
|
||||
ChangeLog
|
||||
=========
|
||||
version 2.2.1 (release 2016-05-xx)
|
||||
|
||||
version 2.3.0 (2017-0x-xx)
|
||||
* WiP!
|
||||
* WiP Switch Windows and OS X build to 5.6.2
|
||||
* WiP Performance improvements for exclude detection
|
||||
* Switch to new ownCloud server WebDAV endpoint
|
||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||
* Conflicts: Use the local mtime for the conflict file name (#5273)
|
||||
* "Sync now" menu item
|
||||
* SSL Client certificate support improved (Show UI, Store keys in keychain)
|
||||
* Propagator: Upload more small files in parallel
|
||||
* Sync Engine: Read data-fingerprint property to detect backups (#2325)
|
||||
* GUI: Show link to ceate an app password/token for syncing
|
||||
* Share dialog: Add 'Mail link' button
|
||||
* Caja file manager plugin
|
||||
* Make "backup detected" message to not trigger in wrong cases
|
||||
* SyncEngine: Fix renaming of folder when file are changed (#5192)
|
||||
* Fix reconnect bug if status.php intermittently returns wrong data (#5188)
|
||||
* Improve sync scheduling (#5317)
|
||||
* Overlay icons: Improvements in correctnes
|
||||
* Tray menu: Only update on demand to fix Linux desktop integration glitches
|
||||
* Progress: Better time/bandwidth estimations
|
||||
* Network: Follow certain HTTP redirects (#2791)
|
||||
* Network: Remove all cookies (including load balancers etc) when logging out
|
||||
* Discovery thread: Low priority
|
||||
* owncloudsync.log: Write during propagation
|
||||
* Better error message for files with trailing spaces on Windows
|
||||
* Excludes: Consider files in hidden folders excluded (#5163)
|
||||
* Allow sync directory to be a symlinked directory
|
||||
* Add manifest file on Windows to make the application UAC aware
|
||||
* macOS: Improve monochrome tray icons
|
||||
* Don't blacklist 507 Insufficent Storage #5346 (#5424)
|
||||
* Shibboleth bugfixes
|
||||
* Fixes with regards to low disk space
|
||||
* A ton of other bugfixes
|
||||
* Refactorings
|
||||
* Improved documentation
|
||||
* Crash fixes
|
||||
|
||||
version 2.2.4 (release 2016-09-27)
|
||||
* Dolphin Plugin: Use the Application name for the socket path (#5172)
|
||||
* SyncEngine: Fix renaming of folder when file are changed (#5195)
|
||||
* Selective Sync: Fix HTTP request loop and show error in view (#5154)
|
||||
* ConnectionValidator: properly handle error in status.php request (#5188)
|
||||
* Discovery: Set thread priority to low (#5017)
|
||||
* ExcludeFiles: Fix when the folder casing is not the same in the settings and in the FS
|
||||
* ShareLink: Ensure the password line edit is enabled (#5117)
|
||||
|
||||
version 2.2.3 (release 2016-08-08)
|
||||
* SyncEngine: Fix detection of backup (#5104)
|
||||
* Fix bug with overriding URL in config (#5016)
|
||||
* Sharing: Fix bug with file names containing percent encodes (#5042, #5043)
|
||||
* Sharing: Permissions for federated shares on servers >=9.1 (#4996, #5001)
|
||||
* Overlays: Fix issues with file name casing on OS X and Windows
|
||||
* Windows: Skip symlinks and junctions again (#5019)
|
||||
* Only accept notification API Capability if endpoint is OCS-enabled (#5034)
|
||||
* Fix windows HiDPI (#4994)
|
||||
* SocketAPI: Use different pipe name to avoid unusual delay (#4977)
|
||||
* Tray: Add minimal mode as workaround and testing tool for Linux issues (#4985, #4990)
|
||||
* owncloudcmd: Fix --exclude regression #4979
|
||||
* Small memleak: Use the full file stat destructors (#4992)
|
||||
* Fix small QAction memleak (#5008)
|
||||
* Fix crash on shutting down during propagation (#4979)
|
||||
* Decrease memory usage during sync #4979
|
||||
* Setup csync logging earlier to get all log output (#4991)
|
||||
* Enable Shibboleth debug view with OWNCLOUD_SHIBBOLETH_DEBUG env
|
||||
|
||||
version 2.2.2 (release 2016-06-21)
|
||||
* Excludes: Don't redundantly add the same exclude files (memleak) (#4967, #4988)
|
||||
* Excludes: Only log if the pattern was really logged. (#4989)
|
||||
|
||||
version 2.2.1 (release 2016-06-06)
|
||||
* Fix out of memory error when too many uploads happen (#4611)
|
||||
* Fix display errors in progress display (#4803 #4856)
|
||||
* LockWatcher: Remember to upload files after they become unlocked (#4865)
|
||||
* Fix overlay icons for files with umlauts (#4884)
|
||||
* Certs: Re-ask for different cert after rejection (#4898, #4911)
|
||||
* Progress: Don't count items without propagation jobs (#4856, #4910)
|
||||
* Utility: Fix for the translation of minutes, second (#4855)
|
||||
* SyncEngine: invalid the blacklist entry when the rename destination change
|
||||
|
||||
version 2.2.0 (release 2016-05-12)
|
||||
* Overlay icons: Refactoring - mainly for performance improvements
|
||||
|
||||
externo
+58
@@ -0,0 +1,58 @@
|
||||
#!groovy
|
||||
|
||||
node('CLIENT') {
|
||||
stage 'Checkout'
|
||||
checkout scm
|
||||
sh '''git submodule update --init'''
|
||||
|
||||
stage 'Qt4'
|
||||
sh '''rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=ON ..
|
||||
make
|
||||
ctest --output-on-failure'''
|
||||
|
||||
stage 'Qt4 - clang'
|
||||
sh '''rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=ON ..
|
||||
make
|
||||
ctest --output-on-failure'''
|
||||
|
||||
stage 'Qt5'
|
||||
sh '''rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF ..
|
||||
make
|
||||
ctest --output-on-failure'''
|
||||
|
||||
stage 'Qt5 - clang'
|
||||
sh '''rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF ..
|
||||
make
|
||||
ctest --output-on-failure'''
|
||||
|
||||
|
||||
stage 'Win32'
|
||||
def win32 = docker.image('deepdiver/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 .
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ with your computer.
|
||||
|
||||
### Binary packages
|
||||
|
||||
* Refer to the download page http://owncloud.org/sync-clients/
|
||||
* Refer to the download page https://owncloud.org/install/#install-clients
|
||||
|
||||
### Source code
|
||||
|
||||
@@ -27,7 +27,7 @@ https://github.com/owncloud/client.
|
||||
|
||||
## Building the source code
|
||||
|
||||
[Building the Client](http://doc.owncloud.org/desktop/2.0/building.html)
|
||||
[Building the Client](http://doc.owncloud.org/desktop/2.2/building.html)
|
||||
in the ownCloud Desktop Client manual.
|
||||
|
||||
## Maintainers and Contributors
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#
|
||||
# ownCloud is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ownCLoud is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -39,7 +40,6 @@ QT_PLUGINS = [
|
||||
'imageformats/libqico.dylib',
|
||||
'imageformats/libqjpeg.dylib',
|
||||
'imageformats/libqsvg.dylib',
|
||||
'imageformats/libqmng.dylib',
|
||||
]
|
||||
|
||||
QT_PLUGINS_SEARCH_PATH=[
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
From ea4dcc5931d455e4ee3e958ffa54a9f54ab022c8 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <daniel@molkentin.de>
|
||||
Date: Mon, 5 Jan 2015 10:45:25 +0100
|
||||
Subject: [PATCH 1/3] Fix crash on Mac OS if PAC URL contains non-URL legal
|
||||
chars
|
||||
|
||||
macQueryInternal() was retrieving the PAC URL string as-entered by
|
||||
the user in the 'Proxies' tab of the system network settings dialog
|
||||
and passing it to CFURLCreateWithString().
|
||||
|
||||
CFURLCreateWithString() returns null if the input string contains
|
||||
non-URL legal chars or is empty.
|
||||
|
||||
Change-Id: I9166d0433a62c7b2274b5435a7dea0a16997d10e
|
||||
Patch-By: Robert Knight
|
||||
Task-number: QTBUG-36787
|
||||
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
|
||||
Reviewed-by: Markus Goetz <markus@woboq.com>
|
||||
---
|
||||
src/network/kernel/qnetworkproxy_mac.cpp | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
index 7d26246..81bce0c 100644
|
||||
--- a/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
@@ -221,7 +221,11 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
|
||||
int enabled;
|
||||
if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
|
||||
// PAC is enabled
|
||||
- CFStringRef cfPacLocation = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
|
||||
+ // kSCPropNetProxiesProxyAutoConfigURLString returns the URL string
|
||||
+ // as entered in the system proxy configuration dialog
|
||||
+ CFStringRef pacLocationSetting = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
|
||||
+ QCFType<CFStringRef> cfPacLocation = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, pacLocationSetting, NULL, NULL,
|
||||
+ kCFStringEncodingUTF8);
|
||||
|
||||
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
|
||||
QCFType<CFDataRef> pacData;
|
||||
--
|
||||
1.8.3.4 (Apple Git-47)
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
From a83e4d1d9dd90d4563ce60f27dfb7802a780e33e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <daniel@molkentin.de>
|
||||
Date: Mon, 5 Jan 2015 11:42:52 +0100
|
||||
Subject: [PATCH 2/3] Fix possible crash when passing an invalid PAC URL
|
||||
|
||||
This commit checks whether CFURLCreateWithString() succeeded.
|
||||
|
||||
It does not appear to be possible to enter an empty URL directly in the
|
||||
PAC configuration dialog but I can't rule out the possibility
|
||||
that it could find its way into the settings via some other means.
|
||||
|
||||
Change-Id: I6c2053d385503bf0330f5ae9fb1ec36a473d425d
|
||||
Patch-By: Robert Knight
|
||||
Task-number: QTBUG-36787
|
||||
Reviewed-by: Markus Goetz <markus@woboq.com>
|
||||
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
|
||||
---
|
||||
src/network/kernel/qnetworkproxy_mac.cpp | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
index 81bce0c..6be032e 100644
|
||||
--- a/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
@@ -230,6 +230,10 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
|
||||
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
|
||||
QCFType<CFDataRef> pacData;
|
||||
QCFType<CFURLRef> pacUrl = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, NULL);
|
||||
+ if (!pacUrl) {
|
||||
+ qWarning("Invalid PAC URL \"%s\"", qPrintable(QCFString::toQString(cfPacLocation)));
|
||||
+ return result;
|
||||
+ }
|
||||
SInt32 errorCode;
|
||||
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacUrl, &pacData, NULL, NULL, &errorCode)) {
|
||||
QString pacLocation = QCFString::toQString(cfPacLocation);
|
||||
--
|
||||
1.8.3.4 (Apple Git-47)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From 83bd9393e5564ea9168fda90c0f44456633a483a Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <daniel@molkentin.de>
|
||||
Date: Mon, 5 Jan 2015 15:22:57 +0100
|
||||
Subject: [PATCH 3/3] Fix crash if PAC script retrieval returns a null CFData
|
||||
instance
|
||||
|
||||
The documentation for CFURLCreateDataAndPropertiesFromResource()
|
||||
does not make this clear but from looking at the CFNetwork implementation
|
||||
and a user stacktrace it appears that this function can return true
|
||||
but not set the data argument under certain circumstances.
|
||||
|
||||
Change-Id: I48034a640d6f47a51cd5883bbafacad4bcbd0415
|
||||
Task-number: QTBUG-36787
|
||||
Patch-By: Robert Knight
|
||||
Reviewed-by: Markus Goetz <markus@woboq.com>
|
||||
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
|
||||
---
|
||||
src/network/kernel/qnetworkproxy_mac.cpp | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
index 6be032e..a1ac349 100644
|
||||
--- a/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||
@@ -240,7 +240,10 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
|
||||
qWarning("Unable to get the PAC script at \"%s\" (%s)", qPrintable(pacLocation), cfurlErrorDescription(errorCode));
|
||||
return result;
|
||||
}
|
||||
-
|
||||
+ if (!pacData) {
|
||||
+ qWarning("\"%s\" returned an empty PAC script", qPrintable(QCFString::toQString(cfPacLocation)));
|
||||
+ return result;
|
||||
+ }
|
||||
QCFType<CFStringRef> pacScript = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1);
|
||||
if (!pacScript) {
|
||||
// This should never happen, but the documentation says it may return NULL if there was a problem creating the object.
|
||||
--
|
||||
1.8.3.4 (Apple Git-47)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
From 22f3d359350fd65e4bbe2e9420fcc4460e8a590a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= <morten.sorvig@digia.com>
|
||||
Date: Tue, 10 Mar 2015 22:37:39 +0100
|
||||
Subject: [PATCH] Cocoa: Fix systray SVG icons.
|
||||
|
||||
Regression caused by f3699510.
|
||||
|
||||
Task-number: QTBUG-44686
|
||||
Change-Id: I546422a67d4da29fac196025b09bddcb45c1b641
|
||||
Reviewed-by: Timur Pocheptsov <Timur.Pocheptsov@digia.com>
|
||||
---
|
||||
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
index e449fd3..8a35705 100755
|
||||
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
@@ -234,6 +234,10 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
}
|
||||
}
|
||||
|
||||
+ // Handle SVG icons, which do not return anything for availableSizes().
|
||||
+ if (!selectedSize.isValid())
|
||||
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
|
||||
+
|
||||
QPixmap pixmap = icon.pixmap(selectedSize, mode);
|
||||
|
||||
// Draw a low-resolution icon if there is not enough pixels for a retina
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
From ee7fea33383726f0bb72e8082a357820e3ee3675 Mon Sep 17 00:00:00 2001
|
||||
From: Jocelyn Turcotte <jturcotte@woboq.com>
|
||||
Date: Tue, 24 Feb 2015 17:02:02 +0100
|
||||
Subject: [PATCH] OSX Fix disapearing tray icon
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It would happen together with an error:
|
||||
QPainter::begin: Paint device returned engine == 0
|
||||
and would be caused by the size provided to QIcon::pixmap being empty,
|
||||
itself caused by the availableSizes list being empty for the Selected
|
||||
mode.
|
||||
|
||||
This bug was most often hidden by the fact that the Selected icon mode
|
||||
was not triggered properly since we usually only set menuVisible after
|
||||
calling updateIcon, and most of the time when it did, we would overwrite
|
||||
it right after with a Normal mode icon.
|
||||
|
||||
Fix the issue by disabling the broken feature completely since the
|
||||
default Selected icon is grayed out while tray icons are now usually
|
||||
black (or white when selected). To support the dark menu bar mode on
|
||||
10.10 we'll need to use NSImage's setTemplate anyway and that
|
||||
knowing in advance if we can invert the colors ourselves would also
|
||||
better solve the menuVisible usecase.
|
||||
|
||||
Task-number: QTBUG-42910
|
||||
Change-Id: If9ec9659af28ecceb841bfc2f11721e6029fe891
|
||||
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
|
||||
---
|
||||
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 17 +++--------------
|
||||
1 file changed, 3 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
index 8a35705..d366a3c 100755
|
||||
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
@@ -102,7 +102,6 @@ QT_USE_NAMESPACE
|
||||
QCocoaSystemTrayIcon *systray;
|
||||
NSStatusItem *item;
|
||||
QCocoaMenu *menu;
|
||||
- bool menuVisible;
|
||||
QIcon icon;
|
||||
QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
|
||||
}
|
||||
@@ -202,8 +201,6 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
|
||||
m_sys->item->icon = icon;
|
||||
|
||||
- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
|
||||
-
|
||||
// The reccomended maximum title bar icon height is 18 points
|
||||
// (device independent pixels). The menu height on past and
|
||||
// current OS X versions is 22 points. Provide some future-proofing
|
||||
@@ -218,9 +215,8 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
// devicePixelRatio for the "best" screen on the system.
|
||||
qreal devicePixelRatio = qApp->devicePixelRatio();
|
||||
const int maxPixmapHeight = maxImageHeight * devicePixelRatio;
|
||||
- const QIcon::Mode mode = menuVisible ? QIcon::Selected : QIcon::Normal;
|
||||
QSize selectedSize;
|
||||
- Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) {
|
||||
+ Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes())) {
|
||||
// Select a pixmap based on the height. We want the largest pixmap
|
||||
// with a height smaller or equal to maxPixmapHeight. The pixmap
|
||||
// may rectangular; assume it has a reasonable size. If there is
|
||||
@@ -236,9 +232,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
|
||||
// Handle SVG icons, which do not return anything for availableSizes().
|
||||
if (!selectedSize.isValid())
|
||||
- selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
|
||||
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight));
|
||||
|
||||
- QPixmap pixmap = icon.pixmap(selectedSize, mode);
|
||||
+ QPixmap pixmap = icon.pixmap(selectedSize);
|
||||
|
||||
// Draw a low-resolution icon if there is not enough pixels for a retina
|
||||
// icon. This prevents showing a small icon on retina displays.
|
||||
@@ -385,9 +381,6 @@ QT_END_NAMESPACE
|
||||
Q_UNUSED(notification);
|
||||
down = NO;
|
||||
|
||||
- parent->systray->updateIcon(parent->icon);
|
||||
- parent->menuVisible = false;
|
||||
-
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -397,8 +390,6 @@ QT_END_NAMESPACE
|
||||
int clickCount = [mouseEvent clickCount];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
- parent->systray->updateIcon(parent->icon);
|
||||
-
|
||||
if (clickCount == 2) {
|
||||
[self menuTrackingDone:nil];
|
||||
[parent doubleClickSelector:self];
|
||||
@@ -454,7 +445,6 @@ QT_END_NAMESPACE
|
||||
if (self) {
|
||||
item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
|
||||
menu = 0;
|
||||
- menuVisible = false;
|
||||
systray = sys;
|
||||
imageCell = [[QNSImageView alloc] initWithParent:self];
|
||||
[item setView: imageCell];
|
||||
@@ -498,7 +488,6 @@ QT_END_NAMESPACE
|
||||
selector:@selector(menuTrackingDone:)
|
||||
name:NSMenuDidEndTrackingNotification
|
||||
object:m];
|
||||
- menuVisible = true;
|
||||
[item popUpStatusItemMenu: m];
|
||||
}
|
||||
}
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,691 +0,0 @@
|
||||
From cff39fba10ffc10ee4dcfdc66ff6528eb26462d3 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Goetz <markus@woboq.com>
|
||||
Date: Fri, 10 Apr 2015 14:09:53 +0200
|
||||
Subject: [PATCH] QNAM: Fix upload corruptions when server closes connection
|
||||
|
||||
This patch fixes several upload corruptions if the server closes the connection
|
||||
while/before we send data into it. They happen inside multiple places in the HTTP
|
||||
layer and are explained in the comments.
|
||||
Corruptions are:
|
||||
* The upload byte device has an in-flight signal with pending upload data, if
|
||||
it gets reset (because server closes the connection) then the re-send of the
|
||||
request was sometimes taking this stale in-flight pending upload data.
|
||||
* Because some signals were DirectConnection and some were QueuedConnection, there
|
||||
was a chance that a direct signal overtakes a queued signal. The state machine
|
||||
then sent data down the socket which was buffered there (and sent later) although
|
||||
it did not match the current state of the state machine when it was actually sent.
|
||||
* A socket was seen as being able to have requests sent even though it was not
|
||||
encrypted yet. This relates to the previous corruption where data is stored inside
|
||||
the socket's buffer and then sent later.
|
||||
|
||||
The included auto test produces all fixed corruptions, I detected no regressions
|
||||
via the other tests.
|
||||
This code also adds a bit of sanity checking to protect from possible further
|
||||
problems.
|
||||
|
||||
[ChangeLog][QtNetwork] Fix HTTP(s) upload corruption when server closes connection
|
||||
|
||||
Change-Id: I54c883925ec897050941498f139c4b523030432e
|
||||
Reviewed-by: Peter Hartmann <peter-qt@hartmann.tk>
|
||||
---
|
||||
src/corelib/io/qnoncontiguousbytedevice.cpp | 18 +++
|
||||
src/corelib/io/qnoncontiguousbytedevice_p.h | 4 +
|
||||
.../access/qhttpnetworkconnectionchannel.cpp | 35 ++++-
|
||||
.../access/qhttpnetworkconnectionchannel_p.h | 2 +
|
||||
src/network/access/qhttpprotocolhandler.cpp | 7 +
|
||||
src/network/access/qhttpthreaddelegate_p.h | 36 ++++-
|
||||
src/network/access/qnetworkreplyhttpimpl.cpp | 25 ++-
|
||||
src/network/access/qnetworkreplyhttpimpl_p.h | 7 +-
|
||||
.../access/qnetworkreply/tst_qnetworkreply.cpp | 175 ++++++++++++++++++++-
|
||||
9 files changed, 279 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
|
||||
index 11510a8..760ca3d 100644
|
||||
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
|
||||
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
|
||||
@@ -236,6 +236,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size()
|
||||
return byteArray->size();
|
||||
}
|
||||
|
||||
+qint64 QNonContiguousByteDeviceByteArrayImpl::pos()
|
||||
+{
|
||||
+ return currentPosition;
|
||||
+}
|
||||
+
|
||||
QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb)
|
||||
: QNonContiguousByteDevice(), currentPosition(0)
|
||||
{
|
||||
@@ -273,6 +278,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
|
||||
return currentPosition >= size();
|
||||
}
|
||||
|
||||
+qint64 QNonContiguousByteDeviceRingBufferImpl::pos()
|
||||
+{
|
||||
+ return currentPosition;
|
||||
+}
|
||||
+
|
||||
bool QNonContiguousByteDeviceRingBufferImpl::reset()
|
||||
{
|
||||
if (resetDisabled)
|
||||
@@ -406,6 +416,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
|
||||
return device->size() - initialPosition;
|
||||
}
|
||||
|
||||
+qint64 QNonContiguousByteDeviceIoDeviceImpl::pos()
|
||||
+{
|
||||
+ if (device->isSequential())
|
||||
+ return -1;
|
||||
+
|
||||
+ return device->pos();
|
||||
+}
|
||||
+
|
||||
QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
|
||||
{
|
||||
byteDevice = bd;
|
||||
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
|
||||
index c05ae11..4d7b7b0 100644
|
||||
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
|
||||
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0;
|
||||
virtual bool advanceReadPointer(qint64 amount) = 0;
|
||||
virtual bool atEnd() = 0;
|
||||
+ virtual qint64 pos() { return -1; }
|
||||
virtual bool reset() = 0;
|
||||
void disableReset();
|
||||
bool isResetDisabled() { return resetDisabled; }
|
||||
@@ -106,6 +107,7 @@ public:
|
||||
bool atEnd();
|
||||
bool reset();
|
||||
qint64 size();
|
||||
+ qint64 pos() Q_DECL_OVERRIDE;
|
||||
protected:
|
||||
QByteArray* byteArray;
|
||||
qint64 currentPosition;
|
||||
@@ -121,6 +123,7 @@ public:
|
||||
bool atEnd();
|
||||
bool reset();
|
||||
qint64 size();
|
||||
+ qint64 pos() Q_DECL_OVERRIDE;
|
||||
protected:
|
||||
QSharedPointer<QRingBuffer> ringBuffer;
|
||||
qint64 currentPosition;
|
||||
@@ -138,6 +141,7 @@ public:
|
||||
bool atEnd();
|
||||
bool reset();
|
||||
qint64 size();
|
||||
+ qint64 pos() Q_DECL_OVERRIDE;
|
||||
protected:
|
||||
QIODevice* device;
|
||||
QByteArray* currentReadBuffer;
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
index 9f63280..49c6793 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
@@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init()
|
||||
socket->setProxy(QNetworkProxy::NoProxy);
|
||||
#endif
|
||||
|
||||
+ // We want all signals (except the interactive ones) be connected as QueuedConnection
|
||||
+ // because else we're falling into cases where we recurse back into the socket code
|
||||
+ // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
|
||||
+ // is safer.
|
||||
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
|
||||
this, SLOT(_q_bytesWritten(qint64)),
|
||||
- Qt::DirectConnection);
|
||||
+ Qt::QueuedConnection);
|
||||
QObject::connect(socket, SIGNAL(connected()),
|
||||
this, SLOT(_q_connected()),
|
||||
- Qt::DirectConnection);
|
||||
+ Qt::QueuedConnection);
|
||||
QObject::connect(socket, SIGNAL(readyRead()),
|
||||
this, SLOT(_q_readyRead()),
|
||||
- Qt::DirectConnection);
|
||||
+ Qt::QueuedConnection);
|
||||
|
||||
// The disconnected() and error() signals may already come
|
||||
// while calling connectToHost().
|
||||
@@ -143,13 +147,13 @@ void QHttpNetworkConnectionChannel::init()
|
||||
// won't be a sslSocket if encrypt is false
|
||||
QObject::connect(sslSocket, SIGNAL(encrypted()),
|
||||
this, SLOT(_q_encrypted()),
|
||||
- Qt::DirectConnection);
|
||||
+ Qt::QueuedConnection);
|
||||
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
|
||||
this, SLOT(_q_sslErrors(QList<QSslError>)),
|
||||
Qt::DirectConnection);
|
||||
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
|
||||
this, SLOT(_q_encryptedBytesWritten(qint64)),
|
||||
- Qt::DirectConnection);
|
||||
+ Qt::QueuedConnection);
|
||||
|
||||
if (ignoreAllSslErrors)
|
||||
sslSocket->ignoreSslErrors();
|
||||
@@ -186,8 +190,11 @@ void QHttpNetworkConnectionChannel::close()
|
||||
// pendingEncrypt must only be true in between connected and encrypted states
|
||||
pendingEncrypt = false;
|
||||
|
||||
- if (socket)
|
||||
+ if (socket) {
|
||||
+ // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
|
||||
+ // there is no socket yet.
|
||||
socket->close();
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
@@ -353,6 +360,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
+
|
||||
+ // This code path for ConnectedState
|
||||
+ if (pendingEncrypt) {
|
||||
+ // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up
|
||||
+ // and corrupt the things sent to the server.
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -659,6 +674,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
|
||||
void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
|
||||
{
|
||||
Q_UNUSED(bytes);
|
||||
+ if (ssl) {
|
||||
+ // In the SSL case we want to send data from encryptedBytesWritten signal since that one
|
||||
+ // is the one going down to the actual network, not only into some SSL buffer.
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// bytes have been written to the socket. write even more of them :)
|
||||
if (isSocketWriting())
|
||||
sendRequest();
|
||||
@@ -734,7 +755,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
||||
|
||||
// ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
|
||||
//channels[i].reconnectAttempts = 2;
|
||||
- if (pendingEncrypt) {
|
||||
+ if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
|
||||
#ifndef QT_NO_SSL
|
||||
if (connection->sslContext().isNull()) {
|
||||
// this socket is making the 1st handshake for this connection,
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||
index 692c0e6..231fe11 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||
@@ -83,6 +83,8 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
|
||||
class QHttpNetworkConnectionChannel : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
+ // TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt).
|
||||
+ // Also add an Unconnected state so IdleState does not have double meaning.
|
||||
enum ChannelState {
|
||||
IdleState = 0, // ready to send request
|
||||
ConnectingState = 1, // connecting to host
|
||||
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
||||
index 28e10f7..3357948 100644
|
||||
--- a/src/network/access/qhttpprotocolhandler.cpp
|
||||
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
||||
@@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest()
|
||||
// nothing to read currently, break the loop
|
||||
break;
|
||||
} else {
|
||||
+ if (m_channel->written != uploadByteDevice->pos()) {
|
||||
+ // Sanity check. This was useful in tracking down an upload corruption.
|
||||
+ qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos();
|
||||
+ Q_ASSERT(m_channel->written == uploadByteDevice->pos());
|
||||
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
|
||||
+ return false;
|
||||
+ }
|
||||
qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize);
|
||||
if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
|
||||
// socket broke down
|
||||
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
|
||||
index 1661082..b553409 100644
|
||||
--- a/src/network/access/qhttpthreaddelegate_p.h
|
||||
+++ b/src/network/access/qhttpthreaddelegate_p.h
|
||||
@@ -187,6 +187,7 @@ protected:
|
||||
QByteArray m_dataArray;
|
||||
bool m_atEnd;
|
||||
qint64 m_size;
|
||||
+ qint64 m_pos; // to match calls of haveDataSlot with the expected position
|
||||
public:
|
||||
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
|
||||
: QNonContiguousByteDevice(),
|
||||
@@ -194,7 +195,8 @@ public:
|
||||
m_amount(0),
|
||||
m_data(0),
|
||||
m_atEnd(aE),
|
||||
- m_size(s)
|
||||
+ m_size(s),
|
||||
+ m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -202,6 +204,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
+ qint64 pos() Q_DECL_OVERRIDE
|
||||
+ {
|
||||
+ return m_pos;
|
||||
+ }
|
||||
+
|
||||
const char* readPointer(qint64 maximumLength, qint64 &len)
|
||||
{
|
||||
if (m_amount > 0) {
|
||||
@@ -229,11 +236,10 @@ public:
|
||||
|
||||
m_amount -= a;
|
||||
m_data += a;
|
||||
+ m_pos += a;
|
||||
|
||||
- // To main thread to inform about our state
|
||||
- emit processedData(a);
|
||||
-
|
||||
- // FIXME possible optimization, already ask user thread for some data
|
||||
+ // To main thread to inform about our state. The m_pos will be sent as a sanity check.
|
||||
+ emit processedData(m_pos, a);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -250,10 +256,21 @@ public:
|
||||
{
|
||||
m_amount = 0;
|
||||
m_data = 0;
|
||||
+ m_dataArray.clear();
|
||||
+
|
||||
+ if (wantDataPending) {
|
||||
+ // had requested the user thread to send some data (only 1 in-flight at any moment)
|
||||
+ wantDataPending = false;
|
||||
+ }
|
||||
|
||||
// Communicate as BlockingQueuedConnection
|
||||
bool b = false;
|
||||
emit resetData(&b);
|
||||
+ if (b) {
|
||||
+ // the reset succeeded, we're at pos 0 again
|
||||
+ m_pos = 0;
|
||||
+ // the HTTP code will anyway abort the request if !b.
|
||||
+ }
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -264,8 +281,13 @@ public:
|
||||
|
||||
public slots:
|
||||
// From user thread:
|
||||
- void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
|
||||
+ void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
|
||||
{
|
||||
+ if (pos != m_pos) {
|
||||
+ // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the
|
||||
+ // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk.
|
||||
+ return;
|
||||
+ }
|
||||
wantDataPending = false;
|
||||
|
||||
m_dataArray = dataArray;
|
||||
@@ -285,7 +307,7 @@ signals:
|
||||
|
||||
// to main thread:
|
||||
void wantData(qint64);
|
||||
- void processedData(qint64);
|
||||
+ void processedData(qint64 pos, qint64 amount);
|
||||
void resetData(bool *b);
|
||||
};
|
||||
|
||||
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||
index 4ce7303..974a101 100644
|
||||
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||
@@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate()
|
||||
, synchronous(false)
|
||||
, state(Idle)
|
||||
, statusCode(0)
|
||||
+ , uploadByteDevicePosition(false)
|
||||
, uploadDeviceChoking(false)
|
||||
, outgoingData(0)
|
||||
, bytesUploaded(-1)
|
||||
@@ -863,9 +864,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
||||
q, SLOT(uploadByteDeviceReadyReadSlot()),
|
||||
Qt::QueuedConnection);
|
||||
|
||||
- // From main thread to user thread:
|
||||
- QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)),
|
||||
- forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection);
|
||||
+ // From user thread to http thread:
|
||||
+ QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
|
||||
+ forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
|
||||
QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
|
||||
forwardUploadDevice, SIGNAL(readyRead()),
|
||||
Qt::QueuedConnection);
|
||||
@@ -873,8 +874,8 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
||||
// From http thread to user thread:
|
||||
QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
|
||||
q, SLOT(wantUploadDataSlot(qint64)));
|
||||
- QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
|
||||
- q, SLOT(sentUploadDataSlot(qint64)));
|
||||
+ QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)),
|
||||
+ q, SLOT(sentUploadDataSlot(qint64,qint64)));
|
||||
QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
|
||||
q, SLOT(resetUploadDataSlot(bool*)),
|
||||
Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
|
||||
@@ -1268,12 +1269,22 @@ void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfig
|
||||
void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r)
|
||||
{
|
||||
*r = uploadByteDevice->reset();
|
||||
+ if (*r) {
|
||||
+ // reset our own position which is used for the inter-thread communication
|
||||
+ uploadByteDevicePosition = 0;
|
||||
+ }
|
||||
}
|
||||
|
||||
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
|
||||
-void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount)
|
||||
+void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount)
|
||||
{
|
||||
+ if (uploadByteDevicePosition + amount != pos) {
|
||||
+ // Sanity check, should not happen.
|
||||
+ error(QNetworkReply::UnknownNetworkError, "");
|
||||
+ return;
|
||||
+ }
|
||||
uploadByteDevice->advanceReadPointer(amount);
|
||||
+ uploadByteDevicePosition += amount;
|
||||
}
|
||||
|
||||
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
|
||||
@@ -1298,7 +1309,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize)
|
||||
QByteArray dataArray(data, currentUploadDataLength);
|
||||
|
||||
// Communicate back to HTTP thread
|
||||
- emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
|
||||
+ emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
|
||||
}
|
||||
|
||||
void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot()
|
||||
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
|
||||
index 77d9c5a..1940922 100644
|
||||
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
|
||||
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
|
||||
Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r))
|
||||
Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64))
|
||||
- Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64))
|
||||
+ Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot())
|
||||
Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
|
||||
@@ -144,7 +144,7 @@ signals:
|
||||
|
||||
void startHttpRequestSynchronously();
|
||||
|
||||
- void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
|
||||
+ void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
|
||||
};
|
||||
|
||||
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
|
||||
@@ -195,6 +195,7 @@ public:
|
||||
// upload
|
||||
QNonContiguousByteDevice* createUploadByteDevice();
|
||||
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
|
||||
+ qint64 uploadByteDevicePosition;
|
||||
bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment
|
||||
QIODevice *outgoingData;
|
||||
QSharedPointer<QRingBuffer> outgoingDataBuffer;
|
||||
@@ -283,7 +284,7 @@ public:
|
||||
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
|
||||
void resetUploadDataSlot(bool *r);
|
||||
void wantUploadDataSlot(qint64);
|
||||
- void sentUploadDataSlot(qint64);
|
||||
+ void sentUploadDataSlot(qint64, qint64);
|
||||
|
||||
// From user's QNonContiguousByteDevice
|
||||
void uploadByteDeviceReadyReadSlot();
|
||||
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||
index 3ccedf6..d2edf67 100644
|
||||
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||
@@ -457,6 +457,10 @@ private Q_SLOTS:
|
||||
|
||||
void putWithRateLimiting();
|
||||
|
||||
+#ifndef QT_NO_SSL
|
||||
+ void putWithServerClosingConnectionImmediately();
|
||||
+#endif
|
||||
+
|
||||
// NOTE: This test must be last!
|
||||
void parentingRepliesToTheApp();
|
||||
private:
|
||||
@@ -4718,18 +4722,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
|
||||
class SslServer : public QTcpServer {
|
||||
Q_OBJECT
|
||||
public:
|
||||
- SslServer() : socket(0) {};
|
||||
+ SslServer() : socket(0), m_ssl(true) {}
|
||||
void incomingConnection(qintptr socketDescriptor) {
|
||||
QSslSocket *serverSocket = new QSslSocket;
|
||||
serverSocket->setParent(this);
|
||||
|
||||
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
|
||||
+ connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||
+ if (!m_ssl) {
|
||||
+ emit newPlainConnection(serverSocket);
|
||||
+ return;
|
||||
+ }
|
||||
QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
|
||||
if (testDataDir.isEmpty())
|
||||
testDataDir = QCoreApplication::applicationDirPath();
|
||||
|
||||
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
|
||||
- connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||
serverSocket->setProtocol(QSsl::AnyProtocol);
|
||||
connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors()));
|
||||
serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
|
||||
@@ -4740,11 +4748,12 @@ public:
|
||||
}
|
||||
}
|
||||
signals:
|
||||
- void newEncryptedConnection();
|
||||
+ void newEncryptedConnection(QSslSocket *s);
|
||||
+ void newPlainConnection(QSslSocket *s);
|
||||
public slots:
|
||||
void encryptedSlot() {
|
||||
socket = (QSslSocket*) sender();
|
||||
- emit newEncryptedConnection();
|
||||
+ emit newEncryptedConnection(socket);
|
||||
}
|
||||
void readyReadSlot() {
|
||||
// for the incoming sockets, not the server socket
|
||||
@@ -4753,6 +4762,7 @@ public slots:
|
||||
|
||||
public:
|
||||
QSslSocket *socket;
|
||||
+ bool m_ssl;
|
||||
};
|
||||
|
||||
// very similar to ioPostToHttpUploadProgress but for SSL
|
||||
@@ -4780,7 +4790,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
QNetworkReplyPtr reply(manager.post(request, sourceFile));
|
||||
|
||||
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
|
||||
- connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
+ connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors()));
|
||||
|
||||
// get the request started and the incoming socket connected
|
||||
@@ -4788,7 +4798,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QTcpSocket *incomingSocket = server.socket;
|
||||
QVERIFY(incomingSocket);
|
||||
- disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
+ disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
|
||||
|
||||
incomingSocket->setReadBufferSize(1*1024);
|
||||
@@ -7905,6 +7915,159 @@ void tst_QNetworkReply::putWithRateLimiting()
|
||||
}
|
||||
|
||||
|
||||
+#ifndef QT_NO_SSL
|
||||
+
|
||||
+class PutWithServerClosingConnectionImmediatelyHandler: public QObject
|
||||
+{
|
||||
+ Q_OBJECT
|
||||
+public:
|
||||
+ bool m_parsedHeaders;
|
||||
+ QByteArray m_receivedData;
|
||||
+ QByteArray m_expectedData;
|
||||
+ QSslSocket *m_socket;
|
||||
+ PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s)
|
||||
+ {
|
||||
+ m_socket->setParent(this);
|
||||
+ connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot()));
|
||||
+ connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot()));
|
||||
+ }
|
||||
+signals:
|
||||
+ void correctFileUploadReceived();
|
||||
+ void corruptFileUploadReceived();
|
||||
+
|
||||
+public slots:
|
||||
+ void closeDelayed() {
|
||||
+ m_socket->close();
|
||||
+ }
|
||||
+
|
||||
+ void readyReadSlot()
|
||||
+ {
|
||||
+ QByteArray data = m_socket->readAll();
|
||||
+ m_receivedData += data;
|
||||
+ if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
|
||||
+ m_parsedHeaders = true;
|
||||
+ QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
|
||||
+ // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
|
||||
+ // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
|
||||
+ // This test catches that.
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+ void disconnectedSlot()
|
||||
+ {
|
||||
+ if (m_parsedHeaders) {
|
||||
+ //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n"));
|
||||
+ m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data
|
||||
+ }
|
||||
+ if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) {
|
||||
+ // We had received some data but it is corrupt!
|
||||
+ qDebug() << "CORRUPT" << m_receivedData.count();
|
||||
+
|
||||
+ // Use this to track down the pattern of the corruption and conclude the source
|
||||
+// QFile a("/tmp/corrupt");
|
||||
+// a.open(QIODevice::WriteOnly);
|
||||
+// a.write(m_receivedData);
|
||||
+// a.close();
|
||||
+
|
||||
+// QFile b("/tmp/correct");
|
||||
+// b.open(QIODevice::WriteOnly);
|
||||
+// b.write(m_expectedData);
|
||||
+// b.close();
|
||||
+ //exit(1);
|
||||
+ emit corruptFileUploadReceived();
|
||||
+ } else {
|
||||
+ emit correctFileUploadReceived();
|
||||
+ }
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+class PutWithServerClosingConnectionImmediatelyServer: public SslServer
|
||||
+{
|
||||
+ Q_OBJECT
|
||||
+public:
|
||||
+ int m_correctUploads;
|
||||
+ int m_corruptUploads;
|
||||
+ int m_repliesFinished;
|
||||
+ int m_expectedReplies;
|
||||
+ QByteArray m_expectedData;
|
||||
+ PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0)
|
||||
+ {
|
||||
+ QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
|
||||
+ QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
|
||||
+ }
|
||||
+
|
||||
+public slots:
|
||||
+ void createHandlerForConnection(QSslSocket* s) {
|
||||
+ PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData);
|
||||
+ handler->setParent(this);
|
||||
+ QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect()));
|
||||
+ QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt()));
|
||||
+ }
|
||||
+ void increaseCorrect() {
|
||||
+ m_correctUploads++;
|
||||
+ }
|
||||
+ void increaseCorrupt() {
|
||||
+ m_corruptUploads++;
|
||||
+ }
|
||||
+ void replyFinished() {
|
||||
+ m_repliesFinished++;
|
||||
+ if (m_repliesFinished == m_expectedReplies) {
|
||||
+ QTestEventLoop::instance().exitLoop();
|
||||
+ }
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
+void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
|
||||
+{
|
||||
+ const int numUploads = 40;
|
||||
+ qint64 wantedSize = 512*1024; // 512 kB
|
||||
+ QByteArray sourceFile;
|
||||
+ for (int i = 0; i < wantedSize; ++i) {
|
||||
+ sourceFile += (char)'a' +(i%26);
|
||||
+ }
|
||||
+ bool withSsl = false;
|
||||
+
|
||||
+ for (int s = 0; s <= 1; s++) {
|
||||
+ withSsl = (s == 1);
|
||||
+ // Test also needs to run several times because of 9c2ecf89
|
||||
+ for (int j = 0; j < 20; j++) {
|
||||
+ // emulate a minimal https server
|
||||
+ PutWithServerClosingConnectionImmediatelyServer server;
|
||||
+ server.m_ssl = withSsl;
|
||||
+ server.m_expectedData = sourceFile;
|
||||
+ server.m_expectedReplies = numUploads;
|
||||
+ server.listen(QHostAddress(QHostAddress::LocalHost), 0);
|
||||
+
|
||||
+ for (int i = 0; i < numUploads; i++) {
|
||||
+ // create the request
|
||||
+ QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i));
|
||||
+ QNetworkRequest request(url);
|
||||
+ QNetworkReply *reply = manager.put(request, sourceFile);
|
||||
+ connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
|
||||
+ connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished()));
|
||||
+ reply->setParent(&server);
|
||||
+ }
|
||||
+
|
||||
+ // get the request started and the incoming socket connected
|
||||
+ QTestEventLoop::instance().enterLoop(10);
|
||||
+
|
||||
+ //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
|
||||
+
|
||||
+ // Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
|
||||
+ QVERIFY(server.m_correctUploads > 5);
|
||||
+ // Because actually important is that we don't get any corruption:
|
||||
+ QCOMPARE(server.m_corruptUploads, 0);
|
||||
+
|
||||
+ server.close();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
|
||||
// NOTE: This test must be last testcase in tst_qnetworkreply!
|
||||
void tst_QNetworkReply::parentingRepliesToTheApp()
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
From eae0cb09f1310e755c2aff7c1112f7a6c09d7a53 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Goetz <markus@woboq.com>
|
||||
Date: Fri, 19 Jun 2015 15:35:34 +0200
|
||||
Subject: [PATCH] Network: Fix up previous corruption patch
|
||||
|
||||
This is a fix-up for cff39fba10ffc10ee4dcfdc66ff6528eb26462d3.
|
||||
That patch lead to some internal state issues that lead to the QTBUG-47048
|
||||
or to QNetworkReply objects erroring with "Connection Closed" when
|
||||
the server closed the Keep-Alive connection.
|
||||
|
||||
This patch changes the QNAM socket slot connections to be DirectConnection.
|
||||
We don't close the socket anymore in slots where it is anyway in a closed state
|
||||
afterwards. This prevents event/stack recursions.
|
||||
We also flush QSslSocket/QTcpSocket receive buffers when receiving a disconnect
|
||||
so that the developer always gets the full decrypted data from the buffers.
|
||||
|
||||
[ChangeLog][QtNetwork] Fix HTTP issues with "Unknown Error" and "Connection Closed"
|
||||
[ChangeLog][QtNetwork][Sockets] Read OS/encrypted read buffers when connection
|
||||
closed by server.
|
||||
|
||||
Change-Id: Ib4d6a2d0d988317e3a5356f36e8dbcee4590beed
|
||||
Task-number: QTBUG-47048
|
||||
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
|
||||
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||
---
|
||||
src/network/access/qhttpnetworkconnection.cpp | 1 -
|
||||
.../access/qhttpnetworkconnectionchannel.cpp | 108 +++++++++++++--------
|
||||
.../access/qhttpnetworkconnectionchannel_p.h | 1 +
|
||||
src/network/access/qhttpnetworkreply.cpp | 2 +-
|
||||
src/network/access/qhttpprotocolhandler.cpp | 1 -
|
||||
src/network/socket/qabstractsocket.cpp | 7 +-
|
||||
src/network/ssl/qsslsocket.cpp | 8 ++
|
||||
src/network/ssl/qsslsocket_openssl.cpp | 7 ++
|
||||
.../access/qnetworkreply/tst_qnetworkreply.cpp | 9 +-
|
||||
9 files changed, 94 insertions(+), 50 deletions(-)
|
||||
|
||||
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
|
||||
index 365ce55..543c70e 100644
|
||||
--- a/src/network/access/qhttpnetworkconnection.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnection.cpp
|
||||
@@ -917,7 +917,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
||||
for (int i = 0; i < channelCount; ++i) {
|
||||
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
|
||||
channels[i].resendCurrent = false;
|
||||
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
|
||||
|
||||
// if this is not possible, error will be emitted and connection terminated
|
||||
if (!channels[i].resetUploadData())
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
index 49c6793..e2f6307 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
|
||||
|
||||
+// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
|
||||
+// connection times out)
|
||||
+// We use 3 because we can get a _q_error 3 times depending on the timing:
|
||||
+static const int reconnectAttemptsDefault = 3;
|
||||
+
|
||||
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
|
||||
: socket(0)
|
||||
, ssl(false)
|
||||
@@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
|
||||
, resendCurrent(false)
|
||||
, lastStatus(0)
|
||||
, pendingEncrypt(false)
|
||||
- , reconnectAttempts(2)
|
||||
+ , reconnectAttempts(reconnectAttemptsDefault)
|
||||
, authMethod(QAuthenticatorPrivate::None)
|
||||
, proxyAuthMethod(QAuthenticatorPrivate::None)
|
||||
, authenticationCredentialsSent(false)
|
||||
@@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
|
||||
socket->setProxy(QNetworkProxy::NoProxy);
|
||||
#endif
|
||||
|
||||
- // We want all signals (except the interactive ones) be connected as QueuedConnection
|
||||
- // because else we're falling into cases where we recurse back into the socket code
|
||||
- // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
|
||||
- // is safer.
|
||||
+ // After some back and forth in all the last years, this is now a DirectConnection because otherwise
|
||||
+ // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
|
||||
+ // which behave slightly differently on Windows vs Linux
|
||||
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
|
||||
this, SLOT(_q_bytesWritten(qint64)),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
QObject::connect(socket, SIGNAL(connected()),
|
||||
this, SLOT(_q_connected()),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
QObject::connect(socket, SIGNAL(readyRead()),
|
||||
this, SLOT(_q_readyRead()),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
|
||||
// The disconnected() and error() signals may already come
|
||||
// while calling connectToHost().
|
||||
@@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
|
||||
qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||
QObject::connect(socket, SIGNAL(disconnected()),
|
||||
this, SLOT(_q_disconnected()),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
this, SLOT(_q_error(QAbstractSocket::SocketError)),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
@@ -147,13 +151,13 @@ void QHttpNetworkConnectionChannel::init()
|
||||
// won't be a sslSocket if encrypt is false
|
||||
QObject::connect(sslSocket, SIGNAL(encrypted()),
|
||||
this, SLOT(_q_encrypted()),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
|
||||
this, SLOT(_q_sslErrors(QList<QSslError>)),
|
||||
Qt::DirectConnection);
|
||||
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
|
||||
this, SLOT(_q_encryptedBytesWritten(qint64)),
|
||||
- Qt::QueuedConnection);
|
||||
+ Qt::DirectConnection);
|
||||
|
||||
if (ignoreAllSslErrors)
|
||||
sslSocket->ignoreSslErrors();
|
||||
@@ -397,7 +401,7 @@ void QHttpNetworkConnectionChannel::allDone()
|
||||
|
||||
// reset the reconnection attempts after we receive a complete reply.
|
||||
// in case of failures, each channel will attempt two reconnects before emitting error.
|
||||
- reconnectAttempts = 2;
|
||||
+ reconnectAttempts = reconnectAttemptsDefault;
|
||||
|
||||
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
|
||||
if (state != QHttpNetworkConnectionChannel::ClosingState)
|
||||
@@ -651,6 +655,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
|
||||
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
+void QHttpNetworkConnectionChannel::resendCurrentRequest()
|
||||
+{
|
||||
+ requeueCurrentlyPipelinedRequests();
|
||||
+ if (reply)
|
||||
+ resendCurrent = true;
|
||||
+ if (qobject_cast<QHttpNetworkConnection*>(connection))
|
||||
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||
+}
|
||||
+
|
||||
bool QHttpNetworkConnectionChannel::isSocketBusy() const
|
||||
{
|
||||
return (state & QHttpNetworkConnectionChannel::BusyState);
|
||||
@@ -694,8 +707,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
|
||||
return;
|
||||
}
|
||||
|
||||
- // read the available data before closing
|
||||
- if (isSocketWaiting() || isSocketReading()) {
|
||||
+ // read the available data before closing (also done in _q_error for other codepaths)
|
||||
+ if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
|
||||
if (reply) {
|
||||
state = QHttpNetworkConnectionChannel::ReadingState;
|
||||
_q_receiveReply();
|
||||
@@ -707,7 +720,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
|
||||
state = QHttpNetworkConnectionChannel::IdleState;
|
||||
|
||||
requeueCurrentlyPipelinedRequests();
|
||||
- close();
|
||||
+
|
||||
+ pendingEncrypt = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -789,11 +803,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
errorCode = QNetworkReply::ConnectionRefusedError;
|
||||
break;
|
||||
case QAbstractSocket::RemoteHostClosedError:
|
||||
- // try to reconnect/resend before sending an error.
|
||||
- // while "Reading" the _q_disconnected() will handle this.
|
||||
- if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
|
||||
+ // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
|
||||
+ // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
|
||||
+ // The reconnectAttempts handling catches the cases where we can re-send the request.
|
||||
+ if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
|
||||
+ // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
|
||||
+ // is sent on them. No need to error the other replies below. Just bail out here.
|
||||
+ // The _q_disconnected will handle the possibly pipelined replies
|
||||
+ return;
|
||||
+ } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
|
||||
+ // Try to reconnect/resend before sending an error.
|
||||
+ // While "Reading" the _q_disconnected() will handle this.
|
||||
if (reconnectAttempts-- > 0) {
|
||||
- closeAndResendCurrentRequest();
|
||||
+ resendCurrentRequest();
|
||||
return;
|
||||
} else {
|
||||
errorCode = QNetworkReply::RemoteHostClosedError;
|
||||
@@ -818,24 +840,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
// we can ignore the readbuffersize as the data is already
|
||||
// in memory and we will not receive more data on the socket.
|
||||
reply->setReadBufferSize(0);
|
||||
+ reply->setDownstreamLimited(false);
|
||||
_q_receiveReply();
|
||||
-#ifndef QT_NO_SSL
|
||||
- if (ssl) {
|
||||
- // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
|
||||
- // So we need to check this if the socket is a QSslSocket. When the socket is flushed
|
||||
- // it will force a decrypt of the encrypted data in the plainsocket.
|
||||
- QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
|
||||
- qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
|
||||
- while (sslSocket->encryptedBytesAvailable()) {
|
||||
- sslSocket->flush();
|
||||
- _q_receiveReply();
|
||||
- qint64 afterFlush = sslSocket->encryptedBytesAvailable();
|
||||
- if (afterFlush == beforeFlush)
|
||||
- break;
|
||||
- beforeFlush = afterFlush;
|
||||
- }
|
||||
+ if (!reply) {
|
||||
+ // No more reply assigned after the previous call? Then it had been finished successfully.
|
||||
+ requeueCurrentlyPipelinedRequests();
|
||||
+ state = QHttpNetworkConnectionChannel::IdleState;
|
||||
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||
+ return;
|
||||
}
|
||||
-#endif
|
||||
}
|
||||
|
||||
errorCode = QNetworkReply::RemoteHostClosedError;
|
||||
@@ -846,7 +859,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
case QAbstractSocket::SocketTimeoutError:
|
||||
// try to reconnect/resend before sending an error.
|
||||
if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
|
||||
- closeAndResendCurrentRequest();
|
||||
+ resendCurrentRequest();
|
||||
return;
|
||||
}
|
||||
errorCode = QNetworkReply::TimeoutError;
|
||||
@@ -860,7 +873,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
case QAbstractSocket::ProxyConnectionClosedError:
|
||||
// try to reconnect/resend before sending an error.
|
||||
if (reconnectAttempts-- > 0) {
|
||||
- closeAndResendCurrentRequest();
|
||||
+ resendCurrentRequest();
|
||||
return;
|
||||
}
|
||||
errorCode = QNetworkReply::ProxyConnectionClosedError;
|
||||
@@ -868,7 +881,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||
// try to reconnect/resend before sending an error.
|
||||
if (reconnectAttempts-- > 0) {
|
||||
- closeAndResendCurrentRequest();
|
||||
+ resendCurrentRequest();
|
||||
return;
|
||||
}
|
||||
errorCode = QNetworkReply::ProxyTimeoutError;
|
||||
@@ -916,8 +929,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
// send the next request
|
||||
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
|
||||
|
||||
- if (that) //signal emission triggered event loop
|
||||
- close();
|
||||
+ if (that) {
|
||||
+ //signal emission triggered event loop
|
||||
+ if (!socket)
|
||||
+ state = QHttpNetworkConnectionChannel::IdleState;
|
||||
+ else if (socket->state() == QAbstractSocket::UnconnectedState)
|
||||
+ state = QHttpNetworkConnectionChannel::IdleState;
|
||||
+ else
|
||||
+ state = QHttpNetworkConnectionChannel::ClosingState;
|
||||
+
|
||||
+ // pendingEncrypt must only be true in between connected and encrypted states
|
||||
+ pendingEncrypt = false;
|
||||
+ }
|
||||
}
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
@@ -941,7 +964,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
|
||||
|
||||
void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
|
||||
{
|
||||
- sendRequest();
|
||||
+ if (reply)
|
||||
+ sendRequest();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||
index 231fe11..a834b7d 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||
@@ -169,6 +169,7 @@ public:
|
||||
|
||||
void handleUnexpectedEOF();
|
||||
void closeAndResendCurrentRequest();
|
||||
+ void resendCurrentRequest();
|
||||
|
||||
bool isSocketBusy() const;
|
||||
bool isSocketWriting() const;
|
||||
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
|
||||
index 55863a3..8b71bd8 100644
|
||||
--- a/src/network/access/qhttpnetworkreply.cpp
|
||||
+++ b/src/network/access/qhttpnetworkreply.cpp
|
||||
@@ -191,7 +191,7 @@ QByteArray QHttpNetworkReply::readAny()
|
||||
return QByteArray();
|
||||
|
||||
// we'll take the last buffer, so schedule another read from http
|
||||
- if (d->downstreamLimited && d->responseData.bufferCount() == 1)
|
||||
+ if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
|
||||
d->connection->d_func()->readMoreLater(this);
|
||||
return d->responseData.read();
|
||||
}
|
||||
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
||||
index 3357948..380aaac 100644
|
||||
--- a/src/network/access/qhttpprotocolhandler.cpp
|
||||
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
||||
@@ -250,7 +250,6 @@ bool QHttpProtocolHandler::sendRequest()
|
||||
if (!m_reply) {
|
||||
// heh, how should that happen!
|
||||
qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
|
||||
- m_channel->state = QHttpNetworkConnectionChannel::IdleState;
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
|
||||
index 2666771..0e82d4a 100644
|
||||
--- a/src/network/socket/qabstractsocket.cpp
|
||||
+++ b/src/network/socket/qabstractsocket.cpp
|
||||
@@ -768,6 +768,7 @@ bool QAbstractSocketPrivate::canReadNotification()
|
||||
void QAbstractSocketPrivate::canCloseNotification()
|
||||
{
|
||||
Q_Q(QAbstractSocket);
|
||||
+ // Note that this method is only called on Windows. Other platforms close in the canReadNotification()
|
||||
|
||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||
qDebug("QAbstractSocketPrivate::canCloseNotification()");
|
||||
@@ -777,7 +778,11 @@ void QAbstractSocketPrivate::canCloseNotification()
|
||||
if (isBuffered) {
|
||||
// Try to read to the buffer, if the read fail we can close the socket.
|
||||
newBytes = buffer.size();
|
||||
- if (!readFromSocket()) {
|
||||
+ qint64 oldReadBufferMaxSize = readBufferMaxSize;
|
||||
+ readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
|
||||
+ bool hadReadFromSocket = readFromSocket();
|
||||
+ readBufferMaxSize = oldReadBufferMaxSize;
|
||||
+ if (!hadReadFromSocket) {
|
||||
q->disconnectFromHost();
|
||||
return;
|
||||
}
|
||||
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
|
||||
index c1fab94..2b9e923 100644
|
||||
--- a/src/network/ssl/qsslsocket.cpp
|
||||
+++ b/src/network/ssl/qsslsocket.cpp
|
||||
@@ -2294,6 +2294,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
|
||||
qCDebug(lcSsl) << "\tstate =" << q->state();
|
||||
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
|
||||
#endif
|
||||
+ // this moves encrypted bytes from plain socket into our buffer
|
||||
+ if (plainSocket->bytesAvailable()) {
|
||||
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
|
||||
+ readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
|
||||
+ transmit();
|
||||
+ readBufferMaxSize = tmpReadBufferMaxSize;
|
||||
+ }
|
||||
+
|
||||
q->setSocketError(plainSocket->error());
|
||||
q->setErrorString(plainSocket->errorString());
|
||||
emit q->error(error);
|
||||
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
index ac4336a..94655fe 100644
|
||||
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
@@ -1419,6 +1419,13 @@ void QSslSocketBackendPrivate::disconnected()
|
||||
{
|
||||
if (plainSocket->bytesAvailable() <= 0)
|
||||
destroySslContext();
|
||||
+ else {
|
||||
+ // Move all bytes into the plain buffer
|
||||
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
|
||||
+ readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
|
||||
+ transmit();
|
||||
+ readBufferMaxSize = tmpReadBufferMaxSize;
|
||||
+ }
|
||||
//if there is still buffered data in the plain socket, don't destroy the ssl context yet.
|
||||
//it will be destroyed when the socket is deleted.
|
||||
}
|
||||
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||
index d2edf67..138f528 100644
|
||||
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||
@@ -1051,7 +1051,7 @@ protected:
|
||||
// clean up QAbstractSocket's residue:
|
||||
while (client->bytesToWrite() > 0) {
|
||||
qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
|
||||
- if (!client->waitForBytesWritten(2000)) {
|
||||
+ if (!client->waitForBytesWritten(10000)) {
|
||||
qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
|
||||
return;
|
||||
}
|
||||
@@ -1071,7 +1071,7 @@ protected:
|
||||
measuredSentBytes += writeNextData(client, bytesToWrite);
|
||||
|
||||
while (client->bytesToWrite() > 0) {
|
||||
- if (!client->waitForBytesWritten(2000)) {
|
||||
+ if (!client->waitForBytesWritten(10000)) {
|
||||
qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
|
||||
return;
|
||||
}
|
||||
@@ -7946,7 +7946,7 @@ public slots:
|
||||
m_receivedData += data;
|
||||
if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
|
||||
m_parsedHeaders = true;
|
||||
- QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
|
||||
+ QTimer::singleShot(qrand()%60, this, SLOT(closeDelayed())); // simulate random network latency
|
||||
// This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
|
||||
// In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
|
||||
// This test catches that.
|
||||
@@ -8052,11 +8052,12 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
|
||||
|
||||
// get the request started and the incoming socket connected
|
||||
QTestEventLoop::instance().enterLoop(10);
|
||||
+ QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
//qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
|
||||
|
||||
// Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
|
||||
- QVERIFY(server.m_correctUploads > 5);
|
||||
+ QVERIFY(server.m_correctUploads > 2);
|
||||
// Because actually important is that we don't get any corruption:
|
||||
QCOMPARE(server.m_corruptUploads, 0);
|
||||
|
||||
--
|
||||
1.9.1
|
||||
@@ -1,64 +0,0 @@
|
||||
From bc32c0ebc0bc00db84ca2f28eb16ab2e5b53a1b6 Mon Sep 17 00:00:00 2001
|
||||
From: Markus Goetz <markus@woboq.com>
|
||||
Date: Fri, 24 Jul 2015 09:53:20 +0200
|
||||
Subject: [PATCH] QNAM: Fix reply deadlocks on server closing connection
|
||||
|
||||
The _q_readyRead can also be called from readMoreLater() because we implemented
|
||||
it so that bandwidth limited reading can be implemented.
|
||||
This can lead to a race condition if the socket is closing at the specific moment
|
||||
and then deadlock the channel: It will stay unusable with a zombie request.
|
||||
The fix in QHttpProtocolaHandler checks if there is actually bytes available to read
|
||||
from the socket and only then continue.
|
||||
|
||||
The fix in the HTTP channel needs to be done to properly finish the reply in
|
||||
cases of a server replying with HTTP/1.0 or "Connection: close".
|
||||
The delayed incovation of _q_receiveReply will properly finish up the reply.
|
||||
|
||||
Change-Id: I19ce2ae595f91d56386cc7406ccacc9935672b6b
|
||||
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||
---
|
||||
src/network/access/qhttpnetworkconnectionchannel.cpp | 4 ++++
|
||||
src/network/access/qhttpprotocolhandler.cpp | 7 ++++++-
|
||||
2 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
index 7428f9b..257aa13 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
@@ -829,11 +829,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
|
||||
if (!reply->d_func()->expectContent()) {
|
||||
// No content expected, this is a valid way to have the connection closed by the server
|
||||
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
|
||||
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
|
||||
// There was no content-length header and it's not chunked encoding,
|
||||
// so this is a valid way to have the connection closed by the server
|
||||
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
|
||||
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
// ok, we got a disconnect even though we did not expect it
|
||||
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
||||
index ab2e3da..a208315 100644
|
||||
--- a/src/network/access/qhttpprotocolhandler.cpp
|
||||
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
||||
@@ -237,7 +237,12 @@ void QHttpProtocolHandler::_q_readyRead()
|
||||
}
|
||||
|
||||
if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
|
||||
- m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
|
||||
+ if (m_socket->bytesAvailable()) {
|
||||
+ // We might get a spurious call from readMoreLater()
|
||||
+ // call of the QHttpNetworkConnection even while the socket is disconnecting.
|
||||
+ // Therefore check if there is actually bytes available before changing the channel state.
|
||||
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
|
||||
+ }
|
||||
if (m_reply)
|
||||
_q_receiveReply();
|
||||
}
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
From 63cf5d3d26a6f65938c3cdec1734eac9faaaf8cb Mon Sep 17 00:00:00 2001
|
||||
From: Markus Goetz <markus@woboq.com>
|
||||
Date: Tue, 22 Sep 2015 14:26:24 -0400
|
||||
Subject: [PATCH] QNAM: Assign proper channel before sslErrors() emission
|
||||
|
||||
There can be a race condition where another channel connects
|
||||
and gets the sslErrors() from the socket first. Then the
|
||||
QSslConfiguration from the wrong socket (the default
|
||||
channel 0's socket) was used.
|
||||
|
||||
Task-number: QTBUG-18722
|
||||
Change-Id: Ibbfa48c27f181563745daf540fa792a57cc09682
|
||||
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||
---
|
||||
src/network/access/qhttpnetworkconnectionchannel.cpp | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
index 257aa13..477cba2 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
@@ -1066,6 +1066,8 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
|
||||
connection->d_func()->pauseConnection();
|
||||
if (pendingEncrypt && !reply)
|
||||
connection->d_func()->dequeueRequest(socket);
|
||||
+ if (reply) // a reply was actually dequeued.
|
||||
+ reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest();
|
||||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
|
||||
if (reply)
|
||||
emit reply->sslErrors(errors);
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
From 0df5d079290b4c3b13e58e9397fabdc1dfdba96b Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hermann <ulf.hermann@theqtcompany.com>
|
||||
Date: Fri, 25 Sep 2015 13:23:46 +0200
|
||||
Subject: [PATCH] Don't let closed http sockets pass as valid connections
|
||||
|
||||
A QAbstractSocket can be close()'d at any time, independently of its
|
||||
current connection state. being closed means that we cannot use it to
|
||||
read or write data, but internally it might still have some data to
|
||||
send or receive, for example to an http server. We can even get a
|
||||
connected() signal after close()'ing the socket.
|
||||
|
||||
We need to catch this condition and mark any pending data not yet
|
||||
written to the socket for resending.
|
||||
|
||||
Task-number: QTBUG-48326
|
||||
Change-Id: I6f61c35f2c567f2a138f8cfe9ade7fd1ec039be6
|
||||
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
|
||||
---
|
||||
.../access/qhttpnetworkconnectionchannel.cpp | 7 ++-
|
||||
.../tst_qhttpnetworkconnection.cpp | 54 ++++++++++++++++++++++
|
||||
2 files changed, 60 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
index 293909c..b4eda34 100644
|
||||
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||
@@ -272,7 +272,12 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
||||
QAbstractSocket::SocketState socketState = socket->state();
|
||||
|
||||
// resend this request after we receive the disconnected signal
|
||||
- if (socketState == QAbstractSocket::ClosingState) {
|
||||
+ // If !socket->isOpen() then we have already called close() on the socket, but there was still a
|
||||
+ // pending connectToHost() for which we hadn't seen a connected() signal, yet. The connected()
|
||||
+ // has now arrived (as indicated by socketState != ClosingState), but we cannot send anything on
|
||||
+ // such a socket anymore.
|
||||
+ if (socketState == QAbstractSocket::ClosingState ||
|
||||
+ (socketState != QAbstractSocket::UnconnectedState && !socket->isOpen())) {
|
||||
if (reply)
|
||||
resendCurrent = true;
|
||||
return false;
|
||||
diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
|
||||
index 5d072af..0d188a8 100644
|
||||
--- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
|
||||
+++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "private/qhttpnetworkconnection_p.h"
|
||||
#include "private/qnoncontiguousbytedevice_p.h"
|
||||
#include <QAuthenticator>
|
||||
+#include <QTcpServer>
|
||||
|
||||
#include "../../../network-settings.h"
|
||||
|
||||
@@ -106,6 +107,8 @@ private Q_SLOTS:
|
||||
|
||||
void getAndThenDeleteObject();
|
||||
void getAndThenDeleteObject_data();
|
||||
+
|
||||
+ void overlappingCloseAndWrite();
|
||||
};
|
||||
|
||||
tst_QHttpNetworkConnection::tst_QHttpNetworkConnection()
|
||||
@@ -1112,6 +1115,57 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject()
|
||||
}
|
||||
}
|
||||
|
||||
+class TestTcpServer : public QTcpServer
|
||||
+{
|
||||
+ Q_OBJECT
|
||||
+public:
|
||||
+ TestTcpServer() : errorCodeReports(0)
|
||||
+ {
|
||||
+ connect(this, &QTcpServer::newConnection, this, &TestTcpServer::onNewConnection);
|
||||
+ QVERIFY(listen(QHostAddress::LocalHost));
|
||||
+ }
|
||||
+
|
||||
+ int errorCodeReports;
|
||||
+
|
||||
+public slots:
|
||||
+ void onNewConnection()
|
||||
+ {
|
||||
+ QTcpSocket *socket = nextPendingConnection();
|
||||
+ if (!socket)
|
||||
+ return;
|
||||
+ // close socket instantly!
|
||||
+ connect(socket, &QTcpSocket::readyRead, socket, &QTcpSocket::close);
|
||||
+ }
|
||||
+
|
||||
+ void onReply(QNetworkReply::NetworkError code)
|
||||
+ {
|
||||
+ QCOMPARE(code, QNetworkReply::RemoteHostClosedError);
|
||||
+ ++errorCodeReports;
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+void tst_QHttpNetworkConnection::overlappingCloseAndWrite()
|
||||
+{
|
||||
+ // server accepts connections, but closes the socket instantly
|
||||
+ TestTcpServer server;
|
||||
+ QNetworkAccessManager accessManager;
|
||||
+
|
||||
+ // ten requests are scheduled. All should result in an RemoteHostClosed...
|
||||
+ QUrl url;
|
||||
+ url.setScheme(QStringLiteral("http"));
|
||||
+ url.setHost(server.serverAddress().toString());
|
||||
+ url.setPort(server.serverPort());
|
||||
+ for (int i = 0; i < 10; ++i) {
|
||||
+ QNetworkRequest request(url);
|
||||
+ QNetworkReply *reply = accessManager.get(request);
|
||||
+ // Not using Qt5 connection syntax here because of overly baroque syntax to discern between
|
||||
+ // different error() methods.
|
||||
+ QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||
+ &server, SLOT(onReply(QNetworkReply::NetworkError)));
|
||||
+ }
|
||||
+
|
||||
+ QTRY_COMPARE(server.errorCodeReports, 10);
|
||||
+}
|
||||
|
||||
|
||||
QTEST_MAIN(tst_QHttpNetworkConnection)
|
||||
--
|
||||
1.9.1
|
||||
@@ -1,113 +0,0 @@
|
||||
From c056e63cea1915667997c982f48296ce5acdcc80 Mon Sep 17 00:00:00 2001
|
||||
From: Lorn Potter <lorn.potter@gmail.com>
|
||||
Date: Tue, 2 Jun 2015 13:22:23 +1000
|
||||
Subject: [PATCH] Make sure to report correct NetworkAccessibility
|
||||
|
||||
Task-number: QTBUG-46323
|
||||
Change-Id: Ibdeb3280091a97d785d4314340678a63e88fb219
|
||||
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
|
||||
---
|
||||
src/network/access/qnetworkaccessmanager.cpp | 25 +++++++++++++++++--------
|
||||
src/network/access/qnetworkaccessmanager_p.h | 2 ++
|
||||
2 files changed, 19 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
|
||||
index e878feb..84931cb 100644
|
||||
--- a/src/network/access/qnetworkaccessmanager.cpp
|
||||
+++ b/src/network/access/qnetworkaccessmanager.cpp
|
||||
@@ -472,11 +472,11 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
|
||||
// the QNetworkSession's signals
|
||||
connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
|
||||
SLOT(_q_onlineStateChanged(bool)));
|
||||
- // we would need all active configurations to check for
|
||||
- // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||
- // and potentially expensive. We can just check the configuration here
|
||||
- d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||
}
|
||||
+ // we would need all active configurations to check for
|
||||
+ // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||
+ // and potentially expensive. We can just check the configuration here
|
||||
+ d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -946,6 +946,7 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
|
||||
void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
|
||||
{
|
||||
Q_D(QNetworkAccessManager);
|
||||
+ d->defaultAccessControl = false;
|
||||
|
||||
if (d->networkAccessible != accessible) {
|
||||
NetworkAccessibility previous = networkAccessible();
|
||||
@@ -964,7 +965,6 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
|
||||
QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
|
||||
{
|
||||
Q_D(const QNetworkAccessManager);
|
||||
-
|
||||
if (d->networkSessionRequired) {
|
||||
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
|
||||
if (networkSession) {
|
||||
@@ -975,7 +975,13 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
|
||||
return NotAccessible;
|
||||
} else {
|
||||
// Network accessibility is either disabled or unknown.
|
||||
- return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
|
||||
+ if (d->defaultAccessControl) {
|
||||
+ if (d->online)
|
||||
+ return d->networkAccessible;
|
||||
+ else
|
||||
+ return NotAccessible;
|
||||
+ }
|
||||
+ return (d->networkAccessible);
|
||||
}
|
||||
} else {
|
||||
if (d->online)
|
||||
@@ -1568,7 +1574,7 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
|
||||
if (!networkSessionStrongRef) {
|
||||
online = false;
|
||||
|
||||
- if (networkAccessible == QNetworkAccessManager::NotAccessible)
|
||||
+ if (networkAccessible == QNetworkAccessManager::NotAccessible || !online)
|
||||
emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
|
||||
else
|
||||
emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
|
||||
@@ -1616,11 +1622,14 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
|
||||
if (online) {
|
||||
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
|
||||
online = false;
|
||||
- emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
|
||||
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||
}
|
||||
} else {
|
||||
if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
|
||||
online = true;
|
||||
+ if (defaultAccessControl)
|
||||
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||
emit q->networkAccessibleChanged(networkAccessible);
|
||||
}
|
||||
}
|
||||
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
|
||||
index f513324..c715da0 100644
|
||||
--- a/src/network/access/qnetworkaccessmanager_p.h
|
||||
+++ b/src/network/access/qnetworkaccessmanager_p.h
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
initializeSession(true),
|
||||
#endif
|
||||
cookieJarCreated(false),
|
||||
+ defaultAccessControl(true),
|
||||
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
|
||||
{ }
|
||||
~QNetworkAccessManagerPrivate();
|
||||
@@ -164,6 +165,7 @@ public:
|
||||
#endif
|
||||
|
||||
bool cookieJarCreated;
|
||||
+ bool defaultAccessControl;
|
||||
|
||||
// The cache with authorization data:
|
||||
QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
From bb281eea179d50a413f4ec1ff172d27ee48d3a41 Mon Sep 17 00:00:00 2001
|
||||
From: Lorn Potter <lorn.potter@gmail.com>
|
||||
Date: Fri, 17 Jul 2015 15:32:23 +1000
|
||||
Subject: [PATCH] Make sure networkAccessibilityChanged is emitted
|
||||
|
||||
Task-number: QTBUG-46323
|
||||
Change-Id: I8297072b62763136f457ca6ae15282d1c22244f4
|
||||
Reviewed-by: Timo Jyrinki <timo.jyrinki@canonical.com>
|
||||
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
|
||||
---
|
||||
src/network/access/qnetworkaccessmanager.cpp | 70 +++++++++++++++-------
|
||||
src/network/access/qnetworkaccessmanager_p.h | 14 ++++-
|
||||
.../tst_qnetworkaccessmanager.cpp | 31 +++++-----
|
||||
3 files changed, 77 insertions(+), 38 deletions(-)
|
||||
|
||||
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
|
||||
index 84931cb..f9e9513 100644
|
||||
--- a/src/network/access/qnetworkaccessmanager.cpp
|
||||
+++ b/src/network/access/qnetworkaccessmanager.cpp
|
||||
@@ -278,7 +278,8 @@ static void ensureInitialized()
|
||||
|
||||
\snippet code/src_network_access_qnetworkaccessmanager.cpp 4
|
||||
|
||||
- Network requests can be reenabled again by calling
|
||||
+ Network requests can be re-enabled again, and this property will resume to
|
||||
+ reflect the actual device state by calling
|
||||
|
||||
\snippet code/src_network_access_qnetworkaccessmanager.cpp 5
|
||||
|
||||
@@ -467,16 +468,12 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
|
||||
qRegisterMetaType<QSharedPointer<char> >();
|
||||
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
- if (!d->networkSessionRequired) {
|
||||
- // if a session is required, we track online state through
|
||||
- // the QNetworkSession's signals
|
||||
- connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
|
||||
- SLOT(_q_onlineStateChanged(bool)));
|
||||
- }
|
||||
- // we would need all active configurations to check for
|
||||
- // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||
- // and potentially expensive. We can just check the configuration here
|
||||
- d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||
+ // if a session is required, we track online state through
|
||||
+ // the QNetworkSession's signals if a request is already made.
|
||||
+ // we need to track current accessibility state by default
|
||||
+ //
|
||||
+ connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
|
||||
+ SLOT(_q_onlineStateChanged(bool)));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -946,7 +943,8 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
|
||||
void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
|
||||
{
|
||||
Q_D(QNetworkAccessManager);
|
||||
- d->defaultAccessControl = false;
|
||||
+
|
||||
+ d->defaultAccessControl = accessible == NotAccessible ? false : true;
|
||||
|
||||
if (d->networkAccessible != accessible) {
|
||||
NetworkAccessibility previous = networkAccessible();
|
||||
@@ -965,6 +963,10 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
|
||||
QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
|
||||
{
|
||||
Q_D(const QNetworkAccessManager);
|
||||
+
|
||||
+ if (d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
|
||||
+ return UnknownAccessibility;
|
||||
+
|
||||
if (d->networkSessionRequired) {
|
||||
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
|
||||
if (networkSession) {
|
||||
@@ -1622,32 +1624,56 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
|
||||
if (online) {
|
||||
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
|
||||
online = false;
|
||||
- networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||
- emit q->networkAccessibleChanged(networkAccessible);
|
||||
+ if (networkAccessible != QNetworkAccessManager::NotAccessible) {
|
||||
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
|
||||
online = true;
|
||||
if (defaultAccessControl)
|
||||
- networkAccessible = QNetworkAccessManager::Accessible;
|
||||
- emit q->networkAccessibleChanged(networkAccessible);
|
||||
+ if (networkAccessible != QNetworkAccessManager::Accessible) {
|
||||
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
|
||||
{
|
||||
- // if the user set a config, we only care whether this one is active.
|
||||
+ Q_Q(QNetworkAccessManager);
|
||||
+ // if the user set a config, we only care whether this one is active.
|
||||
// Otherwise, this QNAM is online if there is an online config.
|
||||
if (customNetworkConfiguration) {
|
||||
online = (networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||
} else {
|
||||
- if (isOnline && online != isOnline) {
|
||||
- networkSessionStrongRef.clear();
|
||||
- networkSessionWeakRef.clear();
|
||||
+ if (online != isOnline) {
|
||||
+ if (isOnline) {
|
||||
+ networkSessionStrongRef.clear();
|
||||
+ networkSessionWeakRef.clear();
|
||||
+ }
|
||||
+ online = isOnline;
|
||||
+ }
|
||||
+ }
|
||||
+ if (online) {
|
||||
+ if (defaultAccessControl) {
|
||||
+ if (networkAccessible != QNetworkAccessManager::Accessible) {
|
||||
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) {
|
||||
+ if (networkAccessible != QNetworkAccessManager::UnknownAccessibility) {
|
||||
+ networkAccessible = QNetworkAccessManager::UnknownAccessibility;
|
||||
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (networkAccessible != QNetworkAccessManager::NotAccessible) {
|
||||
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||
}
|
||||
-
|
||||
- online = isOnline;
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
|
||||
index c715da0..54ae114 100644
|
||||
--- a/src/network/access/qnetworkaccessmanager_p.h
|
||||
+++ b/src/network/access/qnetworkaccessmanager_p.h
|
||||
@@ -78,7 +78,6 @@ public:
|
||||
customNetworkConfiguration(false),
|
||||
networkSessionRequired(networkConfigurationManager.capabilities()
|
||||
& QNetworkConfigurationManager::NetworkSessionRequired),
|
||||
- networkAccessible(QNetworkAccessManager::Accessible),
|
||||
activeReplyCount(0),
|
||||
online(false),
|
||||
initializeSession(true),
|
||||
@@ -86,7 +85,18 @@ public:
|
||||
cookieJarCreated(false),
|
||||
defaultAccessControl(true),
|
||||
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
|
||||
- { }
|
||||
+ {
|
||||
+#ifndef QT_NO_BEARERMANAGEMENT
|
||||
+ // we would need all active configurations to check for
|
||||
+ // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||
+ // and potentially expensive. We can just check the configuration here
|
||||
+ online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active));
|
||||
+ if (online)
|
||||
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||
+ else
|
||||
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||
+#endif
|
||||
+ }
|
||||
~QNetworkAccessManagerPrivate();
|
||||
|
||||
void _q_replyFinished();
|
||||
diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
|
||||
index b4e4b9c..8ecb57d 100644
|
||||
--- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
|
||||
+++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
|
||||
@@ -74,6 +74,10 @@ void tst_QNetworkAccessManager::networkAccessible()
|
||||
// if there is no session, we cannot know in which state we are in
|
||||
QNetworkAccessManager::NetworkAccessibility initialAccessibility =
|
||||
manager.networkAccessible();
|
||||
+
|
||||
+ if (initialAccessibility == QNetworkAccessManager::UnknownAccessibility)
|
||||
+ QSKIP("Unknown accessibility", SkipAll);
|
||||
+
|
||||
QCOMPARE(manager.networkAccessible(), initialAccessibility);
|
||||
|
||||
manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||
@@ -94,29 +98,28 @@ void tst_QNetworkAccessManager::networkAccessible()
|
||||
QCOMPARE(manager.networkAccessible(), initialAccessibility);
|
||||
|
||||
QNetworkConfigurationManager configManager;
|
||||
- bool sessionRequired = (configManager.capabilities()
|
||||
- & QNetworkConfigurationManager::NetworkSessionRequired);
|
||||
QNetworkConfiguration defaultConfig = configManager.defaultConfiguration();
|
||||
if (defaultConfig.isValid()) {
|
||||
manager.setConfiguration(defaultConfig);
|
||||
|
||||
- // the accessibility has not changed if no session is required
|
||||
- if (sessionRequired) {
|
||||
+ QCOMPARE(spy.count(), 0);
|
||||
+
|
||||
+ if (defaultConfig.state().testFlag(QNetworkConfiguration::Active))
|
||||
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible);
|
||||
+ else
|
||||
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
|
||||
+
|
||||
+ manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||
+
|
||||
+ if (defaultConfig.state().testFlag(QNetworkConfiguration::Active)) {
|
||||
QCOMPARE(spy.count(), 1);
|
||||
- QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(),
|
||||
- QNetworkAccessManager::Accessible);
|
||||
+ QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()),
|
||||
+ QNetworkAccessManager::NotAccessible);
|
||||
} else {
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
- QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible);
|
||||
-
|
||||
- manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||
-
|
||||
- QCOMPARE(spy.count(), 1);
|
||||
- QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()),
|
||||
- QNetworkAccessManager::NotAccessible);
|
||||
- QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
|
||||
}
|
||||
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
|
||||
#endif
|
||||
}
|
||||
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
From e996d68f6130847637ba287518cff1289cfa48e5 Mon Sep 17 00:00:00 2001
|
||||
From: Lorn Potter <lorn.potter@gmail.com>
|
||||
Date: Fri, 6 Nov 2015 14:22:44 +1000
|
||||
Subject: [PATCH] Make UnknownAccessibility not block requests
|
||||
|
||||
This allows requests to proceed without needing bearer plugins.
|
||||
|
||||
Task-number: QTBUG-49267
|
||||
Change-Id: Ie5ce188ddefebd14d666bb5846e8f93ee2925ed1
|
||||
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||
---
|
||||
src/network/access/qnetworkaccessmanager.cpp | 3 +--
|
||||
src/network/access/qnetworkaccessmanager_p.h | 2 ++
|
||||
2 files changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
|
||||
index 086140f..0e5870a 100644
|
||||
--- a/src/network/access/qnetworkaccessmanager.cpp
|
||||
+++ b/src/network/access/qnetworkaccessmanager.cpp
|
||||
@@ -976,7 +976,6 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
|
||||
else
|
||||
return NotAccessible;
|
||||
} else {
|
||||
- // Network accessibility is either disabled or unknown.
|
||||
if (d->defaultAccessControl) {
|
||||
if (d->online)
|
||||
return d->networkAccessible;
|
||||
@@ -1161,7 +1160,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
// Return a disabled network reply if network access is disabled.
|
||||
// Except if the scheme is empty or file://.
|
||||
- if (!d->networkAccessible && !isLocalFile) {
|
||||
+ if (d->networkAccessible == NotAccessible && !isLocalFile) {
|
||||
return new QDisabledNetworkReply(this, req, op);
|
||||
}
|
||||
|
||||
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
|
||||
index 54ae114..3fc33b5 100644
|
||||
--- a/src/network/access/qnetworkaccessmanager_p.h
|
||||
+++ b/src/network/access/qnetworkaccessmanager_p.h
|
||||
@@ -93,6 +93,8 @@ public:
|
||||
online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active));
|
||||
if (online)
|
||||
networkAccessible = QNetworkAccessManager::Accessible;
|
||||
+ else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
|
||||
+ networkAccessible = QNetworkAccessManager::UnknownAccessibility;
|
||||
else
|
||||
networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||
#endif
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
From ae9d3f4c6c1a732788cd1f24c6a928cee16c3991 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <daniel@molkentin.de>
|
||||
Date: Tue, 27 Jan 2015 16:58:32 +0100
|
||||
Subject: [PATCH] Win32: Re-init system proxy if internet settings change
|
||||
|
||||
Because Proxy Auto Configuration performs DNS lookups,
|
||||
the proxy settings are being cached. For long-running
|
||||
programs this means that once users switch e.g. from or
|
||||
to company networks with a proxy, they instantly will
|
||||
lose connectivity because we cache the old setting.
|
||||
|
||||
To remedy this, we monitor the Registry (locations
|
||||
courtesy of Chromium's platform support) for changes
|
||||
in its settings, and requery for the current proxy in
|
||||
that case.
|
||||
|
||||
Task-number: QTBUG-3470
|
||||
Task-number: QTBUG-29990
|
||||
Change-Id: Id25a51387bcd232c5f879cea0371038986d0e2de
|
||||
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
|
||||
---
|
||||
src/network/kernel/qnetworkproxy_win.cpp | 86 +++++++++++++++++++++++++++++++-
|
||||
1 file changed, 84 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
|
||||
index da2c020..f7741ce 100644
|
||||
--- a/src/network/kernel/qnetworkproxy_win.cpp
|
||||
+++ b/src/network/kernel/qnetworkproxy_win.cpp
|
||||
@@ -345,12 +345,66 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
|
||||
return removeDuplicateProxies(result);
|
||||
}
|
||||
|
||||
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||
+namespace {
|
||||
+class QRegistryWatcher {
|
||||
+public:
|
||||
+ void addLocation(HKEY hive, const QString& path)
|
||||
+ {
|
||||
+ HKEY openedKey;
|
||||
+ if (RegOpenKeyEx(hive, reinterpret_cast<const wchar_t*>(path.utf16()), 0, KEY_READ, &openedKey) != ERROR_SUCCESS)
|
||||
+ return;
|
||||
+
|
||||
+ const DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
+ REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY;
|
||||
+
|
||||
+ // Watch the registry key for a change of value.
|
||||
+ HANDLE handle = CreateEvent(NULL, true, false, NULL);
|
||||
+ if (RegNotifyChangeKeyValue(openedKey, true, filter, handle, true) != ERROR_SUCCESS) {
|
||||
+ CloseHandle(handle);
|
||||
+ return;
|
||||
+ }
|
||||
+ m_watchEvents.append(handle);
|
||||
+ m_registryHandles.append(openedKey);
|
||||
+ }
|
||||
+
|
||||
+ bool hasChanged() const {
|
||||
+ return !isEmpty() &&
|
||||
+ WaitForMultipleObjects(m_watchEvents.size(), m_watchEvents.data(), false, 0) < WAIT_OBJECT_0 + m_watchEvents.size();
|
||||
+ }
|
||||
+
|
||||
+ bool isEmpty() const {
|
||||
+ return m_watchEvents.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ void clear() {
|
||||
+ foreach (HANDLE event, m_watchEvents)
|
||||
+ CloseHandle(event);
|
||||
+ foreach (HKEY key, m_registryHandles)
|
||||
+ RegCloseKey(key);
|
||||
+
|
||||
+ m_watchEvents.clear();
|
||||
+ m_registryHandles.clear();
|
||||
+ }
|
||||
+
|
||||
+ ~QRegistryWatcher() {
|
||||
+ clear();
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ QVector<HANDLE> m_watchEvents;
|
||||
+ QVector<HKEY> m_registryHandles;
|
||||
+};
|
||||
+} // namespace
|
||||
+#endif // !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||
+
|
||||
class QWindowsSystemProxy
|
||||
{
|
||||
public:
|
||||
QWindowsSystemProxy();
|
||||
~QWindowsSystemProxy();
|
||||
void init();
|
||||
+ void reset();
|
||||
|
||||
QMutex mutex;
|
||||
|
||||
@@ -361,7 +415,9 @@ public:
|
||||
QStringList proxyServerList;
|
||||
QStringList proxyBypass;
|
||||
QList<QNetworkProxy> defaultResult;
|
||||
-
|
||||
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||
+ QRegistryWatcher proxySettingsWatcher;
|
||||
+#endif
|
||||
bool initialized;
|
||||
bool functional;
|
||||
bool isAutoConfig;
|
||||
@@ -381,16 +437,42 @@ QWindowsSystemProxy::~QWindowsSystemProxy()
|
||||
ptrWinHttpCloseHandle(hHttpSession);
|
||||
}
|
||||
|
||||
+void QWindowsSystemProxy::reset()
|
||||
+{
|
||||
+ autoConfigUrl.clear();
|
||||
+ proxyServerList.clear();
|
||||
+ proxyBypass.clear();
|
||||
+ defaultResult.clear();
|
||||
+ defaultResult << QNetworkProxy::NoProxy;
|
||||
+ functional = false;
|
||||
+ isAutoConfig = false;
|
||||
+}
|
||||
+
|
||||
void QWindowsSystemProxy::init()
|
||||
{
|
||||
- if (initialized)
|
||||
+ bool proxySettingsChanged = false;
|
||||
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||
+ proxySettingsChanged = proxySettingsWatcher.hasChanged();
|
||||
+#endif
|
||||
+
|
||||
+ if (initialized && !proxySettingsChanged)
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
+ reset();
|
||||
+
|
||||
#ifdef Q_OS_WINCE
|
||||
// Windows CE does not have any of the following API
|
||||
return;
|
||||
#else
|
||||
+
|
||||
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||
+ proxySettingsWatcher.clear(); // needs reset to trigger a new detection
|
||||
+ proxySettingsWatcher.addLocation(HKEY_CURRENT_USER, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
|
||||
+ proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
|
||||
+ proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
|
||||
+#endif
|
||||
+
|
||||
// load the winhttp.dll library
|
||||
QSystemLibrary lib(L"winhttp");
|
||||
if (!lib.load())
|
||||
--
|
||||
1.9.1
|
||||
@@ -1,32 +0,0 @@
|
||||
From c1a67e7dc3a6f8876efa32cdbabbfde1c5a37bc6 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <daniel@molkentin.de>
|
||||
Date: Tue, 31 Mar 2015 17:43:44 +0200
|
||||
Subject: [PATCH] Windows: Do not crash if SSL context is gone after root cert
|
||||
lookup
|
||||
|
||||
On Windows, we perform an extra certificate lookup for root CAs that
|
||||
are not in Windows' (minimal) root store. This check can take up to
|
||||
15 seconds. The SSL context can already be gone once we return. Hence
|
||||
we now check for a non-null SSL context on Windows before proceeding.
|
||||
|
||||
Change-Id: I1951569d9b17da33fa604f7c9d8b33255acf200d
|
||||
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||
---
|
||||
src/network/ssl/qsslsocket_openssl.cpp | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
index 0e1a3e5..b132aec 100644
|
||||
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
@@ -1281,7 +1281,7 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi
|
||||
if (plainSocket)
|
||||
plainSocket->resume();
|
||||
paused = false;
|
||||
- if (checkSslErrors())
|
||||
+ if (checkSslErrors() && ssl)
|
||||
continueHandshake();
|
||||
}
|
||||
|
||||
--
|
||||
1.9.1
|
||||
@@ -1,39 +0,0 @@
|
||||
From cf6881c03d9f08c6ace83defe461423bb87f30d8 Mon Sep 17 00:00:00 2001
|
||||
From: =?utf8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@theqtcompany.com>
|
||||
Date: Fri, 15 Jan 2016 14:15:51 +0100
|
||||
Subject: [PATCH] OS X: Ensure system tray icon is prepared even when menu bar
|
||||
is hidden
|
||||
|
||||
On OS X 10.11 (El Capitan) the system menu bar can be automatically
|
||||
hidden, in which case the menu bar height is reported to be 0 when
|
||||
using the menuBarHeight API.
|
||||
|
||||
This resulted in failing to prepare an image for the system tray
|
||||
icon item, making the tray item "invisible".
|
||||
|
||||
Instead we now use the [[NSStatusBar systemStatusBar] thickness]
|
||||
API, which returns the correct height regardless of the menu bar
|
||||
being hidden or not.
|
||||
|
||||
Task-number: QTBUG-48960
|
||||
Change-Id: I208fb8df13754964a6f254cadfbff06dd56c6bab
|
||||
---
|
||||
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
index a3ffb5b..8152c57 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
@@ -198,7 +198,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
// current OS X versions is 22 points. Provide some future-proofing
|
||||
// by deriving the icon height from the menu height.
|
||||
const int padding = 4;
|
||||
- const int menuHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
|
||||
const int maxImageHeight = menuHeight - padding;
|
||||
|
||||
// Select pixmap based on the device pixel height. Ideally we would use
|
||||
--
|
||||
2.6.2.2.g1b5ffa3
|
||||
|
||||
@@ -1,55 +1,20 @@
|
||||
## Patches used
|
||||
|
||||
There are our patches on top of Qt 5.4.0, which we are currently
|
||||
using for our binary packages on Windows and Mac OS X. Most of them
|
||||
There are our patches on top of Qt 5.6.2, which we are currently
|
||||
using for our binary packages on Windows and macOS. Most of them
|
||||
have been sent upstream and are part of newer Qt releases.
|
||||
|
||||
All changes are designed to up upstream, and all those that are
|
||||
All changes are designed to be upstream, and all those that are
|
||||
special hacks to Qt will bear a NOUPSTREAM in their name
|
||||
|
||||
The git-style numeration is ordered by order of creation, their
|
||||
purpose is outlined in each patches' front matter.
|
||||
You can apply those patches on a git clone using:
|
||||
|
||||
### Part of Qt v5.4.1 and later
|
||||
* 0001-Fix-crash-on-Mac-OS-if-PAC-URL-contains-non-URL-lega.patch
|
||||
* 0002-Fix-possible-crash-when-passing-an-invalid-PAC-URL.patch
|
||||
* 0003-Fix-crash-if-PAC-script-retrieval-returns-a-null-CFD.patch
|
||||
|
||||
### Part of Qt v5.4.2 and later
|
||||
* 0004-Cocoa-Fix-systray-SVG-icons.patch
|
||||
* 0005-OSX-Fix-disapearing-tray-icon.patch
|
||||
* 0007-QNAM-Fix-upload-corruptions-when-server-closes-conne.patch
|
||||
* 0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch
|
||||
|
||||
### Part of Qt v5.5.0 and later
|
||||
* 0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch
|
||||
|
||||
### Part of Qt v5.5.1 and later
|
||||
* 0007-X-Network-Fix-up-previous-corruption-patch.patch
|
||||
* 0008-QNAM-Fix-reply-deadlocks-on-server-closing-connectio.patch
|
||||
* 0014-Fix-SNI-for-TlsV1_0OrLater-TlsV1_1OrLater-and-TlsV1_.patch
|
||||
* 0016-Fix-possible-crash-when-passing-an-invalid-PAC-URL.patch
|
||||
* 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
|
||||
|
||||
### Part of Qt v5.5.2 (UNRELEASED!)
|
||||
* 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
|
||||
* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
|
||||
* 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
|
||||
|
||||
### Part of Qt v5.6 and later
|
||||
* 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
|
||||
* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
|
||||
* 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
|
||||
* 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
|
||||
* 0013-Make-UnknownAccessibility-not-block-requests.patch
|
||||
* 0019-Ensure-system-tray-icon-is-prepared-even-when-menu-bar.patch
|
||||
|
||||
### Part of Qt 5.7 and later
|
||||
* 0015-Remove-legacy-platform-code-in-QSslSocket-for-OS-X-1.patch
|
||||
|
||||
### Not submitted upstream to be part of any release:
|
||||
* 0006-Fix-force-debug-info-with-macx-clang_NOUPSTREAM.patch
|
||||
This is only needed if you intent to harvest debugging symbols
|
||||
for breakpad.
|
||||
```
|
||||
git am <client>/admin/qt/patches/qtbase/*.patch
|
||||
```
|
||||
|
||||
You can update them using:
|
||||
|
||||
```
|
||||
git format-patch -N --no-signature -o <client>/admin/qt/patches/qtbase/ <v5.x.y>
|
||||
```
|
||||
|
||||
+9
-12
@@ -1,30 +1,27 @@
|
||||
From f3cd07c11e0b7327ffc629f48a89c8c457cdba75 Mon Sep 17 00:00:00 2001
|
||||
From 96c34ce85136cbdc16ef83effa8a13137f7ae4c5 Mon Sep 17 00:00:00 2001
|
||||
From: Jocelyn Turcotte <jturcotte@woboq.com>
|
||||
Date: Fri, 6 Mar 2015 16:12:37 +0100
|
||||
Subject: [PATCH] Fix -force-debug-info with macx-clang
|
||||
Subject: [PATCH] [NOUPSTREAM] Fix -force-debug-info with macx-clang
|
||||
|
||||
---
|
||||
mkspecs/common/clang.conf | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf
|
||||
index 2c29bb8..110d380 100644
|
||||
index e003b94..e9b3291 100644
|
||||
--- a/mkspecs/common/clang.conf
|
||||
+++ b/mkspecs/common/clang.conf
|
||||
@@ -20,11 +20,13 @@ QMAKE_CFLAGS_ISYSTEM = -isystem
|
||||
QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
|
||||
@@ -21,11 +21,13 @@ QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_
|
||||
QMAKE_CFLAGS_USE_PRECOMPILE = -Xclang -include-pch -Xclang ${QMAKE_PCH_OUTPUT}
|
||||
QMAKE_CFLAGS_LTCG = -flto
|
||||
QMAKE_CFLAGS_DISABLE_LTCG = -fno-lto
|
||||
+QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_OPTIMIZE -g
|
||||
|
||||
QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
|
||||
QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
|
||||
QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
|
||||
QMAKE_CXXFLAGS_CXX11 = -std=c++11
|
||||
QMAKE_CXXFLAGS_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG
|
||||
+QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
|
||||
|
||||
QMAKE_LFLAGS_CXX11 =
|
||||
QMAKE_LFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
|
||||
--
|
||||
2.2.0
|
||||
|
||||
QMAKE_CXXFLAGS_CXX11 = -std=c++11
|
||||
QMAKE_CXXFLAGS_CXX14 = -std=c++1y
|
||||
QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
|
||||
+17
-22
@@ -1,7 +1,7 @@
|
||||
From 06818f6d1c602aa3c4f9356324866432d2dd0195 Mon Sep 17 00:00:00 2001
|
||||
From e6bccb1f0d8ca59acb1ffdac74a823c06346e7f3 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <daniel@molkentin.de>
|
||||
Date: Mon, 16 Nov 2015 15:02:37 +0100
|
||||
Subject: [PATCH 1/2] Remove legacy platform code in QSslSocket for OS X < 10.5
|
||||
Subject: [PATCH] Remove legacy platform code in QSslSocket for OS X < 10.5
|
||||
|
||||
This avoids manual symbol lookups and makes the code more readable.
|
||||
Mark identical code.
|
||||
@@ -16,20 +16,18 @@ Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||
Conflicts:
|
||||
src/network/ssl/qsslsocket_openssl.cpp
|
||||
---
|
||||
src/network/ssl/qsslsocket_openssl.cpp | 83 +++++++++++-----------------------
|
||||
src/network/ssl/qsslsocket_openssl.cpp | 81 +++++++++++-----------------------
|
||||
src/network/ssl/qsslsocket_p.h | 6 +--
|
||||
2 files changed, 28 insertions(+), 61 deletions(-)
|
||||
2 files changed, 26 insertions(+), 61 deletions(-)
|
||||
|
||||
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
index 13fc534..7d0fe00 100644
|
||||
index 82644c1..415f147 100644
|
||||
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
@@ -69,14 +69,19 @@
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
#include <QLibrary> // for loading the security lib for the CA store
|
||||
@@ -76,14 +76,17 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
+#include <string.h>
|
||||
+
|
||||
+#ifdef Q_OS_DARWIN
|
||||
+# include <private/qcore_mac_p.h>
|
||||
+#endif
|
||||
@@ -50,7 +48,7 @@ index 13fc534..7d0fe00 100644
|
||||
PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0;
|
||||
PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0;
|
||||
PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0;
|
||||
@@ -482,23 +487,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
|
||||
@@ -509,23 +512,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
|
||||
|
||||
#ifndef QT_NO_LIBRARY
|
||||
//load symbols needed to receive certificates from system store
|
||||
@@ -59,23 +57,23 @@ index 13fc534..7d0fe00 100644
|
||||
- if (securityLib.load()) {
|
||||
- ptrSecCertificateCopyData = (PtrSecCertificateCopyData) securityLib.resolve("SecCertificateCopyData");
|
||||
- if (!ptrSecCertificateCopyData)
|
||||
- qWarning("could not resolve symbols in security library"); // should never happen
|
||||
- qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen
|
||||
-
|
||||
- ptrSecTrustSettingsCopyCertificates = (PtrSecTrustSettingsCopyCertificates) securityLib.resolve("SecTrustSettingsCopyCertificates");
|
||||
- if (!ptrSecTrustSettingsCopyCertificates) { // method was introduced in Leopard, use legacy method if it's not there
|
||||
- ptrSecTrustCopyAnchorCertificates = (PtrSecTrustCopyAnchorCertificates) securityLib.resolve("SecTrustCopyAnchorCertificates");
|
||||
- if (!ptrSecTrustCopyAnchorCertificates)
|
||||
- qWarning("could not resolve symbols in security library"); // should never happen
|
||||
- qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen
|
||||
- }
|
||||
- } else {
|
||||
- qWarning("could not load security library");
|
||||
- qCWarning(lcSsl, "could not load security library");
|
||||
- }
|
||||
-#elif defined(Q_OS_WIN)
|
||||
+#if defined(Q_OS_WIN)
|
||||
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
|
||||
if (hLib) {
|
||||
#if defined(Q_OS_WINCE)
|
||||
@@ -635,40 +624,22 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
@@ -693,40 +680,22 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
timer.start();
|
||||
#endif
|
||||
QList<QSslCertificate> systemCerts;
|
||||
@@ -101,7 +99,7 @@ index 13fc534..7d0fe00 100644
|
||||
- data = ptrSecCertificateCopyData(cfCert);
|
||||
-
|
||||
- if (data == NULL) {
|
||||
- qWarning("error retrieving a CA certificate from the system store");
|
||||
- qCWarning(lcSsl, "error retrieving a CA certificate from the system store");
|
||||
- } else {
|
||||
- QByteArray rawCert = QByteArray::fromRawData((const char *)CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||
- systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der));
|
||||
@@ -127,15 +125,15 @@ index 13fc534..7d0fe00 100644
|
||||
- }
|
||||
- else {
|
||||
- // no detailed error handling here
|
||||
- qWarning("could not retrieve system CA certificates");
|
||||
- qCWarning(lcSsl, "could not retrieve system CA certificates");
|
||||
}
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
|
||||
index 6e7a2c5..c1a6f05 100644
|
||||
index d651971..17cc7b4 100644
|
||||
--- a/src/network/ssl/qsslsocket_p.h
|
||||
+++ b/src/network/ssl/qsslsocket_p.h
|
||||
@@ -145,11 +145,7 @@ public:
|
||||
@@ -151,11 +151,7 @@ public:
|
||||
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
|
||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
||||
|
||||
@@ -148,6 +146,3 @@ index 6e7a2c5..c1a6f05 100644
|
||||
static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW;
|
||||
static PtrCertFindCertificateInStore ptrCertFindCertificateInStore;
|
||||
static PtrCertCloseStore ptrCertCloseStore;
|
||||
--
|
||||
1.9.1
|
||||
|
||||
+13
-16
@@ -1,7 +1,7 @@
|
||||
From 6b9366e7748857f14d5b0f92ced70c08ab5235b7 Mon Sep 17 00:00:00 2001
|
||||
From 9d1120db0973ea7741b13a6555b20ae61f6d037e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Molkentin <danimo@owncloud.com>
|
||||
Date: Wed, 25 Nov 2015 12:37:27 +0100
|
||||
Subject: [PATCH 2/2] QSslSocket: evaluate CAs in all keychain categories
|
||||
Subject: [PATCH] QSslSocket: evaluate CAs in all keychain categories
|
||||
|
||||
This will make sure that certs in the domainUser (login),
|
||||
and domainAdmin (per machine) keychain are being picked up
|
||||
@@ -15,7 +15,7 @@ it will be accepted.
|
||||
[ChangeLog][Platform Specific Changes] OS X now accepts trusted
|
||||
certificates from the login and system keychains.
|
||||
|
||||
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e to Qt 5.4)
|
||||
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e)
|
||||
|
||||
Task-number: QTBUG-32898
|
||||
Change-Id: Ia23083d5af74388eeee31ba07239735cbbe64368
|
||||
@@ -29,10 +29,10 @@ Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||
create mode 100644 src/network/ssl/qsslsocket_mac_shared.cpp
|
||||
|
||||
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
|
||||
index 8887f47..6347c20 100644
|
||||
index 549906a..7b202b0 100644
|
||||
--- a/src/network/ssl/qsslsocket.cpp
|
||||
+++ b/src/network/ssl/qsslsocket.cpp
|
||||
@@ -1446,6 +1446,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
|
||||
@@ -1508,6 +1508,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
|
||||
returned by defaultCaCertificates(). You can replace that database
|
||||
with your own with setDefaultCaCertificates().
|
||||
|
||||
@@ -198,10 +198,10 @@ index 0000000..60fea4c
|
||||
+
|
||||
+QT_END_NAMESPACE
|
||||
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
index 7d0fe00..7415e32 100644
|
||||
index 415f147..7a3cb42 100644
|
||||
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
@@ -71,14 +71,6 @@
|
||||
@@ -76,14 +76,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -216,15 +216,15 @@ index 7d0fe00..7415e32 100644
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
@@ -616,6 +608,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
|
||||
setDefaultCiphers(defaultCiphers);
|
||||
@@ -672,6 +664,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves()
|
||||
setDefaultSupportedEllipticCurves(curves);
|
||||
}
|
||||
|
||||
+#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
|
||||
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
{
|
||||
ensureInitialized();
|
||||
@@ -624,25 +617,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
@@ -680,25 +673,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
timer.start();
|
||||
#endif
|
||||
QList<QSslCertificate> systemCerts;
|
||||
@@ -251,7 +251,7 @@ index 7d0fe00..7415e32 100644
|
||||
if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) {
|
||||
HCERTSTORE hSystemStore;
|
||||
#if defined(Q_OS_WINCE)
|
||||
@@ -719,6 +694,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
@@ -775,6 +750,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
|
||||
return systemCerts;
|
||||
}
|
||||
@@ -260,10 +260,10 @@ index 7d0fe00..7415e32 100644
|
||||
void QSslSocketBackendPrivate::startClientEncryption()
|
||||
{
|
||||
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
|
||||
index 384e149..9546f18 100644
|
||||
index 29c47cd..8eb605b 100644
|
||||
--- a/src/network/ssl/ssl.pri
|
||||
+++ b/src/network/ssl/ssl.pri
|
||||
@@ -45,7 +45,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
|
||||
@@ -62,7 +62,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
|
||||
ssl/qsslsocket_openssl.cpp \
|
||||
ssl/qsslsocket_openssl_symbols.cpp
|
||||
|
||||
@@ -274,6 +274,3 @@ index 384e149..9546f18 100644
|
||||
|
||||
# Add optional SSL libs
|
||||
# Static linking of OpenSSL with msvc:
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -33,11 +33,11 @@ StrCpy $UNINSTALL_MESSAGEBOX "Ez dirudi ${APPLICATION_NAME} '$INSTDIR'.$ direkto
|
||||
StrCpy $UNINSTALL_ABORT "Desinstalazioak erabiltzaileak bertan behera utzi du"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Abiarazle Bizkorreko Lasterbidea (E/E)"
|
||||
StrCpy $INIT_NO_DESKTOP "Mahaigaineko Lasterbidea (dagoena berridazten du)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Ezin izan da goratu, errorea:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Instalatzaileak administratzaile baimenak behar ditu, saiatu berriro"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "Instalatzailea dagoeneko martxan da."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Desinstalatzaile honek administratzaile baimenak behar ditu, saiatu berriro"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Saioa hasteko zerbitzua ez dago martxan, bertan behera uzten!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Desinstalatzailea dagoeneko martxan da."
|
||||
StrCpy $SectionGroup_Shortcuts "Lasterbideak"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "No instal·lar"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ja instal·lat"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Trieu la manera com voleu instal·lar ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Una versió més recent de ${APPLICATION_NAME} ja està instal.lada!! No es recomana instal.lar una versió més antiga. Si realment voleu instal.lar una versió més antiga, és millor primer desinstal.lar la versió actual. Seleccioni l'operació que desitjeu realitzar i feu clic a Següent per a continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} ja està instal·lat.$\n$\nSeleccioneu la operació que voleu fer i feu clic a Següent per continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Afegir/Reinstal.lar components"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Desinstal.lar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstal.lar ${APPLICATION_NAME}"
|
||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "No es pot elevar, error:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Aquest instal·lador requereix accés d'administrador, intenteu-ho de nou"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "L'instal·lador ja s'està executant."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Aquest desinstal·lador requereix accés d'administrador, intenteu-ho de nou."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "El servei de inici de sessió no s'està executant, s'està abortant!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "El desinstal·lador ja s'està executant."
|
||||
StrCpy $SectionGroup_Shortcuts "Dreceres"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Toon opmerkingen bij deze uitgave"
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Toon opmerkingen bij deze versie"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Gevonden ${APPLICATION_EXECUTABLE} proces(sen) moet worden gestopt.$\nWilt u dat het installatieprogramma dat voor u doet?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Stoppen ${APPLICATION_EXECUTABLE} processen."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Het te stoppen proces is niet gevonden!"
|
||||
|
||||
@@ -9,7 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "インストール済"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} のインストール方法を選択する"
|
||||
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} の最新バージョンがすでにインストールされています。$\n旧バージョンのインストールはお勧めしません。旧バージョンのインストールが本当に必要な場合は、まず最新バージョンをアンインストールしてから、旧バージョンをインストールしてください。$\nオペレーションを選択し、次へをクリックする。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} が既にインストールされています。$\n$\n実行したい操作を選択し、次へをクリックする。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} がすでにインストールされています。$\n$\n実行したい操作を選択して、次へをクリックしてください。"
|
||||
StrCpy $PageReinstall_SAME_Field_2 "追加/再インストールコンポーネント"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} をアンインストール"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} をアンインストール"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de lançamento"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Existem ${APPLICATION_EXECUTABLE} processo(s) em execução que precisa(m) de ser interrompido(s).$\nDeseja que o instalador o(s) termine automaticamente?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "A terminar os processos ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Não foi encontrado o processo a terminar!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Uma versão antiga de ${APPLICATION_NAME} está instalada no sistema. É recomendado que desinstale a versão atual antes de instalar a mais recente. Selecione a operação que deseja executar e clique em $\"Avançar$\" para continuar."
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Encontrados ${APPLICATION_EXECUTABLE} processo(s) em execução que precisa(m) de ser interrompido(s).$\nDeseja que o instalador o(s) termine por si?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "A terminar os processos de ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Não foi encontrado o processo para terminar!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Está instalada no sistema uma versão antiga de ${APPLICATION_NAME}. É recomendado que desinstale a versão atual antes de instalar a mais recente. Selecione a operação que deseja executar e clique em $\"Seguinte$\" para continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Não desinstale"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Já instalado"
|
||||
@@ -20,7 +20,7 @@ StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "A instalar integração para Wi
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Atalho do progama no Menu Inicial"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "A adicionar o atalho de ${APPLICATION_NAME} ao Menu Inicial."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Atalho da área de trabalho"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "A criar atalhos da área de trabalho"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "A criar atalhos na área de trabalho"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Atalho de início rápido"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "A criar atalho de início rápido"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "O essencial de ${APPLICATION_NAME}."
|
||||
|
||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Neodin
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Už je nainštalovaný"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Vyberte si, ako chcete nainštalova� ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Novšia verzia ${APPLICATION_NAME} je už nainštalovaná! Neodporúèam vám nainštalova� staršiu verziu. Ak naozaj chcete nainštalova� túto staršiu verziu, je lepšie najprv odinštalova� aktuálnu verziu. Vyberte operáciu, ktorú chcete vykona�, a kliknite na tlaèidlo Ïalej pre pokraèovanie."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} je už nainštalovaná.$\n$\nVyberte operáciu, ktorú chcete vykona�, a kliknite na tlaèidlo Ïalej pre pokraèovanie."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Prida�/Preinštalova� komponenty"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Odinštalova� ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Odinštalova� ${APPLICATION_NAME}"
|
||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "Nemo
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Tento inštalátor vyžaduje admin prístup, skúste to znova"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "Inštalátor je už spustený."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Tento odinštalátor vyžaduje admin prístup, skúste to znova"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Prihlasovacia služba nebeží! Prerušuje sa."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Odinštalátor je už spustený."
|
||||
StrCpy $SectionGroup_Shortcuts "Zástupcovia"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
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_KILL_NOT_FOUND_TEXT "¡Proceso para detener no encontrado!"
|
||||
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_2 "Desinstalar antes de instalar"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "No desinstalar"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกประจำรุ่น"
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกที่มี"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "พบว่ากระบวนการ ${APPLICATION_EXECUTABLE} จะต้องหยุดทำงาน$\nคุณต้องการติดตั้งเพื่อหยุดการทำงานเหล่านี้ของคุณ?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "ฆ่ากระบวนการทำงาน ${APPLICATION_EXECUTABLE}"
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "ไม่พบการฆ่ากระบวนการ!"
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
!insertmacro MUI_LANGUAGE "Swedish"
|
||||
!insertmacro MUI_LANGUAGE "Estonian"
|
||||
!insertmacro MUI_LANGUAGE "Turkish"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Slovenian"
|
||||
!insertmacro MUI_LANGUAGE "SpanishInternational"
|
||||
!insertmacro MUI_LANGUAGE "Dutch"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Hungarian"
|
||||
!insertmacro MUI_LANGUAGE "Ukrainian"
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Catalan"
|
||||
!insertmacro MUI_LANGUAGE "Russian"
|
||||
!insertmacro MUI_LANGUAGE "Thai"
|
||||
!insertmacro MUI_LANGUAGE "Finnish"
|
||||
!insertmacro MUI_LANGUAGE "Basque"
|
||||
!insertmacro MUI_LANGUAGE "Greek"
|
||||
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Catalan"
|
||||
!insertmacro MUI_LANGUAGE "Italian"
|
||||
!insertmacro MUI_LANGUAGE "Portuguese"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Czech"
|
||||
!insertmacro MUI_LANGUAGE "Japanese"
|
||||
!insertmacro MUI_LANGUAGE "Galician"
|
||||
!insertmacro MUI_LANGUAGE "Czech"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Slovak"
|
||||
!insertmacro MUI_LANGUAGE "Spanish"
|
||||
!insertmacro MUI_LANGUAGE "Polish"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[Paths]
|
||||
Prefix = .
|
||||
Plugins = .
|
||||
Binaries = .
|
||||
Imports = .
|
||||
Qml2Imports = .
|
||||
LibraryExecutables = .
|
||||
+1
-1
Submodule binary updated: d27d472817...741b49156b
@@ -1,5 +0,0 @@
|
||||
--- binary
|
||||
+++ binary
|
||||
@@ -1 +1 @@
|
||||
-Subproject commit 1fb9ddfa9a9a1b4dbc447eee10dbed89172d968a
|
||||
+Subproject commit 01d73965dc8b862d1b2310d3ef801c297b697ec7
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ find_library(CMOCKA_LIBRARY
|
||||
NAMES
|
||||
cmocka
|
||||
PATHS
|
||||
${CMOCKA_ROOT_DIR}/include
|
||||
${CMOCKA_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
if (CMOCKA_LIBRARY)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -411,14 +411,15 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "@CPACK_RESOURCE_FILE_LICENSE@"
|
||||
;File /oname=NOTES.txt ${NSI_PATH}\RELEASE_NOTES.txt
|
||||
|
||||
;Qt config:
|
||||
File "${NSI_PATH}\qt.conf"
|
||||
|
||||
;Qt stuff:
|
||||
File "${QT_DLL_PATH}\Qt5Core.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Network.dll"
|
||||
File "${QT_DLL_PATH}\Qt5OpenGL.dll"
|
||||
File "${QT_DLL_PATH}\Qt5PrintSupport.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Qml.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Quick.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Sql.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKit.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
||||
@@ -432,9 +433,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\icudata53.dll"
|
||||
File "${MING_BIN}\icui18n53.dll"
|
||||
File "${MING_BIN}\icuuc53.dll"
|
||||
File "${MING_BIN}\icudata56.dll"
|
||||
File "${MING_BIN}\icui18n56.dll"
|
||||
File "${MING_BIN}\icuuc56.dll"
|
||||
File "${MING_BIN}\libEGL.dll"
|
||||
File "${MING_BIN}\libGLESv2.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
@@ -443,11 +444,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libcrypto-10.dll"
|
||||
File "${MING_BIN}\libssl-10.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwebp-4.dll"
|
||||
File "${MING_BIN}\libwebp-5.dll"
|
||||
File "${MING_BIN}\libxslt-1.dll"
|
||||
File "${MING_BIN}\libxml2-2.dll"
|
||||
File "${MING_BIN}\zlib1.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
File "${MING_BIN}\libharfbuzz-0.dll"
|
||||
File "${MING_BIN}\libfreetype-6.dll"
|
||||
File "${MING_BIN}\libglib-2.0-0.dll"
|
||||
File "${MING_BIN}\libintl-8.dll"
|
||||
|
||||
;QtKeyChain stuff
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
@@ -22,12 +22,18 @@ if( Qt5Core_FOUND )
|
||||
find_package(Qt5Test REQUIRED)
|
||||
endif()
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
find_package(Qt5WebKitWidgets REQUIRED)
|
||||
find_package(Qt5WebKit REQUIRED)
|
||||
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 )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# (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.
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
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")
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
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)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
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)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
||||
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
||||
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif()
|
||||
|
||||
if(DEFINED MIRALL_FATAL_WARNINGS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
endif(DEFINED MIRALL_FATAL_WARNINGS)
|
||||
if(DEFINED MIRALL_FATAL_WARNINGS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
endif(DEFINED MIRALL_FATAL_WARNINGS)
|
||||
endif()
|
||||
|
||||
@@ -23,4 +23,6 @@
|
||||
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
||||
#cmakedefine SHAREDIR "@SHAREDIR@"
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,8 @@ endif (MEM_NULL_TESTS)
|
||||
add_subdirectory(src)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
include(AddCMockaTest)
|
||||
|
||||
@@ -62,8 +62,4 @@ if (WIN32)
|
||||
check_function_exists(__mingw_asprintf HAVE___MINGW_ASPRINTF)
|
||||
endif(WIN32)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
set(CSYNC_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "csync required system libraries")
|
||||
|
||||
@@ -81,6 +81,13 @@ set(csync_HDRS
|
||||
# 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(
|
||||
@@ -91,6 +98,12 @@ include_directories(
|
||||
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})
|
||||
|
||||
|
||||
+10
-24
@@ -30,7 +30,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -90,7 +89,7 @@ static int _data_cmp(const void *key, const void *data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
void csync_create(CSYNC **csync, const char *local) {
|
||||
CSYNC *ctx;
|
||||
size_t len = 0;
|
||||
|
||||
@@ -104,12 +103,6 @@ void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
|
||||
ctx->local.uri = c_strndup(local, len);
|
||||
|
||||
/* remove trailing slashes */
|
||||
len = strlen(remote);
|
||||
while(len > 0 && remote[len - 1] == '/') --len;
|
||||
|
||||
ctx->remote.uri = c_strndup(remote, len);
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
ctx->current_fs = NULL;
|
||||
@@ -121,7 +114,7 @@ void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
*csync = ctx;
|
||||
}
|
||||
|
||||
void csync_init(CSYNC *ctx) {
|
||||
void csync_init(CSYNC *ctx, const char *db_file) {
|
||||
assert(ctx);
|
||||
/* Do not initialize twice */
|
||||
|
||||
@@ -132,6 +125,9 @@ void csync_init(CSYNC *ctx) {
|
||||
|
||||
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);
|
||||
|
||||
@@ -153,19 +149,11 @@ int csync_update(CSYNC *ctx) {
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
/* create/load statedb */
|
||||
rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
|
||||
ctx->local.uri);
|
||||
if (rc < 0) {
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
return rc;
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Journal: %s", ctx->statedb.file);
|
||||
|
||||
if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
|
||||
/* 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;
|
||||
|
||||
@@ -200,7 +188,7 @@ int csync_update(CSYNC *ctx) {
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
|
||||
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
|
||||
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);
|
||||
@@ -387,7 +375,6 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||
trav.inode = cur->inode;
|
||||
|
||||
trav.error_status = cur->error_status;
|
||||
trav.should_update_metadata = cur->should_update_metadata;
|
||||
trav.has_ignored_files = cur->has_ignored_files;
|
||||
trav.checksum = cur->checksum;
|
||||
trav.checksumTypeId = cur->checksumTypeId;
|
||||
@@ -523,7 +510,6 @@ static void _csync_clean_ctx(CSYNC *ctx)
|
||||
c_rbtree_free(ctx->local.tree);
|
||||
c_rbtree_free(ctx->remote.tree);
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
SAFE_FREE(ctx->remote.root_perms);
|
||||
}
|
||||
|
||||
@@ -580,8 +566,8 @@ int csync_destroy(CSYNC *ctx) {
|
||||
|
||||
_csync_clean_ctx(ctx);
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
SAFE_FREE(ctx->local.uri);
|
||||
SAFE_FREE(ctx->remote.uri);
|
||||
SAFE_FREE(ctx->error_string);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
|
||||
+49
-54
@@ -33,10 +33,10 @@
|
||||
#define _CSYNC_H
|
||||
|
||||
#include "std/c_private.h"
|
||||
#include "ocsynclib.h"
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <config_csync.h>
|
||||
|
||||
@@ -44,11 +44,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct csync_client_certs_s {
|
||||
char *certificatePath;
|
||||
char *certificatePasswd;
|
||||
};
|
||||
|
||||
enum csync_status_codes_e {
|
||||
CSYNC_STATUS_OK = 0,
|
||||
|
||||
@@ -98,6 +93,7 @@ enum csync_status_codes_e {
|
||||
CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK,
|
||||
CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST,
|
||||
CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS,
|
||||
CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE,
|
||||
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME,
|
||||
CYSNC_STATUS_FILE_LOCKED_OR_OPEN,
|
||||
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN,
|
||||
@@ -124,20 +120,22 @@ typedef enum csync_status_codes_e CSYNC_STATUS;
|
||||
* the csync state of a file.
|
||||
*/
|
||||
enum csync_instructions_e {
|
||||
CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */
|
||||
CSYNC_INSTRUCTION_REMOVE = 0x00000002, /* The file need to be removed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_RENAME = 0x00000004, /* The file need to be renamed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL_RENAME= 0x00000800, /* The file is new, it is the destination of a rename (UPDATE) */
|
||||
CSYNC_INSTRUCTION_NEW = 0x00000008, /* The file is new compared to the db (UPDATE) */
|
||||
CSYNC_INSTRUCTION_CONFLICT = 0x00000010, /* The file need to be downloaded because it is a conflict (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
|
||||
CSYNC_INSTRUCTION_ERROR = 0x00000100,
|
||||
CSYNC_INSTRUCTION_TYPE_CHANGE = 0x0000200, /* Like NEW, but deletes the old entity first (RECONCILE)
|
||||
Used when the type of something changes from directory to file
|
||||
or back. */
|
||||
CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */
|
||||
CSYNC_INSTRUCTION_REMOVE = 0x00000002, /* The file need to be removed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_RENAME = 0x00000004, /* The file need to be renamed (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_EVAL_RENAME = 0x00000800, /* The file is new, it is the destination of a rename (UPDATE) */
|
||||
CSYNC_INSTRUCTION_NEW = 0x00000008, /* The file is new compared to the db (UPDATE) */
|
||||
CSYNC_INSTRUCTION_CONFLICT = 0x00000010, /* The file need to be downloaded because it is a conflict (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
|
||||
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
|
||||
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
|
||||
CSYNC_INSTRUCTION_ERROR = 0x00000100,
|
||||
CSYNC_INSTRUCTION_TYPE_CHANGE = 0x00000200, /* Like NEW, but deletes the old entity first (RECONCILE)
|
||||
Used when the type of something changes from directory to file
|
||||
or back. */
|
||||
CSYNC_INSTRUCTION_UPDATE_METADATA = 0x00000400, /* If the etag has been updated and need to be writen to the db,
|
||||
but without any propagation (UPDATE|RECONCILE) */
|
||||
};
|
||||
|
||||
enum csync_ftw_type_e {
|
||||
@@ -226,14 +224,14 @@ struct csync_vio_file_stat_s {
|
||||
char *original_name; // only set if locale conversion fails
|
||||
};
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void);
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat);
|
||||
csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_new(void);
|
||||
csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat);
|
||||
|
||||
void csync_vio_file_stat_destroy(csync_vio_file_stat_t *fstat);
|
||||
void OCSYNC_EXPORT csync_vio_file_stat_destroy(csync_vio_file_stat_t *fstat);
|
||||
|
||||
void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t* dst, const char* src );
|
||||
void OCSYNC_EXPORT csync_vio_file_stat_set_file_id( csync_vio_file_stat_t* dst, const char* src );
|
||||
|
||||
void csync_vio_set_file_id(char* dst, const char *src );
|
||||
void OCSYNC_EXPORT csync_vio_set_file_id(char* dst, const char *src );
|
||||
|
||||
|
||||
/**
|
||||
@@ -253,9 +251,6 @@ struct csync_tree_walk_file_s {
|
||||
enum csync_ftw_type_e type;
|
||||
enum csync_instructions_e instruction;
|
||||
|
||||
/* For directories: If the etag has been updated and need to be writen on the db */
|
||||
int should_update_metadata;
|
||||
|
||||
/* For directories: Does it have children that were ignored (hidden or ignore pattern) */
|
||||
int has_ignored_files;
|
||||
|
||||
@@ -317,7 +312,7 @@ typedef const char* (*csync_checksum_hook) (
|
||||
*
|
||||
* @param csync The context variable to allocate.
|
||||
*/
|
||||
void csync_create(CSYNC **csync, const char *local, const char *remote);
|
||||
void OCSYNC_EXPORT csync_create(CSYNC **csync, const char *local);
|
||||
|
||||
/**
|
||||
* @brief Initialize the file synchronizer.
|
||||
@@ -326,7 +321,7 @@ void csync_create(CSYNC **csync, const char *local, const char *remote);
|
||||
*
|
||||
* @param ctx The context to initialize.
|
||||
*/
|
||||
void csync_init(CSYNC *ctx);
|
||||
void OCSYNC_EXPORT csync_init(CSYNC *ctx, const char *db_file);
|
||||
|
||||
/**
|
||||
* @brief Update detection
|
||||
@@ -335,7 +330,7 @@ void csync_init(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_update(CSYNC *ctx);
|
||||
int OCSYNC_EXPORT csync_update(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Reconciliation
|
||||
@@ -344,7 +339,7 @@ int csync_update(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_reconcile(CSYNC *ctx);
|
||||
int OCSYNC_EXPORT csync_reconcile(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Re-initializes the csync context
|
||||
@@ -353,7 +348,7 @@ int csync_reconcile(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_commit(CSYNC *ctx);
|
||||
int OCSYNC_EXPORT csync_commit(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Destroy the csync context
|
||||
@@ -364,7 +359,7 @@ int csync_commit(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_destroy(CSYNC *ctx);
|
||||
int OCSYNC_EXPORT csync_destroy(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the userdata saved in the context.
|
||||
@@ -386,7 +381,7 @@ void *csync_get_userdata(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_set_userdata(CSYNC *ctx, void *userdata);
|
||||
int OCSYNC_EXPORT csync_set_userdata(CSYNC *ctx, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Get the authentication callback set.
|
||||
@@ -396,7 +391,7 @@ int csync_set_userdata(CSYNC *ctx, void *userdata);
|
||||
* @return The authentication callback set or NULL if an error
|
||||
* occurred.
|
||||
*/
|
||||
csync_auth_callback csync_get_auth_callback(CSYNC *ctx);
|
||||
csync_auth_callback OCSYNC_EXPORT csync_get_auth_callback(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Set the authentication callback.
|
||||
@@ -407,7 +402,7 @@ csync_auth_callback csync_get_auth_callback(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
|
||||
int OCSYNC_EXPORT csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
|
||||
|
||||
/**
|
||||
* @brief Set the log level.
|
||||
@@ -416,14 +411,14 @@ int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
|
||||
*
|
||||
* @return 0 on success, < 0 if an error occurred.
|
||||
*/
|
||||
int csync_set_log_level(int level);
|
||||
int OCSYNC_EXPORT csync_set_log_level(int level);
|
||||
|
||||
/**
|
||||
* @brief Get the log verbosity
|
||||
*
|
||||
* @return The log verbosity, -1 on error.
|
||||
*/
|
||||
int csync_get_log_level(void);
|
||||
int OCSYNC_EXPORT csync_get_log_level(void);
|
||||
|
||||
/**
|
||||
* @brief Get the logging callback set.
|
||||
@@ -431,7 +426,7 @@ int csync_get_log_level(void);
|
||||
* @return The logging callback set or NULL if an error
|
||||
* occurred.
|
||||
*/
|
||||
csync_log_callback csync_get_log_callback(void);
|
||||
csync_log_callback OCSYNC_EXPORT csync_get_log_callback(void);
|
||||
|
||||
/**
|
||||
* @brief Set the logging callback.
|
||||
@@ -440,14 +435,14 @@ csync_log_callback csync_get_log_callback(void);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_set_log_callback(csync_log_callback cb);
|
||||
int OCSYNC_EXPORT csync_set_log_callback(csync_log_callback cb);
|
||||
|
||||
/**
|
||||
* @brief get the userdata set for the logging callback.
|
||||
*
|
||||
* @return The userdata or NULL.
|
||||
*/
|
||||
void *csync_get_log_userdata(void);
|
||||
void OCSYNC_EXPORT *csync_get_log_userdata(void);
|
||||
|
||||
/**
|
||||
* @brief Set the userdata passed to the logging callback.
|
||||
@@ -456,13 +451,13 @@ void *csync_get_log_userdata(void);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_set_log_userdata(void *data);
|
||||
int OCSYNC_EXPORT csync_set_log_userdata(void *data);
|
||||
|
||||
/* Used for special modes or debugging */
|
||||
CSYNC_STATUS csync_get_status(CSYNC *ctx);
|
||||
CSYNC_STATUS OCSYNC_EXPORT csync_get_status(CSYNC *ctx);
|
||||
|
||||
/* Used for special modes or debugging */
|
||||
int csync_set_status(CSYNC *ctx, int status);
|
||||
int OCSYNC_EXPORT csync_set_status(CSYNC *ctx, int status);
|
||||
|
||||
typedef int csync_treewalk_visit_func(TREE_WALK_FILE* ,void*);
|
||||
|
||||
@@ -475,7 +470,7 @@ typedef int csync_treewalk_visit_func(TREE_WALK_FILE* ,void*);
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||
int OCSYNC_EXPORT csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||
|
||||
/**
|
||||
* @brief Walk the remote file tree and call a visitor function for each file.
|
||||
@@ -486,7 +481,7 @@ int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int fi
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occurred.
|
||||
*/
|
||||
int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||
int OCSYNC_EXPORT csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||
|
||||
/**
|
||||
* @brief Get the csync status string.
|
||||
@@ -495,7 +490,7 @@ int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int f
|
||||
*
|
||||
* @return A const pointer to a string with more precise status info.
|
||||
*/
|
||||
const char *csync_get_status_string(CSYNC *ctx);
|
||||
const char OCSYNC_EXPORT *csync_get_status_string(CSYNC *ctx);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
/**
|
||||
@@ -505,7 +500,7 @@ const char *csync_get_status_string(CSYNC *ctx);
|
||||
*
|
||||
* @return 0 on success, or an iconv error number.
|
||||
*/
|
||||
int csync_set_iconv_codec(const char *from);
|
||||
int OCSYNC_EXPORT csync_set_iconv_codec(const char *from);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -513,24 +508,24 @@ int csync_set_iconv_codec(const char *from);
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*/
|
||||
void csync_request_abort(CSYNC *ctx);
|
||||
void OCSYNC_EXPORT csync_request_abort(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Clears the abort flag. Can be called from another thread.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*/
|
||||
void csync_resume(CSYNC *ctx);
|
||||
void OCSYNC_EXPORT csync_resume(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Checks for the abort flag, to be used from the modules.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*/
|
||||
int csync_abort_requested(CSYNC *ctx);
|
||||
int OCSYNC_EXPORT csync_abort_requested(CSYNC *ctx);
|
||||
|
||||
char *csync_normalize_etag(const char *);
|
||||
time_t oc_httpdate_parse( const char *date );
|
||||
char OCSYNC_EXPORT *csync_normalize_etag(const char *);
|
||||
time_t OCSYNC_EXPORT oc_httpdate_parse( const char *date );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "c_private.h"
|
||||
@@ -37,13 +36,31 @@
|
||||
#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 NDEBUG
|
||||
#ifndef WITH_UNIT_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);
|
||||
}
|
||||
|
||||
@@ -139,8 +156,10 @@ int csync_exclude_load(const char *fname, c_strlist_t **list) {
|
||||
buf[i] = '\0';
|
||||
if (*entry != '#') {
|
||||
const char *unescaped = csync_exclude_expand_escapes(entry);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped);
|
||||
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;
|
||||
@@ -211,6 +230,11 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
||||
}
|
||||
blen = strlen(bname);
|
||||
|
||||
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;
|
||||
@@ -229,9 +253,14 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
||||
// 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 && (bname[blen-1]== ' ' || bname[blen-1]== '.' )) {
|
||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||
goto out;
|
||||
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)) {
|
||||
|
||||
@@ -21,20 +21,23 @@
|
||||
#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 NDEBUG
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -45,7 +48,7 @@ int _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
*
|
||||
* @return 0 on success, -1 if an error occurred with errno set.
|
||||
*/
|
||||
int csync_exclude_load(const char *fname, c_strlist_t **list);
|
||||
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.
|
||||
@@ -71,7 +74,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *p
|
||||
* @param filetype
|
||||
* @return
|
||||
*/
|
||||
CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype);
|
||||
CSYNC_EXCLUDE_TYPE OCSYNC_EXPORT csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype);
|
||||
#endif /* _CSYNC_EXCLUDE_H */
|
||||
|
||||
/**
|
||||
|
||||
+1
-42
@@ -23,12 +23,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/utime.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_log.h"
|
||||
@@ -37,46 +31,11 @@ CSYNC_THREAD int csync_log_level;
|
||||
CSYNC_THREAD csync_log_callback csync_log_cb;
|
||||
CSYNC_THREAD void *csync_log_userdata;
|
||||
|
||||
static int current_timestring(int hires, char *buf, size_t len)
|
||||
{
|
||||
char tbuf[64];
|
||||
struct timeval tv;
|
||||
struct tm *tm;
|
||||
time_t t;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
t = (time_t) tv.tv_sec;
|
||||
|
||||
tm = localtime(&t);
|
||||
if (tm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hires) {
|
||||
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
snprintf(buf, len, "%s.%06ld", tbuf, (long) tv.tv_usec);
|
||||
} else {
|
||||
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
snprintf(buf, len, "%s", tbuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void csync_log_stderr(int verbosity,
|
||||
const char *function,
|
||||
const char *buffer)
|
||||
{
|
||||
char date[64] = {0};
|
||||
int rc;
|
||||
|
||||
rc = current_timestring(1, date, sizeof(date));
|
||||
if (rc == 0) {
|
||||
fprintf(stderr, "[%s, %d] %s:", date+5, verbosity, function);
|
||||
} else {
|
||||
fprintf(stderr, "[%d] %s", verbosity, function);
|
||||
}
|
||||
|
||||
fprintf(stderr, "[%d] %s", verbosity, function);
|
||||
fprintf(stderr, " %s\n", buffer);
|
||||
}
|
||||
static void csync_log_function(int verbosity,
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
# include <shlobj.h>
|
||||
#else /* _WIN32 */
|
||||
# include <pwd.h>
|
||||
# include <unistd.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "c_lib.h"
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
|
||||
#endif
|
||||
|
||||
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
|
||||
int csync_fnmatch(const char *pattern, const char *name, int flags);
|
||||
|
||||
/**
|
||||
* @brief csync_errno_to_status - errno to csync status code
|
||||
|
||||
@@ -89,7 +89,7 @@ struct csync_s {
|
||||
|
||||
/* hooks for checking the white list (uses the update_callback_userdata) */
|
||||
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */);
|
||||
|
||||
|
||||
csync_vio_opendir_hook remote_opendir_hook;
|
||||
@@ -103,9 +103,6 @@ struct csync_s {
|
||||
|
||||
} callbacks;
|
||||
c_strlist_t *excludes;
|
||||
|
||||
// needed for SSL client certificate support
|
||||
struct csync_client_certs_s *clientCerts;
|
||||
|
||||
struct {
|
||||
char *file;
|
||||
@@ -126,7 +123,6 @@ struct csync_s {
|
||||
} local;
|
||||
|
||||
struct {
|
||||
char *uri;
|
||||
c_rbtree_t *tree;
|
||||
enum csync_replica_e type;
|
||||
int read_from_db;
|
||||
@@ -186,8 +182,6 @@ struct csync_file_stat_s {
|
||||
mode_t mode; /* u32 */
|
||||
unsigned int type : 4;
|
||||
unsigned int child_modified : 1;
|
||||
unsigned int should_update_metadata : 1; /*specify that the etag, or the remote perm or fileid has
|
||||
changed and need to be updated on the db even for INSTRUCTION_NONE */
|
||||
unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */
|
||||
|
||||
char *destpath; /* for renames */
|
||||
@@ -226,9 +220,6 @@ struct _csync_treewalk_context_s
|
||||
};
|
||||
typedef struct _csync_treewalk_context_s _csync_treewalk_context;
|
||||
|
||||
|
||||
time_t oc_httpdate_parse( const char *date );
|
||||
|
||||
void set_errno_from_http_errcode( int err );
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "csync_private.h"
|
||||
#include "csync_reconcile.h"
|
||||
#include "csync_util.h"
|
||||
@@ -64,7 +65,21 @@ static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* 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
|
||||
@@ -130,6 +145,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
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;
|
||||
@@ -181,13 +197,8 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
|
||||
if(!other) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
if (cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
// For new directories we always want to update the etag once
|
||||
// the directory has been propagated. Otherwise the directory
|
||||
// could appear locally without being added to the database.
|
||||
cur->should_update_metadata = true;
|
||||
}
|
||||
} 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 );
|
||||
@@ -195,7 +206,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
other->should_update_metadata = true;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
@@ -205,12 +215,12 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
csync_vio_set_file_id( other->file_id, cur->file_id );
|
||||
}
|
||||
other->inode = cur->inode;
|
||||
other->should_update_metadata = true;
|
||||
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;
|
||||
}
|
||||
@@ -222,13 +232,19 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
bool is_equal_files = false;
|
||||
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. */
|
||||
@@ -253,42 +269,39 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
if (other->type == CSYNC_FTW_TYPE_DIR &&
|
||||
cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
is_equal_files = (other->modtime == cur->modtime);
|
||||
// Folders of the same path are always considered equals
|
||||
is_conflict = false;
|
||||
} else {
|
||||
is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
|
||||
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 (is_equal_files) {
|
||||
/* The files are considered equal. */
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
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;
|
||||
|
||||
/* update DB with new etag from remote */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
other->should_update_metadata = true;
|
||||
} else {
|
||||
cur->should_update_metadata = true;
|
||||
}
|
||||
} else if(ctx->current == REMOTE_REPLICA) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
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:
|
||||
@@ -310,7 +323,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
if(cur->type == CSYNC_FTW_TYPE_DIR)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
||||
"%-20s %s dir: %s",
|
||||
"%-30s %s dir: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
@@ -318,7 +331,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
else
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
|
||||
"%-20s %s file: %s",
|
||||
"%-30s %s file: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
@@ -329,7 +342,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
if(cur->type == CSYNC_FTW_TYPE_DIR)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"%-20s %s dir: %s",
|
||||
"%-30s %s dir: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
@@ -337,7 +350,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
else
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"%-20s %s file: %s",
|
||||
"%-30s %s file: %s",
|
||||
csync_instruction_str(cur->instruction),
|
||||
repo,
|
||||
cur->path);
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
*
|
||||
* @todo Add an argument to set the algorithm to use.
|
||||
*/
|
||||
int csync_reconcile_updates(CSYNC *ctx);
|
||||
int OCSYNC_EXPORT csync_reconcile_updates(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* }@
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include "csync_private.h"
|
||||
#include "csync_rename.h"
|
||||
}
|
||||
|
||||
#include <map>
|
||||
@@ -93,5 +94,9 @@ char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path)
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,11 +27,13 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Return the final destination path of a given patch in case of renames */
|
||||
char *csync_rename_adjust_path(CSYNC *ctx, const char *path);
|
||||
char OCSYNC_EXPORT *csync_rename_adjust_path(CSYNC *ctx, const char *path);
|
||||
/* Return the source of a given path in case of renames */
|
||||
char *csync_rename_adjust_path_source(CSYNC *ctx, const char *path);
|
||||
void csync_rename_destroy(CSYNC *ctx);
|
||||
void csync_rename_record(CSYNC *ctx, const char *from, const char *to);
|
||||
char OCSYNC_EXPORT *csync_rename_adjust_path_source(CSYNC *ctx, const char *path);
|
||||
void OCSYNC_EXPORT csync_rename_destroy(CSYNC *ctx);
|
||||
void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const char *from, const char *to);
|
||||
/* Return the amount of renamed item recorded */
|
||||
bool OCSYNC_EXPORT csync_rename_count(CSYNC *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -53,7 +52,7 @@
|
||||
|
||||
#define sqlite_open(A, B) sqlite3_open_v2(A,B, SQLITE_OPEN_READONLY+SQLITE_OPEN_NOMUTEX, NULL)
|
||||
|
||||
#define SQLTM_TIME 150000
|
||||
#define SQLTM_TIME 150
|
||||
#define SQLTM_COUNT 10
|
||||
|
||||
#define SQLITE_BUSY_HANDLED(F) if(1) { \
|
||||
@@ -61,7 +60,7 @@
|
||||
do { rc = F ; \
|
||||
if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) { \
|
||||
n++; \
|
||||
usleep(SQLTM_TIME); \
|
||||
csync_sleep(SQLTM_TIME); \
|
||||
} \
|
||||
}while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))); \
|
||||
}
|
||||
@@ -472,7 +471,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
|
||||
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
|
||||
|| excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
|
||||
SAFE_FREE(st);
|
||||
csync_file_stat_free(st);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -481,7 +480,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
|
||||
/* store into result list. */
|
||||
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
||||
SAFE_FREE(st);
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -519,8 +518,7 @@ c_strlist_t *csync_statedb_query(sqlite3 *db,
|
||||
/* compile SQL program into a virtual machine, reattempteing if busy */
|
||||
do {
|
||||
if (busy_count) {
|
||||
/* sleep 100 msec */
|
||||
usleep(100000);
|
||||
csync_sleep(100);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count);
|
||||
}
|
||||
err = sqlite3_prepare(db, statement, -1, &stmt, &tail);
|
||||
@@ -547,8 +545,7 @@ c_strlist_t *csync_statedb_query(sqlite3 *db,
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
|
||||
break;
|
||||
}
|
||||
/* sleep 100 msec */
|
||||
usleep(100000);
|
||||
csync_sleep(100);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
#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"
|
||||
|
||||
@@ -45,7 +50,13 @@
|
||||
|
||||
int csync_gettime(struct timespec *tp)
|
||||
{
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
#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;
|
||||
@@ -62,4 +73,11 @@ int csync_gettime(struct timespec *tp)
|
||||
|
||||
#undef CSYNC_CLOCK
|
||||
|
||||
/* vim: set ts=8 sw=2 et cindent: */
|
||||
void csync_sleep(unsigned int msecs)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
Sleep(msecs);
|
||||
#else
|
||||
usleep(msecs * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -26,5 +26,6 @@
|
||||
#include "csync_private.h"
|
||||
|
||||
int csync_gettime(struct timespec *tp);
|
||||
void csync_sleep(unsigned int msecs);
|
||||
|
||||
#endif /* _CSYNC_TIME_H */
|
||||
|
||||
+52
-124
@@ -56,26 +56,13 @@ static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
|
||||
|
||||
if( ctx && file ) {
|
||||
path = file;
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
if (strlen(path) <= strlen(ctx->local.uri)) {
|
||||
return 0;
|
||||
}
|
||||
path += strlen(ctx->local.uri) + 1;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
if (strlen(path) <= strlen(ctx->remote.uri)) {
|
||||
return 0;
|
||||
}
|
||||
path += strlen(ctx->remote.uri) + 1;
|
||||
break;
|
||||
default:
|
||||
path = NULL;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
len = strlen(path);
|
||||
|
||||
h = c_jhash64((uint8_t *) path, len, 0);
|
||||
}
|
||||
return h;
|
||||
@@ -158,7 +145,19 @@ static bool _csync_mtime_equal(time_t a, time_t b)
|
||||
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;
|
||||
@@ -176,25 +175,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
}
|
||||
|
||||
path = file;
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
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;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
if (strlen(path) <= strlen(ctx->remote.uri)) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
path += strlen(ctx->remote.uri) + 1;
|
||||
break;
|
||||
default:
|
||||
path = NULL;
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
@@ -269,8 +255,8 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
tmp = csync_statedb_get_stat_by_hash(ctx, h);
|
||||
|
||||
if(_last_db_return_error(ctx)) {
|
||||
SAFE_FREE(st);
|
||||
SAFE_FREE(tmp);
|
||||
csync_file_stat_free(st);
|
||||
csync_file_stat_free(tmp);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
@@ -314,8 +300,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
}
|
||||
if (checksumIdentical) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
st->should_update_metadata = true;
|
||||
st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -341,23 +326,24 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
|
||||
ctx->remote.read_from_db = true;
|
||||
}
|
||||
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->should_update_metadata = 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;
|
||||
}
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
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 */
|
||||
SAFE_FREE(tmp);
|
||||
csync_file_stat_free(tmp);
|
||||
|
||||
/* check if it's a file and has been renamed */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
@@ -366,7 +352,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
|
||||
|
||||
if(_last_db_return_error(ctx)) {
|
||||
SAFE_FREE(st);
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
@@ -422,7 +408,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
|
||||
|
||||
if(_last_db_return_error(ctx)) {
|
||||
SAFE_FREE(st);
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
@@ -450,8 +436,8 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
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)) {
|
||||
SAFE_FREE(st);
|
||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
|
||||
csync_file_stat_free(st);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -461,7 +447,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
}
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unable to open statedb" );
|
||||
SAFE_FREE(st);
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
return -1;
|
||||
}
|
||||
@@ -477,6 +463,8 @@ out:
|
||||
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 ) {
|
||||
@@ -486,7 +474,9 @@ out:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
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;
|
||||
}
|
||||
@@ -523,14 +513,14 @@ out:
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
|
||||
SAFE_FREE(st);
|
||||
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) {
|
||||
SAFE_FREE(st);
|
||||
csync_file_stat_free(st);
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
@@ -613,16 +603,7 @@ int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
|
||||
|
||||
static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
|
||||
{
|
||||
const char *path = NULL;
|
||||
|
||||
if( strlen(uri) < strlen(ctx->remote.uri)+1) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "name does not contain remote uri!");
|
||||
return false;
|
||||
}
|
||||
|
||||
path = uri + strlen(ctx->remote.uri)+1;
|
||||
|
||||
if( csync_statedb_get_below_path(ctx, path) < 0 ) {
|
||||
if( csync_statedb_get_below_path(ctx, uri) < 0 ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!");
|
||||
return false;
|
||||
}
|
||||
@@ -664,12 +645,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
|
||||
bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
|
||||
|
||||
if (uri[0] == '\0') {
|
||||
errno = ENOENT;
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
read_from_db = ctx->remote.read_from_db;
|
||||
|
||||
// if the etag of this dir is still the same, its content is restored from the
|
||||
@@ -683,16 +658,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
goto done;
|
||||
}
|
||||
|
||||
const char *uri_for_vio = uri;
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
uri_for_vio += strlen(ctx->remote.uri);
|
||||
if (strlen(uri_for_vio) > 0 && uri_for_vio[0] == '/') {
|
||||
uri_for_vio++; // cut leading slash
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "URI without fuzz for %s is \"%s\"", uri, uri_for_vio);
|
||||
}
|
||||
|
||||
if ((dh = csync_vio_opendir(ctx, uri_for_vio)) == NULL) {
|
||||
if ((dh = csync_vio_opendir(ctx, uri)) == NULL) {
|
||||
if (ctx->abort) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
|
||||
ctx->status_code = CSYNC_STATUS_ABORTED;
|
||||
@@ -738,8 +704,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
}
|
||||
|
||||
while ((dirent = csync_vio_readdir(ctx, dh))) {
|
||||
const char *path = NULL;
|
||||
size_t ulen = 0;
|
||||
int flen;
|
||||
int flag;
|
||||
|
||||
@@ -765,50 +729,19 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
continue;
|
||||
}
|
||||
|
||||
flen = asprintf(&filename, "%s/%s", uri, d_name);
|
||||
if (flen < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Create relative path */
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
ulen = strlen(ctx->local.uri) + 1;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
ulen = strlen(ctx->remote.uri) + 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (((size_t)flen) < ulen) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
path = filename + ulen;
|
||||
|
||||
/* skip ".csync_journal.db" and ".csync_journal.db.ctmp" */
|
||||
/* Isn't this done via csync_exclude already? */
|
||||
if (c_streq(path, ".csync_journal.db")
|
||||
|| c_streq(path, ".csync_journal.db.ctmp")
|
||||
|| c_streq(path, ".csync_journal.db.ctmp-journal")
|
||||
|| c_streq(path, ".csync-progressdatabase")
|
||||
|| c_streq(path, ".csync_journal.db-shm")
|
||||
|| c_streq(path, ".csync_journal.db-wal")
|
||||
|| c_streq(path, ".csync_journal.db-journal")) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
SAFE_FREE(filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -875,10 +808,11 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
|
||||
if (ctx->current_fs && !ctx->current_fs->child_modified
|
||||
&& ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
|
||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
ctx->current_fs->should_update_metadata = true;
|
||||
}
|
||||
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) {
|
||||
@@ -892,12 +826,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
previous_fs->child_modified = ctx->current_fs->child_modified;
|
||||
}
|
||||
|
||||
if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
|
||||
&& (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
|
||||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW)) {
|
||||
ctx->current_fs->should_update_metadata = true;
|
||||
}
|
||||
|
||||
ctx->current_fs = previous_fs;
|
||||
ctx->remote.read_from_db = read_from_db;
|
||||
SAFE_FREE(filename);
|
||||
|
||||
@@ -56,6 +56,7 @@ static const _instr_code_struct _instr[] =
|
||||
{ "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
|
||||
{ "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
|
||||
{ "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE },
|
||||
{ "INSTRUCTION_UPDATE_METADATA", CSYNC_INSTRUCTION_UPDATE_METADATA },
|
||||
{ NULL, CSYNC_INSTRUCTION_ERROR }
|
||||
};
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
const char *csync_instruction_str(enum csync_instructions_e instr);
|
||||
const char OCSYNC_EXPORT *csync_instruction_str(enum csync_instructions_e instr);
|
||||
|
||||
void csync_memstat_check(void);
|
||||
void OCSYNC_EXPORT csync_memstat_check(void);
|
||||
|
||||
bool csync_file_locked_or_open( const char *dir, const char *fname);
|
||||
bool OCSYNC_EXPORT csync_file_locked_or_open( const char *dir, const char *fname);
|
||||
#endif /* _CSYNC_UTIL_H */
|
||||
|
||||
@@ -26,6 +26,12 @@ set(cstdlib_SRCS
|
||||
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}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
https://raw.githubusercontent.com/littlstar/asprintf.c/20ce5207a4ecb24017b5a17e6cd7d006e3047146/asprintf.c
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Little Star Media, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* `asprintf.c' - asprintf
|
||||
*
|
||||
* copyright (c) 2014 joseph werle <joseph.werle@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "asprintf.h"
|
||||
|
||||
int
|
||||
asprintf (char **str, const char *fmt, ...) {
|
||||
int size = 0;
|
||||
va_list args;
|
||||
|
||||
// init variadic argumens
|
||||
va_start(args, fmt);
|
||||
|
||||
// format and get size
|
||||
size = vasprintf(str, fmt, args);
|
||||
|
||||
// toss args
|
||||
va_end(args);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int
|
||||
vasprintf (char **str, const char *fmt, va_list args) {
|
||||
int size = 0;
|
||||
va_list tmpa;
|
||||
|
||||
// copy
|
||||
va_copy(tmpa, args);
|
||||
|
||||
// apply variadic arguments to
|
||||
// sprintf with format to get size
|
||||
size = vsnprintf(NULL, size, fmt, tmpa);
|
||||
|
||||
// toss args
|
||||
va_end(tmpa);
|
||||
|
||||
// return -1 to be compliant if
|
||||
// size is less than 0
|
||||
if (size < 0) { return -1; }
|
||||
|
||||
// alloc with size plus 1 for `\0'
|
||||
*str = (char *) malloc(size + 1);
|
||||
|
||||
// return -1 to be compliant
|
||||
// if pointer is `NULL'
|
||||
if (NULL == *str) { return -1; }
|
||||
|
||||
// format string with original
|
||||
// variadic arguments and set new size
|
||||
size = vsprintf(*str, fmt, args);
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
https://raw.githubusercontent.com/littlstar/asprintf.c/20ce5207a4ecb24017b5a17e6cd7d006e3047146/asprintf.h
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Little Star Media, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* `asprintf.h' - asprintf.c
|
||||
*
|
||||
* copyright (c) 2014 joseph werle <joseph.werle@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
#ifndef ASPRINTF_H
|
||||
#define ASPRINTF_H 1
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Sets `char **' pointer to be a buffer
|
||||
* large enough to hold the formatted string
|
||||
* accepting a `va_list' args of variadic
|
||||
* arguments.
|
||||
*/
|
||||
|
||||
int
|
||||
vasprintf (char **, const char *, va_list);
|
||||
|
||||
/**
|
||||
* Sets `char **' pointer to be a buffer
|
||||
* large enough to hold the formatted
|
||||
* string accepting `n' arguments of
|
||||
* variadic arguments.
|
||||
*/
|
||||
|
||||
int
|
||||
asprintf (char **, const char *, ...);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -31,14 +31,17 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <wchar.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef __MINGW32__
|
||||
#define EDQUOT 0
|
||||
#define ENODATA 0
|
||||
#ifndef S_IRGRP
|
||||
@@ -65,6 +68,8 @@
|
||||
#define nlink_t int
|
||||
#define getuid() 0
|
||||
#define geteuid() 0
|
||||
#elif defined(_WIN32)
|
||||
#define mode_t int
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
@@ -89,8 +94,12 @@ typedef struct stat csync_stat_t;
|
||||
#define ENODATA EBADF
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_ASPRINTF) && defined(HAVE___MINGW_ASPRINTF)
|
||||
#if !defined(HAVE_ASPRINTF)
|
||||
#if defined(HAVE___MINGW_ASPRINTF)
|
||||
#define asprintf __mingw_asprintf
|
||||
#else
|
||||
#include "asprintf.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRERROR_R
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
#include "c_path.h"
|
||||
#include "c_time.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
struct timespec c_tspecdiff(struct timespec time1, struct timespec time0) {
|
||||
struct timespec ret;
|
||||
int xsec = 0;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define _C_TIME_H
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/**
|
||||
* @brief Calculate time difference
|
||||
|
||||
@@ -56,6 +56,7 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,10 @@
|
||||
#ifndef _CSYNC_VIO_LOCAL_H
|
||||
#define _CSYNC_VIO_LOCAL_H
|
||||
|
||||
#include <sys/time.h>
|
||||
csync_vio_handle_t OCSYNC_EXPORT *csync_vio_local_opendir(const char *name);
|
||||
int OCSYNC_EXPORT csync_vio_local_closedir(csync_vio_handle_t *dhandle);
|
||||
csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_local_readdir(csync_vio_handle_t *dhandle);
|
||||
|
||||
csync_vio_handle_t *csync_vio_local_opendir(const char *name);
|
||||
int csync_vio_local_closedir(csync_vio_handle_t *dhandle);
|
||||
csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle);
|
||||
|
||||
int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf);
|
||||
int OCSYNC_EXPORT csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf);
|
||||
|
||||
#endif /* _CSYNC_VIO_LOCAL_H */
|
||||
|
||||
@@ -141,7 +141,7 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
|
||||
return file_stat;
|
||||
|
||||
err:
|
||||
SAFE_FREE(file_stat);
|
||||
csync_vio_file_stat_destroy(file_stat);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "windows.h"
|
||||
@@ -167,16 +166,20 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
|
||||
}
|
||||
file_stat->name = c_utf8_from_locale(handle->ffd.cFileName);
|
||||
|
||||
file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE;
|
||||
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
if ( (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
&& (handle->ffd.dwReserved0 & IO_REPARSE_TAG_SYMLINK)
|
||||
// The SIS or DEDUP flag points to a MS deduplication feature of
|
||||
// certain file storage products. It is not a normal symlink
|
||||
// that should be ignored.
|
||||
&& (! (handle->ffd.dwReserved0 & IO_REPARSE_TAG_SIS))
|
||||
&& (! (handle->ffd.dwReserved0 & IO_REPARSE_TAG_DEDUP)) ) {
|
||||
file_stat->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK;
|
||||
file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
|
||||
if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
// Detect symlinks, and treat junctions as symlinks too.
|
||||
if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK
|
||||
|| handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) {
|
||||
file_stat->flags |= CSYNC_VIO_FILE_FLAGS_SYMLINK;
|
||||
file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
|
||||
} else {
|
||||
// The SIS and DEDUP reparse points should be treated as
|
||||
// regular files. We don't know about the other ones yet,
|
||||
// but will also treat them normally for now.
|
||||
file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
}
|
||||
} else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE
|
||||
|| handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE
|
||||
|| handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
|
||||
@@ -187,7 +190,6 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
|
||||
file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
}
|
||||
|
||||
file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE;
|
||||
/* Check for the hidden flag */
|
||||
if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) {
|
||||
file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
|
||||
|
||||
@@ -23,38 +23,36 @@
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_module(void **state) {
|
||||
static int setup_module(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
|
||||
|
||||
csync_init(csync);
|
||||
csync_init(csync, "foo");
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -66,10 +64,9 @@ static void teardown(void **state) {
|
||||
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_commit(void **state)
|
||||
@@ -97,10 +94,10 @@ static void check_csync_commit_dummy(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_commit, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_commit_dummy, setup_module, teardown),
|
||||
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 run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ static void check_csync_create(void **state)
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
csync_create(&csync, "/tmp/csync1", "/tmp/csync2");
|
||||
csync_create(&csync, "/tmp/csync1");
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
@@ -50,11 +50,11 @@ static void check_csync_create(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_csync_destroy_null),
|
||||
unit_test(check_csync_create),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_csync_destroy_null),
|
||||
cmocka_unit_test(check_csync_create),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "config_csync.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
@@ -28,20 +29,20 @@
|
||||
|
||||
#define EXCLUDE_LIST_FILE SOURCEDIR"/../sync-exclude.lst"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_init(void **state) {
|
||||
static int setup_init(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes));
|
||||
assert_int_equal(rc, 0);
|
||||
@@ -59,9 +60,10 @@ static void setup_init(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -74,6 +76,8 @@ static void teardown(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_exclude_add(void **state)
|
||||
@@ -143,6 +147,17 @@ static void check_csync_excluded(void **state)
|
||||
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);
|
||||
|
||||
|
||||
/* pattern ]*.directory - ignore and remove */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE);
|
||||
@@ -179,6 +194,20 @@ static void check_csync_excluded(void **state)
|
||||
|
||||
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)
|
||||
@@ -305,13 +334,14 @@ static void check_csync_excluded_performance(void **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 (int i = 0; i < N; ++i) {
|
||||
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);
|
||||
}
|
||||
@@ -329,7 +359,7 @@ static void check_csync_excluded_performance(void **state)
|
||||
struct timeval before, after;
|
||||
gettimeofday(&before, 0);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
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);
|
||||
}
|
||||
@@ -365,16 +395,16 @@ static void check_csync_exclude_expand_escapes(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_exclude_add, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_exclude_load, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_excluded_traversal, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
|
||||
unit_test(check_csync_exclude_expand_escapes),
|
||||
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 run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -23,37 +23,33 @@
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_module(void **state) {
|
||||
static int setup_module(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -65,29 +61,28 @@ static void teardown(void **state) {
|
||||
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_init(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
csync_init(csync);
|
||||
csync_init(csync, "");
|
||||
|
||||
assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
|
||||
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_init, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_init, setup_module, teardown),
|
||||
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 run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
@@ -27,22 +26,21 @@
|
||||
#include "csync_log.c"
|
||||
#include "c_private.h"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -54,10 +52,9 @@ static void teardown(void **state) {
|
||||
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_log_callback(int verbosity,
|
||||
@@ -141,11 +138,11 @@ static void check_logging(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_set_log_level),
|
||||
unit_test(check_set_auth_callback),
|
||||
unit_test_setup_teardown(check_logging, setup, teardown),
|
||||
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 run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ static void check_csync_normalize_etag(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_csync_normalize_etag),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_csync_normalize_etag),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
@@ -27,7 +26,7 @@
|
||||
|
||||
#define TESTDB "/tmp/check_csync1/test.db"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
@@ -37,7 +36,7 @@ static void setup(void **state) {
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
csync->statedb.file = c_strdup( TESTDB );
|
||||
*state = csync;
|
||||
@@ -48,9 +47,11 @@ static void setup(void **state) {
|
||||
|
||||
rc = sqlite3_close(db);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -61,6 +62,8 @@ static void teardown(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_statedb_load(void **state)
|
||||
@@ -117,11 +120,11 @@ static void check_csync_statedb_close(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_statedb_load, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_close, setup, teardown),
|
||||
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 run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,23 +27,19 @@
|
||||
|
||||
|
||||
|
||||
static void setup(void **state)
|
||||
static int setup(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int 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);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_init(csync);
|
||||
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);
|
||||
@@ -55,9 +51,11 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_db(void **state)
|
||||
static int setup_db(void **state)
|
||||
{
|
||||
char *errmsg;
|
||||
int rc = 0;
|
||||
@@ -93,10 +91,12 @@ static void setup_db(void **state)
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc = 0;
|
||||
|
||||
@@ -106,10 +106,10 @@ static void teardown(void **state) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,15 +210,15 @@ static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
|
||||
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 run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ static void statedb_insert_metadata(sqlite3 *db)
|
||||
}
|
||||
}
|
||||
|
||||
static void setup(void **state)
|
||||
static int setup(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
@@ -91,10 +91,8 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_init(csync);
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
csync_init(csync, TESTDB);
|
||||
|
||||
/* Create a new db with metadata */
|
||||
sqlite3 *db;
|
||||
@@ -111,9 +109,11 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_ftw(void **state)
|
||||
static int setup_ftw(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
@@ -122,10 +122,8 @@ static void setup_ftw(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp", "/tmp");
|
||||
csync_init(csync);
|
||||
csync_create(&csync, "/tmp");
|
||||
csync_init(csync, TESTDB);
|
||||
|
||||
sqlite3 *db = NULL;
|
||||
rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
|
||||
@@ -139,9 +137,11 @@ static void setup_ftw(void **state)
|
||||
|
||||
csync->statedb.file = c_strdup( TESTDB );
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state)
|
||||
static int teardown(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
@@ -151,9 +151,11 @@ static void teardown(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown_rm(void **state) {
|
||||
static int teardown_rm(void **state) {
|
||||
int rc;
|
||||
|
||||
teardown(state);
|
||||
@@ -162,8 +164,8 @@ static void teardown_rm(void **state) {
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create a file stat, caller must free memory */
|
||||
@@ -430,19 +432,19 @@ static void check_csync_ftw_failing_fn(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
|
||||
|
||||
unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,11 @@ static void check_csync_memstat(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_csync_instruction_str),
|
||||
unit_test(check_csync_memstat),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_csync_instruction_str),
|
||||
cmocka_unit_test(check_csync_memstat),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -457,6 +457,7 @@ sub traverse( $$;$ )
|
||||
|
||||
$isHere = 1 if( $acceptConflicts && !$isHere && $f =~ /_conflict/ );
|
||||
$isHere = 1 if( $f =~ /\.csync/ );
|
||||
$isHere = 1 if( $f =~ /\._sync_/ );
|
||||
assert( $isHere, "Filename local, but not remote: $f" );
|
||||
}
|
||||
|
||||
@@ -520,7 +521,7 @@ sub put_to_dir( $$;$ )
|
||||
$targetUrl = $optionsRef->{url};
|
||||
}
|
||||
}
|
||||
$d->open($dir);
|
||||
$d->open($targetUrl . $dir);
|
||||
|
||||
my $filename = $file;
|
||||
$filename =~ s/^.*\///;
|
||||
|
||||
@@ -176,7 +176,7 @@ assertLocalAndRemoteDir( 'remoteToLocal1', 1);
|
||||
|
||||
printInfo("simulate a owncloud 5 update by removing all the fileid");
|
||||
## simulate a owncloud 5 update by removing all the fileid
|
||||
system( "sqlite3 " . localDir() . ".csync_journal.db \"UPDATE metadata SET fileid='';\"");
|
||||
system( "sqlite3 " . localDir() . "._sync_*.db \"UPDATE metadata SET fileid='';\"");
|
||||
#refresh the ids
|
||||
csync();
|
||||
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
|
||||
|
||||
@@ -61,7 +61,7 @@ sub getETagFromJournal($$)
|
||||
{
|
||||
my ($name,$num) = @_;
|
||||
|
||||
my $sql = "sqlite3 " . localDir() . ".csync_journal.db \"SELECT md5 FROM metadata WHERE path='$name';\"";
|
||||
my $sql = "sqlite3 " . localDir() . "._sync_*.db \"SELECT md5 FROM metadata WHERE path='$name';\"";
|
||||
open(my $fh, '-|', $sql) or die $!;
|
||||
my $etag = <$fh>;
|
||||
close $fh;
|
||||
|
||||
@@ -37,8 +37,8 @@ sub assertCsyncJournalOk {
|
||||
my $path = $_[0];
|
||||
|
||||
# FIXME: should test also remoteperm but it's not working with owncloud6
|
||||
# my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(remotePerm) == 0 or length(fileId) == 0"';
|
||||
my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(fileId) == 0"';
|
||||
# my $cmd = 'sqlite3 ' . $path . '._sync_*.db "SELECT count(*) from metadata where length(remotePerm) == 0 or length(fileId) == 0"';
|
||||
my $cmd = 'sqlite3 ' . $path . '._sync_*.db "SELECT count(*) from metadata where length(fileId) == 0"';
|
||||
my $result = `$cmd`;
|
||||
assert($result == "0");
|
||||
}
|
||||
@@ -170,14 +170,14 @@ assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
#######################################################################
|
||||
printInfo( "move a directory in a outside read only folder" );
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
system("sqlite3 " . localDir().'._sync_*.db .dump');
|
||||
|
||||
#Missing directory should be restored
|
||||
#new directory should be uploaded
|
||||
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_' );
|
||||
|
||||
csync();
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
system("sqlite3 " . localDir().'._sync_*.db .dump');
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
# old name restored
|
||||
@@ -229,7 +229,38 @@ system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/moved_PERM_CK_");
|
||||
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
system("sqlite3 " . localDir().'._sync_*.db .dump');
|
||||
|
||||
|
||||
#######################################################################
|
||||
printInfo( "multiple restores of a file create different conflict files" );
|
||||
|
||||
system("sleep 1"); #make sure changes have different mtime
|
||||
|
||||
system("echo 'modified_1' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
|
||||
|
||||
#do the sync
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
system("sleep 1"); #make sure changes have different mtime
|
||||
|
||||
system("echo 'modified_2' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
|
||||
|
||||
#do the sync
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
# there should be two conflict files
|
||||
# TODO check that the conflict file has the right content
|
||||
my @conflicts = glob(localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
|
||||
assert( scalar @conflicts == 2 );
|
||||
# remove the conflicts for the next assertLocalAndRemoteDir
|
||||
system("rm " . localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
|
||||
|
||||
### Both side should still be the same
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
|
||||
cleanup();
|
||||
|
||||
@@ -56,6 +56,8 @@ assertLocalAndRemoteDir( '', 0);
|
||||
printInfo( "Testing with a .sys.admin#recall#" );
|
||||
system("echo 'dir/file2.dat' > ". $tmpdir . ".sys.admin\#recall\#");
|
||||
system("echo 'dir/file3.dat' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||
system("echo 'nonexistant' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||
system("echo '/tmp/t_recall/file4.dat' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||
glob_put( "$tmpdir/.sys.admin\#recall\#", "" );
|
||||
|
||||
csync();
|
||||
@@ -64,6 +66,14 @@ csync();
|
||||
assert( -e glob(localDir().'dir/file2_.sys.admin#recall#-*.dat' ) );
|
||||
assert( -e glob(localDir().'dir/file3_.sys.admin#recall#-*.dat' ) );
|
||||
|
||||
# verify that the original files still exist
|
||||
assert( -e glob(localDir().'dir/file2.dat' ) );
|
||||
assert( -e glob(localDir().'dir/file3.dat' ) );
|
||||
|
||||
assert( !-e glob(localDir().'nonexistant*' ) );
|
||||
assert( !-e glob('/tmp/t_recall/file4_.sys.admin#recall#-*.dat' ) );
|
||||
assert( -e glob('/tmp/t_recall/file4.dat' ) );
|
||||
|
||||
#Remove the recall file
|
||||
unlink(localDir() . ".sys.admin#recall#");
|
||||
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário