mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-04 12:11:33 +02:00
Compare commits
354 Commits
v1.6.1-rc1
...
v1.7.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
600a6d9346 | ||
|
|
0e22864426 | ||
|
|
5306cdc7a1 | ||
|
|
344b98bf13 | ||
|
|
261d7ee688 | ||
|
|
633267c457 | ||
|
|
80f9ed70d3 | ||
|
|
fa8f6f91c4 | ||
|
|
c3f8e099f4 | ||
|
|
6cb8134690 | ||
|
|
95a77e5ccc | ||
|
|
21783ecef7 | ||
|
|
d8a8b53fc9 | ||
|
|
e71ce01f90 | ||
|
|
6827f9977c | ||
|
|
6d24bd0361 | ||
|
|
22c1629dd3 | ||
|
|
bd9d5432f5 | ||
|
|
370ee5c6f6 | ||
|
|
fe2e4d87c5 | ||
|
|
e9c4635f6b | ||
|
|
7337010fd8 | ||
|
|
f06019ab81 | ||
|
|
55567f8dd2 | ||
|
|
2ccfdcb084 | ||
|
|
084d9de4c9 | ||
|
|
41875c2ddb | ||
|
|
4ad9ff4301 | ||
|
|
c7ff1e9b3f | ||
|
|
fe3f751a8a | ||
|
|
996b7166d2 | ||
|
|
839b2fa8fd | ||
|
|
8b1aebcdba | ||
|
|
f4e2041b0b | ||
|
|
24df6f838d | ||
|
|
c313cc02f2 | ||
|
|
4e13c882f8 | ||
|
|
0fe51d826f | ||
|
|
b2976baf9b | ||
|
|
a0a5a49d7b | ||
|
|
9a1781f613 | ||
|
|
f983264b5d | ||
|
|
40cebeedfc | ||
|
|
1f9280c68e | ||
|
|
14ed261606 | ||
|
|
4fb671e7f4 | ||
|
|
aad5c96759 | ||
|
|
72b8da317f | ||
|
|
7f9033f1f1 | ||
|
|
a42e384935 | ||
|
|
9b37357513 | ||
|
|
23269c9a08 | ||
|
|
327f70240c | ||
|
|
0a7642dbe0 | ||
|
|
742b036a07 | ||
|
|
6e00989a9e | ||
|
|
68f0227ca1 | ||
|
|
fe9a2e7ba4 | ||
|
|
a248fc36fe | ||
|
|
e28a7a7ae3 | ||
|
|
b92789825d | ||
|
|
c3b6aecb79 | ||
|
|
4688126f84 | ||
|
|
5a5c03a826 | ||
|
|
f3477877d0 | ||
|
|
7bef588851 | ||
|
|
72a25cf6ee | ||
|
|
74e13f4c70 | ||
|
|
3c09ef6cbf | ||
|
|
68bfcf5d24 | ||
|
|
b2a10de71a | ||
|
|
267b9e5c2f | ||
|
|
55d94bf15a | ||
|
|
629e2a9e1c | ||
|
|
86acdf69d9 | ||
|
|
a6987ad703 | ||
|
|
5642e40bc8 | ||
|
|
50d178feaa | ||
|
|
8d71328192 | ||
|
|
17b320f7dc | ||
|
|
f1ad82d0ba | ||
|
|
2fb283749c | ||
|
|
5a4c023fc9 | ||
|
|
e8afac3a01 | ||
|
|
6284517dc9 | ||
|
|
80c096b6f1 | ||
|
|
f004d5085d | ||
|
|
98e21ae0ad | ||
|
|
00274722ce | ||
|
|
8b93678e3d | ||
|
|
3d0c009719 | ||
|
|
1b3ec955b1 | ||
|
|
208011f6ab | ||
|
|
f84e0010ee | ||
|
|
c97f46d403 | ||
|
|
5356898efc | ||
|
|
1fb52f0d8b | ||
|
|
d4de024f15 | ||
|
|
1d9d88ca85 | ||
|
|
2ca8805cda | ||
|
|
8e5c41e6f3 | ||
|
|
0f7efbc22e | ||
|
|
6b7bd07c97 | ||
|
|
8d85516e72 | ||
|
|
0f4cf74ae0 | ||
|
|
4dfe0fad7d | ||
|
|
2e91ea8093 | ||
|
|
77e3480b2f | ||
|
|
bca1ef42fc | ||
|
|
010ab7119e | ||
|
|
3cb93510ac | ||
|
|
8a88ca6f34 | ||
|
|
81d786733d | ||
|
|
336e74b992 | ||
|
|
beb9300b4e | ||
|
|
74b3e2ce3f | ||
|
|
c35880d4f1 | ||
|
|
ed6e3e4ee2 | ||
|
|
f8bea55b10 | ||
|
|
72cd84e878 | ||
|
|
35b6d09615 | ||
|
|
1ae727e70f | ||
|
|
0e5d0c1170 | ||
|
|
7ff62bc577 | ||
|
|
743c1c2eda | ||
|
|
0e9a08cbbf | ||
|
|
d2445ec72d | ||
|
|
fef713aaed | ||
|
|
c4d73688a6 | ||
|
|
56b721b2eb | ||
|
|
2981b37219 | ||
|
|
cfc2f84d3e | ||
|
|
d8ebebaf12 | ||
|
|
2a5691e575 | ||
|
|
774432066e | ||
|
|
e6c501de8e | ||
|
|
af3fae9c28 | ||
|
|
d5a8661480 | ||
|
|
d3b72940fd | ||
|
|
e8de3e855a | ||
|
|
71338000a4 | ||
|
|
2fdb3cfdfb | ||
|
|
8961e61f60 | ||
|
|
e5191acd73 | ||
|
|
d697969f36 | ||
|
|
51e9c5fd96 | ||
|
|
997504c03c | ||
|
|
0202351a27 | ||
|
|
dde06dfaba | ||
|
|
eb0f074097 | ||
|
|
b6c9b5645c | ||
|
|
a281b36d6f | ||
|
|
7772501cdf | ||
|
|
d1b991e198 | ||
|
|
00f793a841 | ||
|
|
bdb9598227 | ||
|
|
c6deb392fd | ||
|
|
3477ea0eeb | ||
|
|
9dacad99fa | ||
|
|
73e35c66af | ||
|
|
d3b599b727 | ||
|
|
4369151cd8 | ||
|
|
846773efd3 | ||
|
|
bcfa34357b | ||
|
|
e0c2e8ed86 | ||
|
|
b80a3876ab | ||
|
|
26e17f58ef | ||
|
|
45d1567057 | ||
|
|
8aacb3f7ec | ||
|
|
99ee81a489 | ||
|
|
517ffbd783 | ||
|
|
7dd926d4f1 | ||
|
|
cbc7942a00 | ||
|
|
63cd5ef563 | ||
|
|
3806905f5b | ||
|
|
82c254fecf | ||
|
|
2496f23e45 | ||
|
|
86bea9a9af | ||
|
|
4bb1172c84 | ||
|
|
88f26fb548 | ||
|
|
a9f1de84f0 | ||
|
|
367ff79ef1 | ||
|
|
2961c44bbe | ||
|
|
997559dc6d | ||
|
|
79d28bbc35 | ||
|
|
6bc425f981 | ||
|
|
2cdfc16829 | ||
|
|
e63d45cca9 | ||
|
|
553f186b7c | ||
|
|
623dfc0286 | ||
|
|
ffa7f35a87 | ||
|
|
081b7d4aa9 | ||
|
|
9c3c4bac66 | ||
|
|
6ec218ef11 | ||
|
|
ad2eabeb3b | ||
|
|
26c377d05b | ||
|
|
caa75d98be | ||
|
|
3ad9356ca4 | ||
|
|
dd5296f03c | ||
|
|
e673d76f22 | ||
|
|
393eb7bb4d | ||
|
|
2fa5a5b8c3 | ||
|
|
ca63b79ed8 | ||
|
|
f8b097669a | ||
|
|
2f284209d8 | ||
|
|
09881040a3 | ||
|
|
9066ad5790 | ||
|
|
62d0e670dc | ||
|
|
e7d597045b | ||
|
|
eaa3a2eae2 | ||
|
|
40d765c73a | ||
|
|
21d7d8988a | ||
|
|
e76386be4f | ||
|
|
b3b3ca0e16 | ||
|
|
730e86c4cd | ||
|
|
23e0af5cc1 | ||
|
|
a92f1cb055 | ||
|
|
a54162e009 | ||
|
|
48864a6921 | ||
|
|
92f07cb60f | ||
|
|
5f96de32bb | ||
|
|
d2436ce23d | ||
|
|
fbadadc377 | ||
|
|
9adc30ab9f | ||
|
|
8de3bda0b1 | ||
|
|
3c4f410a4e | ||
|
|
9c0a21a5fb | ||
|
|
94ddf7e5d8 | ||
|
|
f45dd8e94f | ||
|
|
b735dc07d6 | ||
|
|
68c902e60b | ||
|
|
e19214c3c4 | ||
|
|
4759429702 | ||
|
|
b626589c07 | ||
|
|
02704cdf74 | ||
|
|
a7d251f8fc | ||
|
|
4555d4bcbe | ||
|
|
184e58f5e5 | ||
|
|
5c7f3c1642 | ||
|
|
36331512bc | ||
|
|
3e916cfbb9 | ||
|
|
4a9ad14e11 | ||
|
|
f80816d88f | ||
|
|
817f89d586 | ||
|
|
458645101b | ||
|
|
1e306012ec | ||
|
|
db2c198feb | ||
|
|
71a901a24e | ||
|
|
f4ea34e63b | ||
|
|
0d54b88ab2 | ||
|
|
da0bd14bf3 | ||
|
|
6ce746b9ea | ||
|
|
02355696ff | ||
|
|
38254125c9 | ||
|
|
e5b3363ecf | ||
|
|
6c3eb06b65 | ||
|
|
c759e8bb8f | ||
|
|
b83f6c0b3a | ||
|
|
ade92d8ac1 | ||
|
|
08398784e4 | ||
|
|
afea881d90 | ||
|
|
194bba2118 | ||
|
|
a5967e4ecd | ||
|
|
21e22a50c5 | ||
|
|
2f361278d2 | ||
|
|
319cf76417 | ||
|
|
be7b08b50a | ||
|
|
22c01748ce | ||
|
|
02809d5016 | ||
|
|
d21f312936 | ||
|
|
357b041bb4 | ||
|
|
61999a67cd | ||
|
|
8da97a7c6f | ||
|
|
2caa69e0cb | ||
|
|
c5932569f8 | ||
|
|
1921d1a5be | ||
|
|
8745a684ae | ||
|
|
892cd962f8 | ||
|
|
3f543b881d | ||
|
|
4a1d0eb80e | ||
|
|
760ecd71fc | ||
|
|
04f1026cd8 | ||
|
|
b03c4cc62e | ||
|
|
18e9357aaf | ||
|
|
46b8260693 | ||
|
|
d5bd3190d4 | ||
|
|
e497b6d458 | ||
|
|
2e4320ee05 | ||
|
|
3406fcdce4 | ||
|
|
14a5ff6747 | ||
|
|
8dbfcd782b | ||
|
|
abf0f90a13 | ||
|
|
4d5c74c019 | ||
|
|
70ff928381 | ||
|
|
b48ab79a92 | ||
|
|
9a7fbd4f71 | ||
|
|
ef3b4956ad | ||
|
|
fd4642d827 | ||
|
|
6dd248e527 | ||
|
|
7d00c3646a | ||
|
|
e355e12385 | ||
|
|
34b31c0146 | ||
|
|
3934fa019e | ||
|
|
dc53e96f92 | ||
|
|
7fcf6f9f79 | ||
|
|
bd48ab23c3 | ||
|
|
4e28ba73bb | ||
|
|
16cb37ecd0 | ||
|
|
d4d630b2e9 | ||
|
|
2ff27cdd63 | ||
|
|
2f81167164 | ||
|
|
6897c5d41f | ||
|
|
233450d850 | ||
|
|
7428a8fa63 | ||
|
|
18359d7871 | ||
|
|
df12a58e3d | ||
|
|
4b3d124b5a | ||
|
|
51e941e7b5 | ||
|
|
62ea6f316f | ||
|
|
4cb9b3a85b | ||
|
|
806ab8ea46 | ||
|
|
582a8fe7fd | ||
|
|
08ca8b54b1 | ||
|
|
abafbef985 | ||
|
|
06863ca9c6 | ||
|
|
e49b8981dd | ||
|
|
2e91557c28 | ||
|
|
4d4eab8b1c | ||
|
|
4d4ae9374b | ||
|
|
b8e20b412c | ||
|
|
e36f3c5b10 | ||
|
|
8a55f831f4 | ||
|
|
0dcc9be5c1 | ||
|
|
5ee00a8df7 | ||
|
|
1af3d3f18b | ||
|
|
f54248c0a7 | ||
|
|
2911c0e1c4 | ||
|
|
16d35c1489 | ||
|
|
cd82a8585a | ||
|
|
6927fc80c3 | ||
|
|
89a95d6445 | ||
|
|
f9192e27fa | ||
|
|
ba5e955ccb | ||
|
|
fae3e46a59 | ||
|
|
3777074e84 | ||
|
|
5310a3cc1d | ||
|
|
1509c4ffba | ||
|
|
71ea2b582c | ||
|
|
219098c182 | ||
|
|
35b3ddd61f | ||
|
|
a892b79dba | ||
|
|
cd22a1846f | ||
|
|
eadcdab8e7 | ||
|
|
46ffd1c29a |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -2,3 +2,4 @@
|
||||
.gitignore export-ignore
|
||||
.gitattributes export-ignore
|
||||
.commit-template export-ignore
|
||||
/binary export-ignore
|
||||
|
||||
150
.gitignore
vendored
150
.gitignore
vendored
@@ -16,3 +16,153 @@ build*
|
||||
cscope.*
|
||||
tags
|
||||
t1.cfg
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Roslyn cache directories
|
||||
*.ide/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
#NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Mac OS X specific
|
||||
shell_integration/MacOSX/LiferayNativity.xcworkspace/xcuserdata/
|
||||
**/.DS_Store
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
## TODO: Comment the next line if you want to checkin your
|
||||
## web deploy settings but do note that will include unencrypted
|
||||
## passwords
|
||||
*.pubxml
|
||||
|
||||
# NuGet Packages
|
||||
packages/*
|
||||
*.nupkg
|
||||
## TODO: If the tool you use requires repositories.config
|
||||
## uncomment the next line
|
||||
#!packages/repositories.config
|
||||
|
||||
# Enable "build/" folder in the NuGet Packages folder since
|
||||
# NuGet packages use it for MSBuild targets.
|
||||
# This line needs to be after the ignore of the build folder
|
||||
# (and the packages folder if the line above has been uncommented)
|
||||
!packages/build/
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -4,3 +4,6 @@
|
||||
[submodule "src/3rdparty/qtmacgoodies"]
|
||||
path = src/3rdparty/qtmacgoodies
|
||||
url = git://github.com/shadone/qtmacgoodies.git
|
||||
[submodule "binary"]
|
||||
path = binary
|
||||
url = git://github.com/owncloud/owncloud-client-binary.git
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(VERSION 2.8.0)
|
||||
|
||||
project(mirall)
|
||||
set(PACKAGE "mirall")
|
||||
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
||||
@@ -108,7 +110,10 @@ if(NOT TOKEN_AUTH_ONLY)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
Find_package(Sparkle)
|
||||
if(APPLE)
|
||||
find_package(Sparkle)
|
||||
endif(APPLE)
|
||||
|
||||
if(UNIX)
|
||||
find_package(INotify REQUIRED)
|
||||
else()
|
||||
@@ -137,6 +142,7 @@ set(TRANSLATIONS ${TRANS_FILES})
|
||||
|
||||
add_subdirectory(csync)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(shell_integration)
|
||||
add_subdirectory(doc)
|
||||
|
||||
if(UNIT_TESTING)
|
||||
|
||||
35
ChangeLog
35
ChangeLog
@@ -1,5 +1,40 @@
|
||||
ChangeLog
|
||||
=========
|
||||
version 1.6.2 (release 2014-07-x )
|
||||
* Another small mem leak fixed in HTTP Credentials.
|
||||
* Fix local file name clash detection for MacOSX.
|
||||
* Limit maximum wait time to ten seconds in network limiting.
|
||||
* Fix data corruption while trying to resume and the server does
|
||||
not support it.
|
||||
* HTTP Credentials: Read password from legacy place if not found.
|
||||
* Shibboleth: Fix the waiting curser that would not disapear (#1915)
|
||||
* Limit memory usage to avoid mem wasting and crashes
|
||||
* Propagator: Fix crash when logging out during upload (#1957)
|
||||
* Propagator_qnam: Fix signal slot connection (#1963)
|
||||
* Use more elaborated way to detect that the server was reconfigured (#1948)
|
||||
* Setup Wizard: Reconfigure Server also if local path was changed (#1948)
|
||||
|
||||
version 1.6.1 (release 2014-06-26 )
|
||||
* Fix 'precondition failed' bug with broken upload
|
||||
* Fix openSSL problems for windows deployment
|
||||
* Fix syncing a folder with '#' in the name
|
||||
* Fix #1845: do not update parent directory etag before sub
|
||||
directories are removed
|
||||
* Fix reappearing directories if dirs are removed during its
|
||||
upload
|
||||
* Fix app version in settings dialog, General tab
|
||||
* Fix crash in FolderWizard when going offline
|
||||
* Shibboleth fixes
|
||||
* More specific error messages (file remove during upload, open
|
||||
local sync file)
|
||||
* Use QSet rather than QHash in SyncEngine (save memory)
|
||||
* Fix some memory leaks
|
||||
* Fix some thread race problems, ie. wait for neon thread to finish
|
||||
before the propagator is shut down
|
||||
* Fix a lot of issues and warnings found by Coverity
|
||||
* Fix Mac some settings dialog problems
|
||||
|
||||
|
||||
version 1.6.0 (release 2014-05-30 )
|
||||
* Minor GUI improvements
|
||||
* Qt5 compile issues fixed
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
set( MIRALL_VERSION_MAJOR 1 )
|
||||
set( MIRALL_VERSION_MINOR 6 )
|
||||
set( MIRALL_VERSION_PATCH 1 )
|
||||
set( MIRALL_VERSION_MINOR 7 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "rc1") #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "alpha1") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
45
admin/osx/create_mac_pkg.sh
Executable file
45
admin/osx/create_mac_pkg.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to create the Mac installer using the packages tool from
|
||||
# http://s.sudre.free.fr/Software/Packages/about.html
|
||||
#
|
||||
|
||||
# the path of installation must be given as parameter
|
||||
if [ -z "$1" ]; then
|
||||
echo "ERROR: Provide the CMAKE_INSTALL_DIR to this script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
prjfile="admin/osx/macosx.pkgproj"
|
||||
if [ ! -f $prjfile ]; then
|
||||
echo "ERROR: macosx.pkgproj not in admin dir, start from CMAKE_SOURCE_DIR!"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
pack="admin/ownCloud Installer.pkg"
|
||||
rm -f $pack
|
||||
|
||||
install_path=$1
|
||||
|
||||
# The name of the installer package
|
||||
installer=ownCloud\ Installer.pkg
|
||||
|
||||
# The command line tool of the "Packages" tool, see link above.
|
||||
pkgbuild=/usr/local/bin/packagesbuild
|
||||
|
||||
$pkgbuild -F $install_path $prjfile
|
||||
rc=$?
|
||||
|
||||
if [ $rc == 0 ]; then
|
||||
echo "Successfully created $pack"
|
||||
else
|
||||
echo "Failed to create $pack"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# FIXME: Sign the finished package.
|
||||
# See http://s.sudre.free.fr/Software/documentation/Packages/en/Project_Configuration.html#5
|
||||
# certname=gdbsign
|
||||
# productsign --cert $certname admin/$installer ./$installer
|
||||
|
||||
|
||||
1426
admin/osx/macosx.pkgproj
Normal file
1426
admin/osx/macosx.pkgproj
Normal file
File diff suppressed because it is too large
Load Diff
19
admin/win/download_runtimes.sh
Executable file
19
admin/win/download_runtimes.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
#VS2013
|
||||
base_url=http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3
|
||||
tmp_path=/tmp/.vcredist
|
||||
|
||||
mkdir -p $tmp_path
|
||||
|
||||
copy_cached_file() {
|
||||
file=$1
|
||||
if [ ! -e $tmp_path/$file ]; then
|
||||
wget -O $tmp_path/$file $base_url/$file
|
||||
fi
|
||||
cp -a $tmp_path/$file $PWD
|
||||
}
|
||||
|
||||
copy_cached_file "vcredist_x64.exe"
|
||||
copy_cached_file "vcredist_x86.exe"
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Erakutsi bertsio-berritze oharrak"
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "kill prozesua ez da aurkitu!"
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalatu instalatu baino lehen"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Ez desinstalatu"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Dagoeneko Instalatuta"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Hautatu nola nahi duzun ${APPLICATION_NAME} instalatzea."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} dagoeneko instalatuta dago.\nHautatu zer operazio egin nahi duzu eta klikatu Hurrengoa jarraitzeko."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Gehitu/Berrinstalatu osagaiak"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Desinstalatu ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalatu ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Hautatu zer mantenu aukera egin nahi duzun."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Hasierako Menuko Lasterbidea"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Hasierako Menuan ${APPLICATION_NAME}rako Abiarazle bizkorra sortzen."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Mahaigaineko Lasterbidea"
|
||||
@@ -29,14 +32,13 @@ StrCpy $INIT_INSTALLER_RUNNING "Instalatzailea dagoeneko martxan da."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Desinstalatzaile honek administratzaile baimenak behar ditu, saiatu berriro"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Desinstalatzailea dagoeneko martxan da."
|
||||
StrCpy $SectionGroup_Shortcuts "Lasterbideak"
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Show release notes"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
|
||||
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 $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar les notes de versió"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "S'ha trobat el(s) procés ${APPLICATION_EXECUTABLE} que s'ha d'aturar.$\nVoleu que l'instal·lador l'aturi?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "S'estan matant els processos ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Procés per matar no trobat!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Una versió anterior de ${APPLICATION_NAME} està instal·lada en el vostre sistema. Es recomana desinstal·lar la versió actual abans d'instal·lar. Seleccioneu l'operació que desitjeu realitzar i feu clic a Següent per continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstal·lar abans d'instal·lar"
|
||||
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.↩\nSeleccioneu l'operació que desitjeu realitzar 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}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolliu l'opció de manteniment per executar-ho."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instal·lant ${APPLICATION_NAME} essencial."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Accés directe del programa al menú d'inici"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Afegint la drecera per ${APPLICATION_NAME} al menú d'inici."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Drecera a l'escriptori"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creant les dreceres a l'escriptori"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Drecera d'inici ràpid"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creant la drecera per l'inici ràpid"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essencial."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Drecera ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Drecera a l'escrptori per ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Drecera d'inici ràpid per ${APPLICATION_NAME}."
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Esborra la carpeta de dades de ${APPLICATION_NAME} del vostre equip."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Voleu esborrar la carpeta de dades de ${APPLICATION_NAME}?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Deixeu-ho sense marcar per mantenir la carpeta de dades per un ús posterior o marqueu-ho per esborrar la carpeta de dades."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Sí, esborra la carpeta de dades."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Escrivint el desinstal·lador"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Escrivint les claus del registre de l'instal·lador"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Acabat"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "No sembla que ${APPLICATION_NAME} estigui instal·lat en la carpeta '$INSTDIR'.$\n$\nContinuo igualment (no recomanat)?"
|
||||
StrCpy $UNINSTALL_ABORT "La desinstal·lació s'ha cancel·lat."
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Drecera d'inici ràpid (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Drecera de l'escrpitori (sobreescriu l'existent)"
|
||||
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 $INIT_UNINSTALLER_RUNNING "El desinstal·lador ja s'està executant."
|
||||
StrCpy $SectionGroup_Shortcuts "Dreceres"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
|
||||
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 $PageReinstall_SAME_Field_2 "Add/Reinstall components"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Uninstall ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Uninstall ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menu Program Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Desktop Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creating Desktop Shortcuts"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Quick Launch Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creating Quick Launch Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} shortcut."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Desktop shortcut for ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Quick Launch shortcut for ${APPLICATION_NAME}."
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remove ${APPLICATION_NAME}'s data folder from your computer."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Do you want to delete ${APPLICATION_NAME}'s data folder?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Yes, delete this data folder."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Writing Uninstaller"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
|
||||
StrCpy $UNINSTALL_ABORT "Uninstall aborted by user"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Desktop Shortcut (overwrites existing)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "The installer is already running."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "This uninstaller requires admin access, try again"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "The uninstaller is already running."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Odinstalovat ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Odinstalovat ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Vyberte možnost údržby k provedení."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instalují se náležitosti ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Stavová ikona pro Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instaluji stavovou ikonu pro Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Zástupce v Nabídce Start"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Přidávám zástupce pro ${APPLICATION_NAME} do Nabídky Start."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Zástupce na ploše"
|
||||
|
||||
@@ -6,7 +6,7 @@ StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Het te stoppen proces is niet gev
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Er is een oudere versie van ${APPLICATION_NAME} geïnstalleerd op uw systeem. geadviseerd wordt om de huidige versie te de-installeren voordat de nieuwe versie wordt geïnstalleerd. Selecteer de uit te voeren actie en klik op Verder om door te gaan."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "De-installeren voor installeren"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Niet de-installeren"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Reeds geinstalleerd"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Al geïnstalleerd"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Kies hoe u ${APPLICATION_NAME} wilt installeren."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Er is al een recentere versie van ${APPLICATION_NAME} geïnstalleerd! Installeren van een oudere versie wordt niet aangeraden. Als u echt de oudere versie wilt installeren, adviseren we de huidige versie eerst te verwijderen. Kies de actie die u wilt uitvoeren en druk op Verder om door te gaan."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is al geïnstalleerd.\nKies de actie die u wilt uitvoeren en druk op Verder om door te gaan."
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "De-installeer ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "De-installeer ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Kies de uit te voeren onderhoudsoptie."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installeren ${APPLICATION_NAME} basis."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Statuspictogrammen voor Windows Verkenner"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installeren statuspictogrammen voor Windows Verkenner"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Startmenu snelkoppeling"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Toevoegen snelkoppeling voor ${APPLICATION_NAME} aan het Startmenu."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Werkblad snelkoppeling"
|
||||
@@ -27,7 +29,7 @@ StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Werkblad snelkoppeling voor ${APPLICATIO
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Snelstart snelkoppeling voor ${APPLICATION_NAME}."
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Verwijder ${APPLICATION_NAME}'s data map van uw computer."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Wilt u de ${APPLICATION_NAME}'s data map verwijderen?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Niet aankruisen om de datamap te bewaren of aankruisen om de datamap te verwijderen."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Niet aankruisen om de datamap te bewaren, wel aankruisen om de datamap te verwijderen."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Ja, verwijder deze data map."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Wegschrijven Uninstaller"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Wegschrijven installer Registersleutels"
|
||||
@@ -35,10 +37,10 @@ StrCpy $UNINSTALLER_FINISHED_Detail "Klaar"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Het lijkt er niet op dat ${APPLICATION_NAME} is geïnstalleerd in de map '$INSTDIR'.$\n$\nToch doorgaan (niet aangeraden)?"
|
||||
StrCpy $UNINSTALL_ABORT "De-installatie afgebroken door de gebruiker"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Snelstart snelkoppeling (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Desktop snelkoppeleng (overschrijft huidige)"
|
||||
StrCpy $INIT_NO_DESKTOP "Bureaublad snelkoppeling (overschrijft huidige)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Kan niet verhogen, fout:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Dit installatieprogramma vereist administrator rechten. Probeer het opnieuw"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Dit installatieprogramma vereist beheerdersrechten. Probeer het opnieuw"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "De Installer is al gestart."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Deze uninstaller vereist administrator toegang, probeer opnieuw"
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Deze uninstaller vereist Beheerderstoegang, probeer opnieuw"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "De uninstaller is al gestart."
|
||||
StrCpy $SectionGroup_Shortcuts "Snelkoppelingen"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Uninstall ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Uninstall ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menu Program Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Desktop Shortcut"
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "Paigaldaja on juba k
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "See desinstallija vajab admini ligipääsu, proovi uuesti"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "See desinstallija on juba käimas"
|
||||
StrCpy $SectionGroup_Shortcuts "Viidad"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -1,28 +1,39 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Näytä julkaisutiedot"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Havaittiin sovelluksen ${APPLICATION_EXECUTABLE} prosessi (tai prosesseja) jotka pitäisi pysäyttää.\nHaluatko että asennusohjelma pysäyttää nämä puolestasi?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Pysäytetään sovelluksen ${APPLICATION_EXECUTABLE} prosessit."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Tapettavaa prosessia ei löytynyt!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Vanhempi versio sovelluksesta ${APPLICATION_NAME} on jo asennettu. On suositeltavaa että poistat vanhan asennuksen ensin. Valitse mikä toiminto suoritetaan ja napsauta Seuraava jatkaaksesi."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Poista ennen asentamista"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Älä poista"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Asennettu jo"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Valitse miten ${APPLICATION_NAME} asennetaan."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Uudempi versio sovelluksesta ${APPLICATION_NAME} on jo asennettu! Vanhan version asennus ei ole suositeltavaa. Jos todella haluat asentaa vanhemman version, kannattaa poistaa nykyisen version asennus ensin. Valitse minkä toimenpiteen haluat suorittaa ja paina Seuraava jatkaaksesi."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} on jo asennettu.\nValitse suoritettava toimenpide ja napsauta Seuraava jatkaaksesi."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Lisää/uudelleenasenna komponentteja"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Poista ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Poista ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Valitse suoritettava huoltotoimenpide."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Asennetaan sovelluksen ${APPLICATION_NAME} välttämättömyyksiä."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Tilakuvakkeet Windows Explorerille"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Asennetaan tilakuvakkeet Windows Explorerille"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Käynnistä-valikon pikakuvake"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Lisätään ${APPLICATION_NAME}-pikakuvake Käynnistä-valikkoon."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Työpöydän pikakuvake"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Luodaan työpöydän pikakuvakkeet"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Pikakäynnistyksen pikakuvake"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Luodaan pikakuvaketta pikakäynnistykseen"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} välttämättömyydet."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME}-pikakuvake."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Sovelluksen ${APPLICATION_NAME} työpyötäpikakuvake."
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Pikakäynnistyksen pikakuvake sovellukselle ${APPLICATION_NAME}."
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Poista ${APPLICATION_NAME}-datakansio tietokoneelta."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Haluatko varmasti poistaa ${APPLICATION_NAME}-datakansion?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Jätä valinta ruksimatta säilyttääksesti datakansion myöhempää käyttöä varten tai täytä ruksi jos haluat poistaa datakansion ja siinä olevat tiedostot."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Kyllä, poista tämä datakansio."
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Kirjoitetaan asennusohjelman rekisteriavaimia"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Valmis"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Vaikuttaa siltä että sovellus ${APPLICATION_NAME} on asennettu kansioon '$INSTDIR'.\n\nHaluatko jatkaa tästä huolimatta (ei suositeltavaa)?"
|
||||
StrCpy $UNINSTALL_ABORT "Poistaminen keskeytettiin käyttäjän toimesta"
|
||||
StrCpy $INIT_NO_DESKTOP "Työpöydän pikakuvake (korvaa nykyinen)"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Tämä asennusohjelma vaatii ylläpitäjän oikeudet, yritä uudelleen."
|
||||
@@ -30,15 +41,6 @@ StrCpy $INIT_INSTALLER_RUNNING "Asennusohjelma on jo k
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Tämä poisto-ohjelma vaatii ylläpitäjän oikeudet, yritä uudelleen."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Poisto-ohjelma on jo käynnissä."
|
||||
StrCpy $SectionGroup_Shortcuts "Pikakuvakkeet"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Add/Reinstall components"
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Writing Uninstaller"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "Une installation est déjà en cours."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Ce désinstallateur requiert les droits administrateur, essayez à nouveau"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Une désinstallation est déjà en cours."
|
||||
StrCpy $SectionGroup_Shortcuts "Raccourcis"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolla a opción de mantemento a realizar."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instalando ${APPLICATION_NAME} esenciais."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Iconas de estado para Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instalando as iconas de estado para Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso directo ao programa no menú de inicio"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Engadindo o acceso directo ao ${APPLICATION_NAME} no menú de inicio"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Acceso directo no escritorio"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} entfernen"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} entfernen"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Wählen Sie zur Ausführung die Wartungsoption."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installiere ${APPLICATION_NAME} Basis."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status-Icons für den Windows-Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installiere Status-Icons für den Windows-Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Installiere Verknüpfung im Programmmenü"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Füge Verknüpfung für ${APPLICATION_NAME} dem Startmenü hinzu."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Desktop-Verknüpfung"
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Αυτή η εφαρμογή απεγκατάστασης απαιτεί πρόσβαση διαχειριστή, δοκιμάστε ξανά"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Η εφαρμογή απεγκατάστασης λειτουργεί ήδη."
|
||||
StrCpy $SectionGroup_Shortcuts "Συντομεύσεις"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -9,6 +9,13 @@ StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} eltávolítása"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} eltávolítása"
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Igen, törölje ezt az adatkönyvtárat."
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Befejezve"
|
||||
StrCpy $UNINSTALL_ABORT "Az eltávolítást egy felhasználó megszakította"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Gyorsindító Hivatkozás (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Asztali Hivatkozás (felülírja a meglévőt)"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "A telepítő futtatásához adminisztrátori hozzáférés szükséges, próbáld újra."
|
||||
StrCpy $INIT_INSTALLER_RUNNING "A telepítő már fut."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Az eltávolító futtatásához adminisztrátori hozzáférés szükséges, próbáld újra."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Az eltávolító már fut."
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Process to kill not found!"
|
||||
@@ -17,6 +24,8 @@ StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is alr
|
||||
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 $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menu Program Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Desktop Shortcut"
|
||||
@@ -33,12 +42,5 @@ StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Writing Uninstaller"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
|
||||
StrCpy $UNINSTALL_ABORT "Uninstall aborted by user"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Desktop Shortcut (overwrites existing)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "The installer is already running."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "This uninstaller requires admin access, try again"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "The uninstaller is already running."
|
||||
StrCpy $SectionGroup_Shortcuts "Shortcuts"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Disinstalla ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Disinstalla ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Scegli l'opzione di manutenzione da eseguire."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installazione degli elementi fondamentali di ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Icone di stato per Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installazione delle icone di stato per Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Scorciatoia di programma menu Start"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Aggiunta della scorciatoia per ${APPLICATION_NAME} al menu Start."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Scorciatoia del desktop"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME}
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} をアンインストール"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "実行するには、メンテナンスオプションを選択してください。"
|
||||
StrCpy $SEC_APPLICATION_DETAILS "${APPLICATION_NAME} の重要なパッケージをインストール中"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Windowsエクスプローラの状態アイコン"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Windowsエクスプローラの状態アイコンをインストール中"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "スタートメニューショートカット"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "スタートメニューに${APPLICATION_NAME} のショートカットの追加"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "デスクトップショートカット"
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "Instalator już jest uruchomiony."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Ten dezinstalator potrzebuje uprawnień administratora, spróbuj ponownie"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Dezinstalator już jest uruchomiony."
|
||||
StrCpy $SectionGroup_Shortcuts "Skróty"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolha a opção de manutenção a fazer."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "A instalar o essencial de ${APPLICATION_NAME}."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Icons de estado para Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "A instalar icons de estado para Windows Explorer"
|
||||
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"
|
||||
|
||||
@@ -6,7 +6,7 @@ StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Processo para eliminar n
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Uma versão mais antiga de ${APPLICATION_NAME} está instalado em seu sistema. É recomendado que você desinstale a versão atual antes de instalar. Selecione a operação que deseja executar e clique em Avançar 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"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Já Instalado"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Escolha como você deseja instalar ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "A versão mais recente do ${APPLICATION_NAME} já está instalado! Não é recomendado que você instale uma versão mais antiga. Se você realmente deseja instalar esta versão mais antiga, é melhor desinstalar a versão atual primeiro. Selecione a operação que deseja executar e clique em Avançar para continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${version} já está instalado. \nSelecione a operação que deseja executar e clique em Avançar para continuar."
|
||||
@@ -15,8 +15,10 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolha a opção de realizar manutenção."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instalando ${APPLICATION_NAME} fundamentos."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Ícones de status para Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instalando os ícones de status para o Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Menu Iniciar Programa Atalho"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adicionando atalho para ${APPLICATION_NAME} para o Menu Iniciar."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adicionando atalho para ${APPLICATION_NAME} ao Menu Iniciar."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Atalho Desktop"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Criando Atalhos de Desktop"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Atalho Rápido"
|
||||
@@ -29,13 +31,13 @@ StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remover ${APPLICATION_NAME} pasta de dado
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Você quer apagar ${APPLICATION_NAME} 's pasta de dados?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Deixe desmarcada para manter a pasta de dados para uso posterior ou cheque para excluir a pasta de dados."
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Sim, excluir essa pasta de dados."
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Escrevendo Desinstalador"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Escrevendo Chaves de Registro do Inslalador"
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Gravando Desinstalador"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Gravando Chaves de Registro do Inslalador"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Finalizado"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Não parece que ${APPLICATION_NAME} está instalado no diretório '$INSTDIR'.$\n$\nContinuar assim mesmo (não recomendado)?"
|
||||
StrCpy $UNINSTALL_ABORT "Desinstalação abortada pelo usuário"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Atalho de Inicialização Rápida (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Atalho Desktop (substituições existente)"
|
||||
StrCpy $INIT_NO_DESKTOP "Atalho Desktop (substitui os existente)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Incapaz de elevar, erro:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este programa de instalação requer acesso de administrador, tente novamente"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "O instalador já está em execução."
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "Установщик уже запущен."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Этот деинсталятор требует права администратора, попытайтесь ещё"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Программа удаления уже выполняется."
|
||||
StrCpy $SectionGroup_Shortcuts "Ярлыки"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Auto-generated - do not modify
|
||||
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 "未找到要杀死的进程!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "您的系统已经安装${APPLICATION_NAME}较老版本。建议安装前卸载当前版本。选择将要执行的操作,点击下一步继续。"
|
||||
@@ -7,11 +8,15 @@ StrCpy $PageReinstall_NEW_Field_2 "在安装前先卸载"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "不要卸载"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "已经安装"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "选择如何安装${APPLICATION_NAME}。"
|
||||
StrCpy $PageReinstall_SAME_Field_2 "添加/重装组件"
|
||||
StrCpy $PageReinstall_OLD_Field_1 "较新版本的 ${APPLICATION_NAME} 已经安装!安装较旧版本的程序是不推荐的。如果您希望继续安装较旧版本,建议先卸载较新版本。选择您想要执行的操作并点击下一步以继续。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} 已经安装。\n请选择想要执行的操作并点击下一步。"
|
||||
StrCpy $PageReinstall_SAME_Field_2 "增加/重装组件"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "卸载${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "卸载${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "选择需要执行的维护选项。"
|
||||
StrCpy $SEC_APPLICATION_DETAILS "安装${APPLICATION_NAME}基本组件。"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "开始菜单程序快捷方式"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "添加 ${APPLICATION_NAME} 快捷方式到开始菜单。"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "桌面快捷方式"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "创建桌面快捷方式"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "快速启动栏快捷方式"
|
||||
@@ -20,25 +25,22 @@ StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME}基本组件。"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME}快捷方式。"
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "${APPLICATION_NAME}桌面快捷方式。"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "${APPLICATION_NAME}快速启动栏快捷方式。"
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "从电脑中移除 ${APPLICATION_NAME} 数据文件夹。"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "移除 ${APPLICATION_NAME} 数据文件夹?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "选择以删除数据文件夹,不选择以保留数据文件夹内容供后续使用。"
|
||||
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "删除数据文件。"
|
||||
StrCpy $UNINSTALLER_FILE_Detail "覆盖卸载器"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "正在写入注册表"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "完成"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "${APPLICATION_NAME} 可能并没有安装在 $INSTDIR。$\n$\n仍然继续吗?(不推荐)"
|
||||
StrCpy $UNINSTALL_ABORT "用户取消了卸载"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "快速启动栏快捷方式(N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "桌面快捷方式(覆盖)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "无法获得权限,错误:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "安装程序需要管理员权限,请重试"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "安装程序已经运行。"
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "卸载程序需要管理员权限,请重试"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "卸载程序已经运行。"
|
||||
StrCpy $SectionGroup_Shortcuts "快捷方式"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
|
||||
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 $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
|
||||
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remove ${APPLICATION_NAME}'s data folder from your computer."
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Do you want to delete ${APPLICATION_NAME}'s data folder?"
|
||||
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
|
||||
StrCpy $UNINSTALL_ABORT "Uninstall aborted by user"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "The installer is already running."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "This uninstaller requires admin access, try again"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "The uninstaller is already running."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -3,7 +3,7 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Zobrazi
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Našli sa ${APPLICATION_EXECUTABLE} proces (y), ktoré je potrebné zastavi<76>.$\nChcete, aby ich inštalátor zastavil?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Ukonèujem ${APPLICATION_EXECUTABLE} procesy."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Proces ukonèenia nebol nájdený!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Staršia verzia ${APPLICATION_NAME} je nainštalovaná vo vašom systéme. Odporúèam vám odinštalova<76> aktuálnu verziu pred inštaláciou. Vyberte operáciu, ktorú chcete vykona<6E>, a kliknite na tlaèidlo Ïalej pre pokraèovanie."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Staršia verzia ${APPLICATION_NAME} je nainštalovaná vo vašom poèítaèi. Odporúèam vám odinštalova<76> aktuálnu verziu pred inštaláciou. Vyberte operáciu, ktorú chcete vykona<6E>, a kliknite na tlaèidlo Ïalej pre pokraèovanie."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Odinštalova<EFBFBD> pred inštaláciou"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Neodinštalova<EFBFBD>"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Už je nainštalovaný"
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "In
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Tento odinštalátor vyžaduje admin prístup, skúste to znova"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Odinštalátor je už spustený."
|
||||
StrCpy $SectionGroup_Shortcuts "Zástupcovia"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "Namestilnik je
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Program za odstranjevanje namestitve zahteva skrbniška dovoljenja."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Program za odstranjevanje namestitve je že zagnan."
|
||||
StrCpy $SectionGroup_Shortcuts "Bližnjice"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Elija la opcion de mantenimiento a realizar."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instalando ${APPLICATION_NAME} esenciales."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Íconos de estado para el Explorador de Windows"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instalando íconos de estado para el Explorador de Windows"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso Directo al Programa Menú de Inicio"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Añadiendo accesos directos para ${APPLICATION_NAME} en el Menú de Inicio."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Acceso directo de Escritorio"
|
||||
|
||||
@@ -35,6 +35,8 @@ StrCpy $INIT_UNINSTALLER_RUNNING "El des-instalador ya esta corriendo"
|
||||
StrCpy $SectionGroup_Shortcuts "Accesos Directos"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
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 $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Quick Launch Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creating Quick Launch Shortcut"
|
||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
|
||||
|
||||
@@ -42,3 +42,5 @@ StrCpy $INIT_INSTALLER_RUNNING "Installationsprogrammet körs redan."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Detta avinstallationsprogram kräver administratörs rättigheter, försök igen"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallationsprogrammet körs redan."
|
||||
StrCpy $SectionGroup_Shortcuts "Genvägar"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Status icons for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing status icons for Windows Explorer"
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} uygulamas
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} uygulamasını kaldır"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Yapmak istediğiniz bakım işlemini seçin."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "${APPLICATION_NAME} gereklilikleri yükleniyor."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Windows Gezgini için durum simgeleri"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Windows Gezgini için durum simgeleri yükleniyor"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Başlat Menüsü Program Kısayolu"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "${APPLICATION_NAME} için Başlat Menüsü'ne kısayol ekleniyor."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Masaüstü Kısayolu"
|
||||
|
||||
@@ -15,6 +15,8 @@ Var PageReinstall_SAME_Field_3
|
||||
Var UNINSTALLER_APPDATA_TITLE
|
||||
Var PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE
|
||||
Var SEC_APPLICATION_DETAILS
|
||||
Var OPTION_SECTION_SC_SHELL_EXT_SECTION
|
||||
Var OPTION_SECTION_SC_SHELL_EXT_DetailPrint
|
||||
Var OPTION_SECTION_SC_START_MENU_SECTION
|
||||
Var OPTION_SECTION_SC_START_MENU_DetailPrint
|
||||
Var OPTION_SECTION_SC_DESKTOP_SECTION
|
||||
|
||||
@@ -85,6 +85,14 @@ msgstr "Choose the maintenance option to perform."
|
||||
msgid "Installing ${APPLICATION_NAME} essentials."
|
||||
msgstr "Installing ${APPLICATION_NAME} essentials."
|
||||
|
||||
#. OPTION_SECTION_SC_SHELL_EXT_SECTION
|
||||
msgid "Status icons for Windows Explorer"
|
||||
msgstr "Status icons for Windows Explorer"
|
||||
|
||||
#. OPTION_SECTION_SC_SHELL_EXT_DetailPrint
|
||||
msgid "Installing status icons for Windows Explorer"
|
||||
msgstr "Installing status icons for Windows Explorer"
|
||||
|
||||
#. OPTION_SECTION_SC_START_MENU_SECTION
|
||||
msgid "Start Menu Program Shortcut"
|
||||
msgstr "Start Menu Program Shortcut"
|
||||
|
||||
1
binary
Submodule
1
binary
Submodule
Submodule binary added at 1645f4df2f
@@ -13,7 +13,7 @@ if (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)")
|
||||
if (NOT CSYNC_STATIC_COMPILE_DIR)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -pedantic-errors")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute -D_GNU_SOURCE")
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
!define OPTION_LICENSE_AGREEMENT
|
||||
!endif
|
||||
!define OPTION_UAC_PLUGIN_ENHANCED
|
||||
!define OPTION_SECTION_SC_SHELL_EXT
|
||||
!define OPTION_SECTION_SC_START_MENU
|
||||
!define OPTION_SECTION_SC_DESKTOP
|
||||
!define OPTION_SECTION_SC_QUICK_LAUNCH
|
||||
@@ -94,6 +95,7 @@ ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
|
||||
!include WordFunc.nsh ;Used by VersionCompare macro function.
|
||||
!include FileFunc.nsh ;Used to read out parameters
|
||||
!include UAC.nsh ;Used by the UAC elevation to install as user or admin.
|
||||
!include x64.nsh ;Used to determine the right arch for the shell extensions
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Memento selections stored in registry.
|
||||
@@ -111,8 +113,8 @@ ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_BITMAP ${WIN_SETUP_BITMAP_PATH}/page_header.bmp
|
||||
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||
!define MUI_FINISHPAGE_LINK "www.${APPLICATION_DOMAIN}"
|
||||
!define MUI_FINISHPAGE_LINK_LOCATION "http://www.${APPLICATION_DOMAIN}"
|
||||
!define MUI_FINISHPAGE_LINK "${APPLICATION_DOMAIN}"
|
||||
!define MUI_FINISHPAGE_LINK_LOCATION "http://${APPLICATION_DOMAIN}"
|
||||
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
|
||||
!ifdef OPTION_FINISHPAGE_RELEASE_NOTES
|
||||
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
|
||||
@@ -275,10 +277,60 @@ FunctionEnd
|
||||
no_process_${processName}_to_end:
|
||||
!macroend
|
||||
|
||||
!macro StartExplorerAsUserMacro un
|
||||
Function ${un}StartExplorerAsUser
|
||||
Exec "$WINDIR\explorer.exe"
|
||||
FunctionEnd
|
||||
!macroend
|
||||
|
||||
!insertmacro StartExplorerAsUserMacro ""
|
||||
!insertmacro StartExplorerAsUserMacro "un."
|
||||
|
||||
!macro StartExplorer un
|
||||
DetailPrint "Starting Explorer..."
|
||||
${UAC.CallFunctionAsUser} ${un}StartExplorerAsUser
|
||||
!macroend
|
||||
|
||||
!macro StopExplorer
|
||||
DetailPrint "Terminated Explorer..."
|
||||
FindWindow $R0 "Shell_TrayWnd"
|
||||
SendMessage $R0 0x5B4 0 0
|
||||
#Processes::KillProcess explorer.exe
|
||||
Sleep 1500
|
||||
DetailPrint "Continuing..."
|
||||
!macroend
|
||||
|
||||
Function EnsureOwncloudShutdown
|
||||
!insertmacro CheckAndConfirmEndProcess "${APPLICATION_EXECUTABLE}"
|
||||
FunctionEnd
|
||||
|
||||
Function RegisterShellExt
|
||||
SetOutPath "$INSTDIR\shellext"
|
||||
${If} ${RunningX64}
|
||||
ExecWait '"$SYSDIR\regsvr32.exe" /s "$OUTDIR\OCOverlays_x64.dll"'
|
||||
${Else}
|
||||
ExecWait '"$SYSDIR\regsvr32.exe" /s "$OUTDIR\OCOverlays_x86.dll"'
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function Un.RegisterShellExt
|
||||
${If} ${RunningX64}
|
||||
ExecWait '"$SYSDIR\regsvr32.exe" /u /s "$INSTDIR\shellext\OCOverlays_x64.dll"'
|
||||
${Else}
|
||||
ExecWait '"$SYSDIR\regsvr32.exe" /u /s "$INSTDIR\shellext\OCOverlays_x86.dll"'
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function InstallRedistributables
|
||||
${If} ${RunningX64}
|
||||
ExecWait '"$OUTDIR\vcredist_x64.exe" /install /quiet'
|
||||
${Else}
|
||||
ExecWait '"$OUTDIR\vcredist_x86.exe" /install /quiet'
|
||||
${EndIf}
|
||||
Delete "$OUTDIR\vcredist_x86.exe"
|
||||
Delete "$OUTDIR\vcredist_x64.exe"
|
||||
FunctionEnd
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# RE-INSTALLER FUNCTIONS #
|
||||
@@ -370,10 +422,10 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
;Main executable & csync
|
||||
File "${BUILD_PATH}\bin\${APPLICATION_EXECUTABLE}"
|
||||
File "${BUILD_PATH}\bin\${APPLICATION_CMD_EXECUTABLE}"
|
||||
File "${BUILD_PATH}\bin\socketapiclient.exe"
|
||||
File "${BUILD_PATH}\src\lib${APPLICATION_SHORTNAME}sync.dll"
|
||||
File "${BUILD_PATH}\csync\src\libocsync.dll"
|
||||
|
||||
|
||||
File "${BUILD_PATH}\src\mirall_*.qm"
|
||||
; Make sure only to copy qt, not qt_help, etc
|
||||
File "${MING_SHARE}\qt5\translations\qt_??.qm"
|
||||
@@ -414,15 +466,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\icudata51.dll"
|
||||
File "${MING_BIN}\icui18n51.dll"
|
||||
File "${MING_BIN}\icuuc51.dll"
|
||||
File "${MING_BIN}\icudata53.dll"
|
||||
File "${MING_BIN}\icui18n53.dll"
|
||||
File "${MING_BIN}\icuuc53.dll"
|
||||
File "${MING_BIN}\libEGL.dll"
|
||||
File "${MING_BIN}\libGLESv2.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
File "${MING_BIN}\libpcre16-0.dll"
|
||||
File "${MING_BIN}\libproxy.dll"
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
File "${MING_BIN}\libcrypto-10.dll"
|
||||
File "${MING_BIN}\libssl-10.dll"
|
||||
@@ -435,9 +486,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
|
||||
;QtKeyChain stuff
|
||||
File "${MING_BIN}\libqtkeychain.dll"
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
|
||||
; ownCloud plugin
|
||||
;ownCloud plugin
|
||||
File "${MING_BIN}\libintl-8.dll"
|
||||
File "${MING_BIN}\libneon-27.dll"
|
||||
File "${MING_BIN}\libproxy.dll"
|
||||
@@ -449,11 +500,30 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwinpthread-1.dll"
|
||||
|
||||
; CSync configs
|
||||
;CSync configs
|
||||
File "${SOURCE_PATH}/sync-exclude.lst"
|
||||
|
||||
SectionEnd
|
||||
|
||||
!ifdef OPTION_SECTION_SC_SHELL_EXT
|
||||
${MementoSection} $OPTION_SECTION_SC_SHELL_EXT_SECTION SEC_SHELL_EXT
|
||||
SectionIn 1 2
|
||||
SetDetailsPrint textonly
|
||||
DetailPrint $OPTION_SECTION_SC_SHELL_EXT_DetailPrint
|
||||
SetOutPath "$INSTDIR\shellext"
|
||||
File "${SOURCE_PATH}\binary\shell_integration\windows\Release\x64\OCUtil_x64.dll"
|
||||
File "${SOURCE_PATH}\binary\shell_integration\windows\Release\x64\OCOverlays_x64.dll"
|
||||
File "${SOURCE_PATH}\binary\shell_integration\windows\Release\Win32\OCUtil_x86.dll"
|
||||
File "${SOURCE_PATH}\binary\shell_integration\windows\Release\Win32\OCOverlays_x86.dll"
|
||||
File "${BUILD_PATH}\vcredist_x86.exe"
|
||||
File "${BUILD_PATH}\vcredist_x64.exe"
|
||||
Call InstallRedistributables
|
||||
Call RegisterShellExt
|
||||
!insertMacro StopExplorer
|
||||
!insertMacro StartExplorer ""
|
||||
${MementoSectionEnd}
|
||||
!endif
|
||||
|
||||
SectionGroup $SectionGroup_Shortcuts
|
||||
|
||||
!ifdef OPTION_SECTION_SC_START_MENU
|
||||
@@ -601,6 +671,15 @@ Section Uninstall
|
||||
|
||||
DeleteRegKey HKCR "${APPLICATION_NAME}"
|
||||
|
||||
;Shell extension
|
||||
!ifdef OPTION_SECTION_SC_SHELL_EXT
|
||||
${If} ${HasSection} SEC_SHELL_EXT
|
||||
!insertmacro StopExplorer
|
||||
Call Un.RegisterShellExt
|
||||
!insertmacro StartExplorer "Un."
|
||||
${EndIf}
|
||||
!endif
|
||||
|
||||
;Start menu shortcut
|
||||
!ifdef OPTION_SECTION_SC_START_MENU
|
||||
SetShellVarContext all
|
||||
|
||||
@@ -19,10 +19,11 @@ if( Qt5Core_FOUND )
|
||||
find_package(Qt5PrintSupport REQUIRED)
|
||||
find_package(Qt5Quick REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
if(APPLE)
|
||||
find_package(Qt5MacExtras REQUIRED)
|
||||
endif(APPLE)
|
||||
endif()
|
||||
if(APPLE)
|
||||
find_package(Qt5MacExtras REQUIRED)
|
||||
endif(APPLE)
|
||||
|
||||
else( Qt5Core_FOUND )
|
||||
if(WIN32 OR APPLE)
|
||||
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
|
||||
@@ -147,6 +148,8 @@ if(NOT Qt5Core_FOUND)
|
||||
|
||||
include( ${QT_USE_FILE} )
|
||||
endmacro()
|
||||
|
||||
add_definitions("-DQ_DECL_OVERRIDE=override")
|
||||
endif()
|
||||
|
||||
if( Qt5Core_DIR )
|
||||
|
||||
@@ -6,9 +6,11 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
|
||||
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif(CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
# TODO: handle msvc compilers warnings?
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@ include(MacroCopyFile)
|
||||
if (NOT WIN32)
|
||||
find_package(Iconv)
|
||||
endif (NOT WIN32)
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
include(AddCMockaTest)
|
||||
endif (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
|
||||
include(ConfigureChecks.cmake)
|
||||
|
||||
@@ -47,9 +43,13 @@ endif (MEM_NULL_TESTS)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
if (UNIT_TESTING)
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
include(AddCMockaTest)
|
||||
add_subdirectory(tests)
|
||||
endif (CMOCKA_FOUND)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h)
|
||||
configure_file(config_test.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_test.h)
|
||||
|
||||
@@ -96,10 +96,10 @@ include_directories(
|
||||
)
|
||||
|
||||
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
|
||||
add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
|
||||
#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
|
||||
|
||||
target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES})
|
||||
target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
|
||||
#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${CSYNC_LIBRARY}
|
||||
|
||||
@@ -96,8 +96,6 @@ static int _data_cmp(const void *key, const void *data) {
|
||||
int csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
CSYNC *ctx;
|
||||
size_t len = 0;
|
||||
char *home;
|
||||
int rc;
|
||||
|
||||
ctx = c_malloc(sizeof(CSYNC));
|
||||
if (ctx == NULL) {
|
||||
@@ -129,31 +127,6 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
ctx->options.local_only_mode = false;
|
||||
|
||||
ctx->pwd.uid = getuid();
|
||||
ctx->pwd.euid = geteuid();
|
||||
|
||||
home = csync_get_user_home_dir();
|
||||
if (home == NULL) {
|
||||
SAFE_FREE(ctx->local.uri);
|
||||
SAFE_FREE(ctx->remote.uri);
|
||||
SAFE_FREE(ctx);
|
||||
errno = ENOMEM;
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = asprintf(&ctx->options.config_dir, "%s/%s", home, CSYNC_CONF_DIR);
|
||||
SAFE_FREE(home);
|
||||
if (rc < 0) {
|
||||
SAFE_FREE(ctx->local.uri);
|
||||
SAFE_FREE(ctx->remote.uri);
|
||||
SAFE_FREE(ctx);
|
||||
errno = ENOMEM;
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->local.list = 0;
|
||||
ctx->remote.list = 0;
|
||||
@@ -167,7 +140,6 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
|
||||
int csync_init(CSYNC *ctx) {
|
||||
int rc;
|
||||
char *config = NULL;
|
||||
|
||||
if (ctx == NULL) {
|
||||
errno = EBADF;
|
||||
@@ -190,12 +162,8 @@ int csync_init(CSYNC *ctx) {
|
||||
|
||||
ctx->local.type = LOCAL_REPLICA;
|
||||
|
||||
if ( !ctx->options.local_only_mode) {
|
||||
owncloud_init(csync_get_userdata(ctx));
|
||||
ctx->remote.type = REMOTE_REPLICA;
|
||||
} else {
|
||||
ctx->remote.type = LOCAL_REPLICA;
|
||||
}
|
||||
owncloud_init(ctx);
|
||||
ctx->remote.type = REMOTE_REPLICA;
|
||||
|
||||
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
@@ -211,15 +179,12 @@ int csync_init(CSYNC *ctx) {
|
||||
|
||||
ctx->status = CSYNC_STATUS_INIT;
|
||||
|
||||
csync_set_module_property(ctx, "csync_context", ctx);
|
||||
|
||||
/* initialize random generator */
|
||||
srand(time(NULL));
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
SAFE_FREE(config);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -234,7 +199,6 @@ int csync_update(CSYNC *ctx) {
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
/* create/load statedb */
|
||||
if (! csync_is_statedb_disabled(ctx)) {
|
||||
rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
|
||||
ctx->local.uri);
|
||||
if (rc < 0) {
|
||||
@@ -248,7 +212,6 @@ int csync_update(CSYNC *ctx) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
@@ -278,27 +241,25 @@ int csync_update(CSYNC *ctx) {
|
||||
csync_memstat_check();
|
||||
|
||||
/* update detection for remote replica */
|
||||
if( ! ctx->options.local_only_mode ) {
|
||||
csync_gettime(&start);
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
csync_gettime(&start);
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
|
||||
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK)
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Update detection for remote replica took %.2f seconds "
|
||||
"walking %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
|
||||
csync_memstat_check();
|
||||
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK)
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Update detection for remote replica took %.2f seconds "
|
||||
"walking %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
|
||||
csync_memstat_check();
|
||||
|
||||
ctx->status |= CSYNC_STATUS_UPDATE;
|
||||
|
||||
return 0;
|
||||
@@ -431,14 +392,15 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||
trav.path = cur->path;
|
||||
trav.size = cur->size;
|
||||
trav.modtime = cur->modtime;
|
||||
trav.uid = cur->uid;
|
||||
trav.gid = cur->gid;
|
||||
trav.mode = cur->mode;
|
||||
trav.type = cur->type;
|
||||
trav.instruction = cur->instruction;
|
||||
trav.rename_path = cur->destpath;
|
||||
trav.etag = cur->etag;
|
||||
trav.file_id = cur->file_id;
|
||||
trav.remotePerm = cur->remotePerm;
|
||||
trav.directDownloadUrl = cur->directDownloadUrl;
|
||||
trav.directDownloadCookies = cur->directDownloadCookies;
|
||||
trav.inode = cur->inode;
|
||||
|
||||
trav.error_status = cur->error_status;
|
||||
@@ -461,7 +423,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||
|
||||
rc = (*visitor)(&trav, twctx->userdata);
|
||||
cur->instruction = trav.instruction;
|
||||
if (trav.etag != cur->etag) {
|
||||
if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
|
||||
SAFE_FREE(cur->etag);
|
||||
cur->etag = c_strdup(trav.etag);
|
||||
}
|
||||
@@ -612,7 +574,7 @@ int csync_commit(CSYNC *ctx) {
|
||||
}
|
||||
ctx->statedb.db = NULL;
|
||||
|
||||
rc = csync_vio_commit(ctx);
|
||||
rc = owncloud_commit(ctx);
|
||||
if (rc < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "commit failed: %s",
|
||||
ctx->error_string ? ctx->error_string : "");
|
||||
@@ -671,9 +633,10 @@ int csync_destroy(CSYNC *ctx) {
|
||||
|
||||
SAFE_FREE(ctx->local.uri);
|
||||
SAFE_FREE(ctx->remote.uri);
|
||||
SAFE_FREE(ctx->options.config_dir);
|
||||
SAFE_FREE(ctx->error_string);
|
||||
|
||||
owncloud_destroy(ctx);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
c_close_iconv();
|
||||
#endif
|
||||
@@ -705,70 +668,6 @@ void csync_clear_exclude_list(CSYNC *ctx)
|
||||
csync_exclude_clear(ctx);
|
||||
}
|
||||
|
||||
const char *csync_get_config_dir(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx->options.config_dir;
|
||||
}
|
||||
|
||||
int csync_set_config_dir(CSYNC *ctx, const char *path) {
|
||||
if (ctx == NULL || path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SAFE_FREE(ctx->options.config_dir);
|
||||
ctx->options.config_dir = c_strdup(path);
|
||||
if (ctx->options.config_dir == NULL) {
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_enable_statedb(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
if (ctx->status & CSYNC_STATUS_INIT) {
|
||||
fprintf(stderr, "This function must be called before initialization.");
|
||||
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->statedb.disabled = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_disable_statedb(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
if (ctx->status & CSYNC_STATUS_INIT) {
|
||||
fprintf(stderr, "This function must be called before initialization.");
|
||||
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->statedb.disabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_is_statedb_disabled(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return ctx->statedb.disabled;
|
||||
}
|
||||
|
||||
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
|
||||
if (ctx == NULL || cb == NULL) {
|
||||
return -1;
|
||||
@@ -784,15 +683,6 @@ int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *csync_get_statedb_file(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
return c_strdup(ctx->statedb.file);
|
||||
}
|
||||
|
||||
void *csync_get_userdata(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
@@ -836,33 +726,6 @@ CSYNC_STATUS csync_get_status(CSYNC *ctx) {
|
||||
return ctx->status_code;
|
||||
}
|
||||
|
||||
int csync_set_local_only(CSYNC *ctx, bool local_only) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
if (ctx->status & CSYNC_STATUS_INIT) {
|
||||
fprintf(stderr, "csync_set_local_only: This function must be called before initialization.");
|
||||
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->options.local_only_mode=local_only;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool csync_get_local_only(CSYNC *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
return ctx->options.local_only_mode;
|
||||
}
|
||||
|
||||
const char *csync_get_status_string(CSYNC *ctx)
|
||||
{
|
||||
return csync_vio_get_status_string(ctx);
|
||||
@@ -907,6 +770,8 @@ int csync_abort_requested(CSYNC *ctx)
|
||||
void csync_file_stat_free(csync_file_stat_t *st)
|
||||
{
|
||||
if (st) {
|
||||
SAFE_FREE(st->directDownloadUrl);
|
||||
SAFE_FREE(st->directDownloadCookies);
|
||||
SAFE_FREE(st->etag);
|
||||
SAFE_FREE(st->destpath);
|
||||
SAFE_FREE(st);
|
||||
@@ -915,7 +780,7 @@ void csync_file_stat_free(csync_file_stat_t *st)
|
||||
|
||||
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
|
||||
{
|
||||
return csync_vio_set_property(ctx, key, value);
|
||||
return owncloud_set_property(ctx, key, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -44,13 +44,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* csync file declarations
|
||||
*/
|
||||
#define CSYNC_CONF_DIR ".ocsync"
|
||||
#define CSYNC_CONF_FILE "ocsync.conf"
|
||||
#define CSYNC_EXCLUDE_FILE "ocsync_exclude.conf"
|
||||
|
||||
/**
|
||||
* Instruction enum. In the file traversal structure, it describes
|
||||
* the csync state of a file.
|
||||
@@ -59,7 +52,7 @@ enum csync_status_codes_e {
|
||||
CSYNC_STATUS_OK = 0,
|
||||
|
||||
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
|
||||
just use in csync_status_ok */
|
||||
*/
|
||||
CSYNC_STATUS_UNSUCCESSFUL,
|
||||
CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */
|
||||
CSYNC_STATUS_STATEDB_LOAD_ERROR,
|
||||
@@ -172,13 +165,6 @@ struct csync_tree_walk_file_s {
|
||||
int64_t size;
|
||||
int64_t inode;
|
||||
time_t modtime;
|
||||
#ifdef _WIN32
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
#else
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
#endif
|
||||
mode_t mode;
|
||||
enum csync_ftw_type_e type;
|
||||
enum csync_instructions_e instruction;
|
||||
@@ -189,6 +175,9 @@ struct csync_tree_walk_file_s {
|
||||
const char *rename_path;
|
||||
const char *etag;
|
||||
const char *file_id;
|
||||
const char *remotePerm;
|
||||
char *directDownloadUrl;
|
||||
char *directDownloadCookies;
|
||||
struct {
|
||||
int64_t size;
|
||||
time_t modtime;
|
||||
@@ -214,14 +203,6 @@ typedef void (*csync_log_callback) (int verbosity,
|
||||
const char *buffer,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Check internal csync status.
|
||||
*
|
||||
* @param csync The context to check.
|
||||
*
|
||||
* @return true if status is error free, false for error states.
|
||||
*/
|
||||
bool csync_status_ok(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Allocate a csync context.
|
||||
@@ -333,62 +314,6 @@ int csync_add_exclude_list(CSYNC *ctx, const char *path);
|
||||
*/
|
||||
void csync_clear_exclude_list(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the config directory.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return The path of the config directory or NULL on error.
|
||||
*/
|
||||
const char *csync_get_config_dir(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Change the config directory.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @param path The path to the new config directory.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_set_config_dir(CSYNC *ctx, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Remove the complete config directory.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_remove_config_dir(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Enable the usage of the statedb. It is enabled by default.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_enable_statedb(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Disable the usage of the statedb. It is enabled by default.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_disable_statedb(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Check if the statedb usage is enabled.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 1 if it is enabled, 0 if it is disabled.
|
||||
*/
|
||||
int csync_is_statedb_disabled(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the userdata saved in the context.
|
||||
*
|
||||
@@ -481,31 +406,6 @@ void *csync_get_log_userdata(void);
|
||||
*/
|
||||
int csync_set_log_userdata(void *data);
|
||||
|
||||
/**
|
||||
* @brief Get the path of the statedb file used.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return The path to the statedb file, NULL if an error occured.
|
||||
*/
|
||||
const char *csync_get_statedb_file(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Flag to tell csync that only a local run is intended. Call before csync_init
|
||||
*
|
||||
* @param local_only Bool flag to indicate local only mode.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_set_local_only( CSYNC *ctx, bool local_only );
|
||||
|
||||
/**
|
||||
* @brief Retrieve the flag to tell csync that only a local run is intended.
|
||||
*
|
||||
* @return 1: stay local only, 0: local and remote mode
|
||||
*/
|
||||
bool csync_get_local_only( CSYNC *ctx );
|
||||
|
||||
/* Used for special modes or debugging */
|
||||
CSYNC_STATUS csync_get_status(CSYNC *ctx);
|
||||
|
||||
|
||||
@@ -20,12 +20,18 @@
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_exclude.h"
|
||||
@@ -217,7 +223,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
SAFE_FREE(bname);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
if (ctx->excludes == NULL) {
|
||||
if (ctx == NULL || ctx->excludes == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,52 +47,6 @@
|
||||
#include "csync_macros.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
char *csync_get_user_home_dir(void) {
|
||||
wchar_t tmp[MAX_PATH];
|
||||
char *szPath = NULL;
|
||||
|
||||
if( SHGetFolderPathW( NULL,
|
||||
CSIDL_PROFILE|CSIDL_FLAG_CREATE,
|
||||
NULL,
|
||||
0,
|
||||
tmp) == S_OK ) {
|
||||
szPath = c_utf8_from_locale(tmp);
|
||||
return szPath;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else /* ************* !WIN32 ************ */
|
||||
|
||||
#ifndef NSS_BUFLEN_PASSWD
|
||||
#define NSS_BUFLEN_PASSWD 4096
|
||||
#endif /* NSS_BUFLEN_PASSWD */
|
||||
|
||||
char *csync_get_user_home_dir(void) {
|
||||
const char *envp;
|
||||
struct passwd pwd;
|
||||
struct passwd *pwdbuf;
|
||||
char buf[NSS_BUFLEN_PASSWD];
|
||||
int rc;
|
||||
|
||||
envp = getenv("HOME");
|
||||
if (envp != NULL && envp[0] != '\0') {
|
||||
return c_strdup(envp);
|
||||
}
|
||||
|
||||
/* Still nothing found, read the password file */
|
||||
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||
if (rc != 0) {
|
||||
return c_strdup(pwd.pw_dir);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* ************* WIN32 ************ */
|
||||
|
||||
#ifdef HAVE_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
||||
#endif
|
||||
|
||||
char *csync_get_user_home_dir(void);
|
||||
|
||||
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,79 +20,10 @@
|
||||
*/
|
||||
|
||||
#include "csync_owncloud.h"
|
||||
#include "csync_owncloud_private.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
* free the fetchCtx
|
||||
*/
|
||||
static void free_fetchCtx( struct listdir_context *ctx )
|
||||
{
|
||||
struct resource *newres, *res;
|
||||
if( ! ctx ) return;
|
||||
newres = ctx->list;
|
||||
res = newres;
|
||||
|
||||
ctx->ref--;
|
||||
if (ctx->ref > 0) return;
|
||||
|
||||
SAFE_FREE(ctx->target);
|
||||
|
||||
while( res ) {
|
||||
SAFE_FREE(res->uri);
|
||||
SAFE_FREE(res->name);
|
||||
SAFE_FREE(res->md5);
|
||||
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
|
||||
|
||||
newres = res->next;
|
||||
SAFE_FREE(res);
|
||||
res = newres;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* local variables.
|
||||
*/
|
||||
|
||||
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
|
||||
int _connected = 0; /* flag to indicate if a connection exists, ie.
|
||||
the dav_session is valid */
|
||||
|
||||
|
||||
void *_userdata;
|
||||
long long chunked_total_size = 0;
|
||||
long long chunked_done = 0;
|
||||
|
||||
struct listdir_context *propfind_cache = 0;
|
||||
|
||||
bool is_first_propfind = true;
|
||||
|
||||
|
||||
csync_vio_file_stat_t _stat_cache;
|
||||
/* id cache, cache the ETag: header of a GET request */
|
||||
struct { char *uri; char *id; } _id_cache = { NULL, NULL };
|
||||
|
||||
static void clean_caches() {
|
||||
clear_propfind_recursive_cache();
|
||||
|
||||
free_fetchCtx(propfind_cache);
|
||||
propfind_cache = NULL;
|
||||
|
||||
SAFE_FREE(_stat_cache.name);
|
||||
SAFE_FREE(_stat_cache.etag );
|
||||
memset( _stat_cache.file_id, 0, FILE_ID_BUF_SIZE+1 );
|
||||
|
||||
SAFE_FREE(_id_cache.uri);
|
||||
SAFE_FREE(_id_cache.id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define PUT_BUFFER_SIZE 1024*5
|
||||
|
||||
char _buffer[PUT_BUFFER_SIZE];
|
||||
|
||||
/*
|
||||
* helper method to build up a user text for SSL problems, called from the
|
||||
@@ -116,7 +47,7 @@ static void addSSLWarning( char *ptr, const char *warn, int len )
|
||||
* it to the csync callback to ask the user.
|
||||
*/
|
||||
#define LEN 4096
|
||||
static int verify_sslcert(void *userdata, int failures,
|
||||
static int ssl_callback_by_neon(void *userdata, int failures,
|
||||
const ne_ssl_certificate *certificate)
|
||||
{
|
||||
char problem[LEN];
|
||||
@@ -124,8 +55,8 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
int ret = -1;
|
||||
const ne_ssl_certificate *cert = certificate;
|
||||
csync_auth_callback authcb = NULL;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
(void) userdata;
|
||||
memset( problem, 0, LEN );
|
||||
|
||||
while( cert ) {
|
||||
@@ -161,14 +92,14 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
}
|
||||
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
|
||||
|
||||
if( dav_session.csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
||||
if( ctx->csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
||||
}
|
||||
if( authcb ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for SSL problems");
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||
if( buf[0] == 'y' || buf[0] == 'Y') {
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -184,41 +115,39 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
* Authentication callback. Is set by ne_set_server_auth to be called
|
||||
* from the neon lib to authenticate a request.
|
||||
*/
|
||||
static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
||||
char *username, char *password)
|
||||
{
|
||||
char buf[NE_ABUFSIZ];
|
||||
csync_auth_callback authcb = NULL;
|
||||
int re = attempt;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
(void) userdata;
|
||||
(void) realm;
|
||||
|
||||
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
|
||||
if( username && password ) {
|
||||
DEBUG_WEBDAV( "Authentication required %s", username );
|
||||
if( dav_session.user ) {
|
||||
if( ctx->dav_session.user ) {
|
||||
/* allow user without password */
|
||||
if( strlen( dav_session.user ) < NE_ABUFSIZ ) {
|
||||
strcpy( username, dav_session.user );
|
||||
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
|
||||
strcpy( username, ctx->dav_session.user );
|
||||
}
|
||||
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
|
||||
strcpy( password, dav_session.pwd );
|
||||
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
|
||||
strcpy( password, ctx->dav_session.pwd );
|
||||
}
|
||||
} else {
|
||||
if( dav_session.csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
||||
}
|
||||
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
||||
if( authcb != NULL ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||
if( strlen(buf) < NE_ABUFSIZ ) {
|
||||
strcpy( username, buf );
|
||||
}
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
|
||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||
if( strlen(buf) < NE_ABUFSIZ) {
|
||||
strcpy( password, buf );
|
||||
}
|
||||
@@ -235,15 +164,15 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||
* from the neon lib to authenticate against a proxy. The data to authenticate
|
||||
* against comes from mirall throught vio_module_init function.
|
||||
*/
|
||||
static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
|
||||
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
||||
char *username, char *password)
|
||||
{
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
(void) realm;
|
||||
if( dav_session.proxy_user && strlen( dav_session.proxy_user ) < NE_ABUFSIZ) {
|
||||
strcpy( username, dav_session.proxy_user );
|
||||
if( dav_session.proxy_pwd && strlen( dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
||||
strcpy( password, dav_session.proxy_pwd );
|
||||
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
|
||||
strcpy( username, ctx->dav_session.proxy_user );
|
||||
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
||||
strcpy( password, ctx->dav_session.proxy_pwd );
|
||||
}
|
||||
}
|
||||
/* NTLM needs several attempts */
|
||||
@@ -251,42 +180,42 @@ static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
|
||||
}
|
||||
|
||||
/* Configure the proxy depending on the variables */
|
||||
static int configureProxy( ne_session *session )
|
||||
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
|
||||
{
|
||||
int port = 8080;
|
||||
int re = -1;
|
||||
|
||||
if( ! session ) return -1;
|
||||
if( ! dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
||||
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
||||
|
||||
if( dav_session.proxy_port > 0 ) {
|
||||
port = dav_session.proxy_port;
|
||||
if( ctx->dav_session.proxy_port > 0 ) {
|
||||
port = ctx->dav_session.proxy_port;
|
||||
}
|
||||
|
||||
if( c_streq(dav_session.proxy_type, "NoProxy" )) {
|
||||
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
|
||||
DEBUG_WEBDAV("No proxy configured.");
|
||||
re = 0;
|
||||
} else if( c_streq(dav_session.proxy_type, "DefaultProxy") ||
|
||||
c_streq(dav_session.proxy_type, "HttpProxy") ||
|
||||
c_streq(dav_session.proxy_type, "HttpCachingProxy") ||
|
||||
c_streq(dav_session.proxy_type, "Socks5Proxy")) {
|
||||
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
|
||||
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
|
||||
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
|
||||
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
||||
|
||||
if( dav_session.proxy_host ) {
|
||||
DEBUG_WEBDAV("%s at %s:%d", dav_session.proxy_type, dav_session.proxy_host, port );
|
||||
if (c_streq(dav_session.proxy_type, "Socks5Proxy")) {
|
||||
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, dav_session.proxy_host, port,
|
||||
dav_session.proxy_user, dav_session.proxy_pwd);
|
||||
if( ctx->dav_session.proxy_host ) {
|
||||
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
|
||||
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
||||
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
|
||||
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
|
||||
} else {
|
||||
ne_session_proxy(session, dav_session.proxy_host, port );
|
||||
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
|
||||
}
|
||||
re = 2;
|
||||
} else {
|
||||
DEBUG_WEBDAV("%s requested but no proxy host defined.", dav_session.proxy_type );
|
||||
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
|
||||
/* we used to try ne_system_session_proxy here, but we should rather err out
|
||||
to behave exactly like the caller. */
|
||||
}
|
||||
} else {
|
||||
DEBUG_WEBDAV( "Unsupported Proxy: %s", dav_session.proxy_type );
|
||||
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
|
||||
}
|
||||
|
||||
return re;
|
||||
@@ -303,9 +232,9 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||
const char *sc = NULL;
|
||||
char *key = NULL;
|
||||
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
if (dav_session.session_key)
|
||||
if (ctx->dav_session.session_key)
|
||||
return; /* We already have a session cookie, and we should ignore other ones */
|
||||
|
||||
if(!(status && req)) return;
|
||||
@@ -373,8 +302,8 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||
}
|
||||
if( key ) {
|
||||
DEBUG_WEBDAV("----> Session-key: %s", key);
|
||||
SAFE_FREE(dav_session.session_key);
|
||||
dav_session.session_key = key;
|
||||
SAFE_FREE(ctx->dav_session.session_key);
|
||||
ctx->dav_session.session_key = key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,13 +314,14 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||
static void request_created_hook(ne_request *req, void *userdata,
|
||||
const char *method, const char *requri)
|
||||
{
|
||||
(void) userdata;
|
||||
// FIXME Can possibly be merged with pre_send_hook
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||
(void) method;
|
||||
(void) requri;
|
||||
|
||||
if( !req ) return;
|
||||
|
||||
if(dav_session.proxy_type) {
|
||||
if(ctx->dav_session.proxy_type) {
|
||||
/* required for NTLM */
|
||||
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
|
||||
}
|
||||
@@ -404,12 +334,12 @@ static void request_created_hook(ne_request *req, void *userdata,
|
||||
static void pre_send_hook(ne_request *req, void *userdata,
|
||||
ne_buffer *header)
|
||||
{
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||
|
||||
if( !req ) return;
|
||||
|
||||
if(dav_session.session_key) {
|
||||
ne_buffer_concat(header, "Cookie: ", dav_session.session_key, "\r\n", NULL);
|
||||
if(ctx->dav_session.session_key) {
|
||||
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
|
||||
} else {
|
||||
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
|
||||
}
|
||||
@@ -419,16 +349,15 @@ static int post_send_hook(ne_request *req, void *userdata,
|
||||
const ne_status *status)
|
||||
{
|
||||
const char *location;
|
||||
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||
(void) status;
|
||||
|
||||
location = ne_get_response_header(req, "Location");
|
||||
|
||||
if( !location ) return NE_OK;
|
||||
|
||||
if( dav_session.redir_callback ) {
|
||||
if( dav_session.redir_callback( dav_session.csync_ctx, location ) ) {
|
||||
if( ctx->dav_session.redir_callback ) {
|
||||
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
|
||||
return NE_REDIRECT;
|
||||
} else {
|
||||
return NE_RETRY;
|
||||
@@ -438,37 +367,12 @@ static int post_send_hook(ne_request *req, void *userdata,
|
||||
return NE_REDIRECT;
|
||||
}
|
||||
|
||||
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
|
||||
// extend as required
|
||||
static const char* get_platform() {
|
||||
#if defined (_WIN32)
|
||||
return "Windows";
|
||||
#elif defined(__APPLE__)
|
||||
return "Macintosh";
|
||||
#elif defined(__gnu_linux__)
|
||||
return "Linux";
|
||||
#elif defined(__DragonFly__)
|
||||
/* might also define __FreeBSD__ */
|
||||
return "DragonFlyBSD";
|
||||
#elif defined(__FreeBSD__)
|
||||
return "FreeBSD";
|
||||
#elif defined(__NetBSD__)
|
||||
return "NetBSD";
|
||||
#elif defined(__OpenBSD__)
|
||||
return "OpenBSD";
|
||||
#elif defined(sun) || defined(__sun)
|
||||
return "Solaris";
|
||||
#else
|
||||
return "Unknown OS";
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to a DAV server
|
||||
* This function sets the flag _connected if the connection is established
|
||||
* and returns if the flag is set, so calling it frequently is save.
|
||||
*/
|
||||
static int dav_connect(const char *base_url) {
|
||||
static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
|
||||
int useSSL = 0;
|
||||
int rc;
|
||||
char protocol[6] = {'\0'};
|
||||
@@ -479,11 +383,14 @@ static int dav_connect(const char *base_url) {
|
||||
unsigned int port = 0;
|
||||
int proxystate = -1;
|
||||
|
||||
if (_connected) {
|
||||
if (ctx->_connected) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = c_parse_uri( base_url, &scheme, &dav_session.user, &dav_session.pwd, &host, &port, &path );
|
||||
rc = c_parse_uri( base_url, &scheme,
|
||||
&ctx->dav_session.user,
|
||||
&ctx->dav_session.pwd,
|
||||
&host, &port, &path );
|
||||
if( rc < 0 ) {
|
||||
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
|
||||
goto out;
|
||||
@@ -505,29 +412,29 @@ static int dav_connect(const char *base_url) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUG_WEBDAV("* user %s", dav_session.user ? dav_session.user : "");
|
||||
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
|
||||
|
||||
if (port == 0) {
|
||||
port = ne_uri_defaultport(protocol);
|
||||
}
|
||||
|
||||
dav_session.ctx = ne_session_create( protocol, host, port);
|
||||
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
|
||||
|
||||
if (dav_session.ctx == NULL) {
|
||||
if (ctx->dav_session.ctx == NULL) {
|
||||
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dav_session.read_timeout != 0) {
|
||||
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
|
||||
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
|
||||
if (ctx->dav_session.read_timeout != 0) {
|
||||
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
|
||||
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
|
||||
}
|
||||
|
||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
||||
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
||||
ne_set_useragent( dav_session.ctx, uaBuf);
|
||||
ne_set_server_auth(dav_session.ctx, ne_auth, 0 );
|
||||
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
||||
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
||||
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
||||
|
||||
if( useSSL ) {
|
||||
if (!ne_has_support(NE_FEATURE_SSL)) {
|
||||
@@ -536,28 +443,28 @@ static int dav_connect(const char *base_url) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ne_ssl_trust_default_ca( dav_session.ctx );
|
||||
ne_ssl_set_verify( dav_session.ctx, verify_sslcert, 0 );
|
||||
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
|
||||
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
|
||||
}
|
||||
|
||||
/* Hook called when a request is created. It sets the proxy connection header. */
|
||||
ne_hook_create_request( dav_session.ctx, request_created_hook, NULL );
|
||||
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
|
||||
/* Hook called after response headers are read. It gets the Session ID. */
|
||||
ne_hook_post_headers( dav_session.ctx, post_request_hook, NULL );
|
||||
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
|
||||
/* Hook called before a request is sent. It sets the cookies. */
|
||||
ne_hook_pre_send( dav_session.ctx, pre_send_hook, NULL );
|
||||
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
|
||||
/* Hook called after request is dispatched. Used for handling possible redirections. */
|
||||
ne_hook_post_send( dav_session.ctx, post_send_hook, NULL );
|
||||
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
|
||||
|
||||
/* Proxy support */
|
||||
proxystate = configureProxy( dav_session.ctx );
|
||||
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
|
||||
if( proxystate < 0 ) {
|
||||
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
|
||||
} else if( proxystate > 0 ) {
|
||||
ne_set_proxy_auth( dav_session.ctx, ne_proxy_auth, 0 );
|
||||
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, ctx );
|
||||
}
|
||||
|
||||
_connected = 1;
|
||||
ctx->_connected = 1;
|
||||
rc = 0;
|
||||
out:
|
||||
SAFE_FREE(path);
|
||||
@@ -573,24 +480,16 @@ out:
|
||||
* and fills a resource struct and stores it to the result list which
|
||||
* is stored in the listdir_context.
|
||||
*/
|
||||
static void results(void *userdata,
|
||||
static void propfind_results_callback(void *userdata,
|
||||
const ne_uri *uri,
|
||||
const ne_prop_result_set *set)
|
||||
{
|
||||
struct listdir_context *fetchCtx = userdata;
|
||||
struct resource *newres = 0;
|
||||
const char *clength, *modtime = NULL;
|
||||
const char *resourcetype = NULL;
|
||||
const char *md5sum = NULL;
|
||||
const char *file_id = NULL;
|
||||
const ne_status *status = NULL;
|
||||
char *path = ne_path_unescape( uri->path );
|
||||
|
||||
(void) status;
|
||||
if( ! fetchCtx ) {
|
||||
DEBUG_WEBDAV("No valid fetchContext");
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! fetchCtx->target ) {
|
||||
DEBUG_WEBDAV("error: target must not be zero!" );
|
||||
@@ -599,37 +498,9 @@ static void results(void *userdata,
|
||||
|
||||
/* Fill the resource structure with the data about the file */
|
||||
newres = c_malloc(sizeof(struct resource));
|
||||
ZERO_STRUCTP(newres);
|
||||
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
|
||||
newres->name = c_basename( path );
|
||||
|
||||
modtime = ne_propset_value( set, &ls_props[0] );
|
||||
clength = ne_propset_value( set, &ls_props[1] );
|
||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||
file_id = ne_propset_value( set, &ls_props[4] );
|
||||
|
||||
newres->type = resr_normal;
|
||||
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||
newres->type = resr_collection;
|
||||
}
|
||||
|
||||
if (modtime) {
|
||||
newres->modtime = oc_httpdate_parse(modtime);
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
|
||||
newres->size = 0;
|
||||
if (clength) {
|
||||
newres->size = atoll(clength);
|
||||
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
|
||||
}
|
||||
|
||||
if( md5sum ) {
|
||||
newres->md5 = csync_normalize_etag(md5sum);
|
||||
}
|
||||
|
||||
csync_vio_set_file_id(newres->file_id, file_id);
|
||||
fill_webdav_properties_into_resource(newres, set);
|
||||
|
||||
/* prepend the new resource to the result list */
|
||||
newres->next = fetchCtx->list;
|
||||
@@ -643,7 +514,7 @@ static void results(void *userdata,
|
||||
/*
|
||||
* fetches a resource list from the WebDAV server. This is equivalent to list dir.
|
||||
*/
|
||||
static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
|
||||
{
|
||||
struct listdir_context *fetchCtx;
|
||||
int ret = 0;
|
||||
@@ -657,12 +528,12 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
|
||||
/* The old legacy one-level PROPFIND cache. Also gets filled
|
||||
by the recursive cache if 'infinity' did not suceed. */
|
||||
if (propfind_cache) {
|
||||
if (c_streq(curi, propfind_cache->target)) {
|
||||
if (ctx->propfind_cache) {
|
||||
if (c_streq(curi, ctx->propfind_cache->target)) {
|
||||
DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
|
||||
propfind_cache->ref++;
|
||||
ctx->propfind_cache->ref++;
|
||||
SAFE_FREE(curi);
|
||||
return propfind_cache;
|
||||
return ctx->propfind_cache;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,10 +549,10 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
fetchCtx->ref = 1;
|
||||
|
||||
/* do a propfind request and parse the results in the results function, set as callback */
|
||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
||||
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||
|
||||
if(hdl) {
|
||||
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
|
||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_callback, fetchCtx);
|
||||
request = ne_propfind_get_request( hdl );
|
||||
req_status = ne_get_status( request );
|
||||
}
|
||||
@@ -694,14 +565,14 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
||||
req_status->reason_phrase);
|
||||
ret = NE_CONNECT;
|
||||
set_error_message(req_status->reason_phrase);
|
||||
set_error_message(ctx, req_status->reason_phrase);
|
||||
}
|
||||
DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
|
||||
} else {
|
||||
if( ret == NE_ERROR && req_status->code == 404) {
|
||||
errno = ENOENT;
|
||||
} else {
|
||||
set_errno_from_neon_errcode(ret);
|
||||
set_errno_from_neon_errcode(ctx, ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,18 +587,18 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
||||
content_type ? content_type: "<empty>");
|
||||
errno = ERRNO_WRONG_CONTENT;
|
||||
set_error_message("Server error: PROPFIND reply is not XML formatted!");
|
||||
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
|
||||
ret = NE_CONNECT;
|
||||
}
|
||||
}
|
||||
|
||||
if( ret != NE_OK ) {
|
||||
const char *err = NULL;
|
||||
set_errno_from_neon_errcode(ret);
|
||||
set_errno_from_neon_errcode(ctx, ret);
|
||||
|
||||
err = ne_get_error( dav_session.ctx );
|
||||
err = ne_get_error( ctx->dav_session.ctx );
|
||||
if(err) {
|
||||
set_error_message(err);
|
||||
set_error_message(ctx, err);
|
||||
}
|
||||
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
||||
}
|
||||
@@ -740,19 +611,19 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free_fetchCtx(propfind_cache);
|
||||
propfind_cache = fetchCtx;
|
||||
propfind_cache->ref++;
|
||||
free_fetchCtx(ctx->propfind_cache);
|
||||
ctx->propfind_cache = fetchCtx;
|
||||
ctx->propfind_cache->ref++;
|
||||
return fetchCtx;
|
||||
}
|
||||
|
||||
static struct listdir_context *fetch_resource_list_attempts(const char *uri, int depth)
|
||||
static struct listdir_context *fetch_resource_list_attempts(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
for(i = 0; i < 10; ++i) {
|
||||
fetchCtx = fetch_resource_list(uri, depth);
|
||||
fetchCtx = fetch_resource_list(ctx, uri, depth);
|
||||
if(fetchCtx) break;
|
||||
/* only loop in case the content is not XML formatted. Otherwise for every
|
||||
* non successful stat (for non existing directories) its tried 10 times. */
|
||||
@@ -764,165 +635,39 @@ static struct listdir_context *fetch_resource_list_attempts(const char *uri, int
|
||||
return fetchCtx;
|
||||
}
|
||||
|
||||
static void fill_stat_cache( csync_vio_file_stat_t *lfs ) {
|
||||
|
||||
if( _stat_cache.name ) SAFE_FREE(_stat_cache.name);
|
||||
if( _stat_cache.etag ) SAFE_FREE(_stat_cache.etag );
|
||||
|
||||
if( !lfs) return;
|
||||
|
||||
_stat_cache.name = c_strdup(lfs->name);
|
||||
_stat_cache.mtime = lfs->mtime;
|
||||
_stat_cache.fields = lfs->fields;
|
||||
_stat_cache.type = lfs->type;
|
||||
_stat_cache.size = lfs->size;
|
||||
csync_vio_file_stat_set_file_id(&_stat_cache, lfs->file_id);
|
||||
|
||||
if( lfs->etag ) {
|
||||
_stat_cache.etag = c_strdup(lfs->etag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* file functions
|
||||
*/
|
||||
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
/* get props:
|
||||
* modtime
|
||||
* creattime
|
||||
* size
|
||||
*/
|
||||
csync_vio_file_stat_t *lfs = NULL;
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
char *decodedUri = NULL;
|
||||
int len = 0;
|
||||
errno = 0;
|
||||
|
||||
buf->name = c_basename(uri);
|
||||
|
||||
if (buf->name == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( _stat_cache.name && strcmp( buf->name, _stat_cache.name ) == 0 ) {
|
||||
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
buf->fields = _stat_cache.fields;
|
||||
buf->type = _stat_cache.type;
|
||||
buf->mtime = _stat_cache.mtime;
|
||||
buf->size = _stat_cache.size;
|
||||
buf->mode = _stat_perms( _stat_cache.type );
|
||||
buf->etag = NULL;
|
||||
if( _stat_cache.etag ) {
|
||||
buf->etag = c_strdup( _stat_cache.etag );
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
||||
}
|
||||
csync_vio_file_stat_set_file_id( buf, _stat_cache.file_id );
|
||||
return 0;
|
||||
}
|
||||
DEBUG_WEBDAV("owncloud_stat => Could not find in stat cache %s", uri);
|
||||
|
||||
/* fetch data via a propfind call. */
|
||||
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE); */
|
||||
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
|
||||
DEBUG_WEBDAV("=> Errno after fetch resource list for %s: %d", uri, errno);
|
||||
if (!fetchCtx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( fetchCtx ) {
|
||||
struct resource *res = fetchCtx->list;
|
||||
while( res ) {
|
||||
/* remove trailing slashes */
|
||||
len = strlen(res->uri);
|
||||
while( len > 0 && res->uri[len-1] == '/' ) --len;
|
||||
decodedUri = ne_path_unescape( fetchCtx->target ); /* allocates memory */
|
||||
|
||||
/* Only do the comparaison of the part of the string without the trailing
|
||||
slashes, and make sure decodedUri is not too large */
|
||||
if( strncmp(res->uri, decodedUri, len ) == 0 && decodedUri[len] == '\0') {
|
||||
SAFE_FREE( decodedUri );
|
||||
break;
|
||||
}
|
||||
res = res->next;
|
||||
SAFE_FREE( decodedUri );
|
||||
}
|
||||
if( res ) {
|
||||
DEBUG_WEBDAV("Working on file %s", res->name );
|
||||
} else {
|
||||
DEBUG_WEBDAV("ERROR: Result struct not valid!");
|
||||
}
|
||||
|
||||
lfs = resourceToFileStat( res );
|
||||
if( lfs ) {
|
||||
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
||||
|
||||
buf->fields = lfs->fields;
|
||||
buf->type = lfs->type;
|
||||
buf->mtime = lfs->mtime;
|
||||
buf->size = lfs->size;
|
||||
buf->mode = _stat_perms( lfs->type );
|
||||
buf->etag = NULL;
|
||||
if( lfs->etag ) {
|
||||
buf->etag = c_strdup( lfs->etag );
|
||||
}
|
||||
csync_vio_file_stat_set_file_id( buf, lfs->file_id );
|
||||
|
||||
/* fill the static stat buf as input for the stat function */
|
||||
csync_vio_file_stat_destroy( lfs );
|
||||
}
|
||||
|
||||
free_fetchCtx( fetchCtx );
|
||||
}
|
||||
DEBUG_WEBDAV("STAT result from propfind: %s, mtime: %llu", buf->name ? buf->name:"NULL",
|
||||
(unsigned long long) buf->mtime );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* directory functions
|
||||
*/
|
||||
csync_vio_handle_t *owncloud_opendir(const char *uri) {
|
||||
csync_vio_handle_t *owncloud_opendir(CSYNC *ctx, const char *uri) {
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
char *curi = NULL;
|
||||
|
||||
DEBUG_WEBDAV("opendir method called on %s", uri );
|
||||
|
||||
if (dav_connect( uri ) < 0) {
|
||||
if (dav_connect( ctx->owncloud_context, uri ) < 0) {
|
||||
DEBUG_WEBDAV("connection failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curi = _cleanPath( uri );
|
||||
if (is_first_propfind && !dav_session.no_recursive_propfind) {
|
||||
is_first_propfind = false;
|
||||
if (ctx->owncloud_context->is_first_propfind && !ctx->owncloud_context->dav_session.no_recursive_propfind) {
|
||||
ctx->owncloud_context->is_first_propfind = false;
|
||||
// Try to fill it
|
||||
fill_recursive_propfind_cache(uri, curi);
|
||||
fill_recursive_propfind_cache(ctx->owncloud_context, uri, curi);
|
||||
}
|
||||
if (propfind_recursive_cache) {
|
||||
if (ctx->owncloud_context->propfind_recursive_cache) {
|
||||
// Try to fetch from recursive cache (if we have one)
|
||||
fetchCtx = get_listdir_context_from_recursive_cache(curi);
|
||||
fetchCtx = get_listdir_context_from_recursive_cache(ctx->owncloud_context, curi);
|
||||
}
|
||||
SAFE_FREE(curi);
|
||||
is_first_propfind = false;
|
||||
ctx->owncloud_context->is_first_propfind = false;
|
||||
if (fetchCtx) {
|
||||
return fetchCtx;
|
||||
}
|
||||
|
||||
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE ); */
|
||||
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
|
||||
fetchCtx = fetch_resource_list_attempts( ctx->owncloud_context, uri, NE_DEPTH_ONE);
|
||||
if( !fetchCtx ) {
|
||||
/* errno is set properly in fetch_resource_list */
|
||||
DEBUG_WEBDAV("Errno set to %d", errno);
|
||||
@@ -935,17 +680,16 @@ csync_vio_handle_t *owncloud_opendir(const char *uri) {
|
||||
/* no freeing of curi because its part of the fetchCtx and gets freed later */
|
||||
}
|
||||
|
||||
int owncloud_closedir(csync_vio_handle_t *dhandle) {
|
||||
|
||||
int owncloud_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||
struct listdir_context *fetchCtx = dhandle;
|
||||
|
||||
free_fetchCtx(fetchCtx);
|
||||
|
||||
(void)ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
||||
csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||
struct listdir_context *fetchCtx = dhandle;
|
||||
(void)ctx;
|
||||
|
||||
// DEBUG_WEBDAV("owncloud_readdir" );
|
||||
// DEBUG_WEBDAV("owncloud_readdir %s ", fetchCtx->target);
|
||||
@@ -971,8 +715,10 @@ csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
||||
*/
|
||||
escaped_path = ne_path_escape( currResource->uri );
|
||||
if (ne_path_compare(fetchCtx->target, escaped_path) != 0) {
|
||||
csync_vio_file_stat_t* lfs = resourceToFileStat(currResource);
|
||||
fill_stat_cache(lfs);
|
||||
// Convert the resource for the caller
|
||||
csync_vio_file_stat_t* lfs = csync_vio_file_stat_new();
|
||||
resourceToFileStat(lfs, currResource);
|
||||
|
||||
SAFE_FREE( escaped_path );
|
||||
return lfs;
|
||||
}
|
||||
@@ -984,39 +730,55 @@ csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *owncloud_error_string(void)
|
||||
char *owncloud_error_string(CSYNC* ctx)
|
||||
{
|
||||
return dav_session.error_string;
|
||||
return ctx->owncloud_context->dav_session.error_string;
|
||||
}
|
||||
|
||||
int owncloud_commit(void) {
|
||||
int owncloud_commit(CSYNC* ctx) {
|
||||
if (!ctx->owncloud_context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
clean_caches();
|
||||
clear_propfind_recursive_cache(ctx->owncloud_context);
|
||||
|
||||
if( dav_session.ctx ) {
|
||||
ne_forget_auth(dav_session.ctx);
|
||||
ne_session_destroy( dav_session.ctx );
|
||||
}
|
||||
free_fetchCtx(ctx->owncloud_context->propfind_cache);
|
||||
ctx->owncloud_context->propfind_cache = NULL;
|
||||
|
||||
if( ctx->owncloud_context->dav_session.ctx ) {
|
||||
ne_forget_auth(ctx->owncloud_context->dav_session.ctx);
|
||||
ne_session_destroy(ctx->owncloud_context->dav_session.ctx );
|
||||
ctx->owncloud_context->dav_session.ctx = 0;
|
||||
}
|
||||
|
||||
ctx->owncloud_context->is_first_propfind = true;
|
||||
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
|
||||
|
||||
dav_session.ctx = 0;
|
||||
ctx->owncloud_context->dav_session.ctx = 0;
|
||||
|
||||
// ne_sock_exit();
|
||||
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
||||
ctx->owncloud_context->_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
||||
|
||||
SAFE_FREE( dav_session.user );
|
||||
SAFE_FREE( dav_session.pwd );
|
||||
SAFE_FREE( dav_session.session_key);
|
||||
SAFE_FREE( dav_session.error_string );
|
||||
SAFE_FREE( ctx->owncloud_context->dav_session.user );
|
||||
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
|
||||
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
|
||||
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int owncloud_set_property(const char *key, void *data) {
|
||||
void owncloud_destroy(CSYNC* ctx)
|
||||
{
|
||||
owncloud_commit(ctx);
|
||||
SAFE_FREE(ctx->owncloud_context);
|
||||
ctx->owncloud_context = 0;
|
||||
}
|
||||
|
||||
int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
|
||||
#define READ_STRING_PROPERTY(P) \
|
||||
if (c_streq(key, #P)) { \
|
||||
SAFE_FREE(dav_session.P); \
|
||||
dav_session.P = c_strdup((const char*)data); \
|
||||
SAFE_FREE(ctx->owncloud_context->dav_session.P); \
|
||||
ctx->owncloud_context->dav_session.P = c_strdup((const char*)data); \
|
||||
return 0; \
|
||||
}
|
||||
READ_STRING_PROPERTY(session_key)
|
||||
@@ -1027,48 +789,43 @@ int owncloud_set_property(const char *key, void *data) {
|
||||
#undef READ_STRING_PROPERTY
|
||||
|
||||
if (c_streq(key, "proxy_port")) {
|
||||
dav_session.proxy_port = *(int*)(data);
|
||||
ctx->owncloud_context->dav_session.proxy_port = *(int*)(data);
|
||||
return 0;
|
||||
}
|
||||
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
|
||||
dav_session.read_timeout = *(int*)(data);
|
||||
return 0;
|
||||
}
|
||||
if( c_streq(key, "csync_context")) {
|
||||
dav_session.csync_ctx = data;
|
||||
ctx->owncloud_context->dav_session.read_timeout = *(int*)(data);
|
||||
return 0;
|
||||
}
|
||||
if( c_streq(key, "get_dav_session")) {
|
||||
/* Give the ne_session to the caller */
|
||||
*(ne_session**)data = dav_session.ctx;
|
||||
*(ne_session**)data = ctx->owncloud_context->dav_session.ctx;
|
||||
return 0;
|
||||
}
|
||||
if( c_streq(key, "no_recursive_propfind")) {
|
||||
dav_session.no_recursive_propfind = *(bool*)(data);
|
||||
ctx->owncloud_context->dav_session.no_recursive_propfind = *(bool*)(data);
|
||||
return 0;
|
||||
}
|
||||
if( c_streq(key, "redirect_callback")) {
|
||||
if (data) {
|
||||
csync_owncloud_redirect_callback_t* cb_wrapper = data;
|
||||
|
||||
dav_session.redir_callback = *cb_wrapper;
|
||||
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
|
||||
} else {
|
||||
dav_session.redir_callback = NULL;
|
||||
ctx->owncloud_context->dav_session.redir_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void owncloud_init(void *userdata) {
|
||||
void owncloud_init(CSYNC* ctx) {
|
||||
|
||||
_userdata = userdata;
|
||||
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
||||
|
||||
memset(&dav_session, 0, sizeof(dav_session));
|
||||
ctx->owncloud_context = c_malloc( sizeof( struct csync_owncloud_ctx_s ));
|
||||
ctx->owncloud_context->csync_ctx = ctx; // back reference
|
||||
ctx->owncloud_context->is_first_propfind = true;
|
||||
|
||||
/* Disable it, Mirall can enable it for the first sync (= no DB)*/
|
||||
dav_session.no_recursive_propfind = true;
|
||||
ctx->owncloud_context->dav_session.no_recursive_propfind = true;
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -21,159 +21,18 @@
|
||||
#ifndef CSYNC_OWNCLOUD_H
|
||||
#define CSYNC_OWNCLOUD_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "config_csync.h"
|
||||
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
|
||||
#define NE_LFS
|
||||
#endif
|
||||
|
||||
#include <neon/ne_basic.h>
|
||||
#include <neon/ne_socket.h>
|
||||
#include <neon/ne_session.h>
|
||||
#include <neon/ne_request.h>
|
||||
#include <neon/ne_props.h>
|
||||
#include <neon/ne_auth.h>
|
||||
#include <neon/ne_dates.h>
|
||||
#include <neon/ne_compress.h>
|
||||
#include <neon/ne_redirect.h>
|
||||
|
||||
|
||||
#include "c_rbtree.h"
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync.h"
|
||||
#include "csync_misc.h"
|
||||
#include "csync_macros.h"
|
||||
#include "c_private.h"
|
||||
#include "httpbf.h"
|
||||
|
||||
#include "vio/csync_vio_file_stat.h"
|
||||
#include "vio/csync_vio.h"
|
||||
|
||||
#include "csync_log.h"
|
||||
|
||||
|
||||
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
|
||||
|
||||
enum resource_type {
|
||||
resr_normal = 0,
|
||||
resr_collection,
|
||||
resr_reference,
|
||||
resr_error
|
||||
};
|
||||
|
||||
/* Struct to store data for each resource found during an opendir operation.
|
||||
* It represents a single file entry.
|
||||
*/
|
||||
|
||||
typedef struct resource {
|
||||
char *uri; /* The complete uri */
|
||||
char *name; /* The filename only */
|
||||
|
||||
enum resource_type type;
|
||||
int64_t size;
|
||||
time_t modtime;
|
||||
char* md5;
|
||||
char file_id[FILE_ID_BUF_SIZE+1];
|
||||
|
||||
struct resource *next;
|
||||
} resource;
|
||||
|
||||
/* Struct to hold the context of a WebDAV PropFind operation to fetch
|
||||
* a directory listing from the server.
|
||||
*/
|
||||
struct listdir_context {
|
||||
struct resource *list; /* The list of result resources */
|
||||
struct resource *currResource; /* A pointer to the current resource */
|
||||
char *target; /* Request-URI of the PROPFIND */
|
||||
unsigned int result_count; /* number of elements stored in list */
|
||||
int ref; /* reference count, only destroy when it reaches 0 */
|
||||
};
|
||||
|
||||
|
||||
/* Our cache, key is a char* */
|
||||
extern c_rbtree_t *propfind_recursive_cache;
|
||||
/* Values are propfind_recursive_element: */
|
||||
struct propfind_recursive_element {
|
||||
struct resource *self;
|
||||
struct resource *children;
|
||||
struct propfind_recursive_element *parent;
|
||||
};
|
||||
typedef struct propfind_recursive_element propfind_recursive_element_t;
|
||||
void clear_propfind_recursive_cache(void);
|
||||
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi);
|
||||
void fill_recursive_propfind_cache(const char *uri, const char *curi);
|
||||
struct listdir_context *get_listdir_context_from_cache(const char *curi);
|
||||
void fetch_resource_list_recursive(const char *uri, const char *curi);
|
||||
|
||||
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
|
||||
|
||||
/* Struct with the WebDAV session */
|
||||
struct dav_session_s {
|
||||
ne_session *ctx;
|
||||
char *user;
|
||||
char *pwd;
|
||||
|
||||
char *proxy_type;
|
||||
char *proxy_host;
|
||||
int proxy_port;
|
||||
char *proxy_user;
|
||||
char *proxy_pwd;
|
||||
|
||||
char *session_key;
|
||||
|
||||
char *error_string;
|
||||
|
||||
int read_timeout;
|
||||
|
||||
CSYNC *csync_ctx;
|
||||
|
||||
bool no_recursive_propfind;
|
||||
|
||||
csync_owncloud_redirect_callback_t redir_callback;
|
||||
};
|
||||
extern struct dav_session_s dav_session;
|
||||
|
||||
/* The list of properties that is fetched in PropFind on a collection */
|
||||
static const ne_propname ls_props[] = {
|
||||
{ "DAV:", "getlastmodified" },
|
||||
{ "DAV:", "getcontentlength" },
|
||||
{ "DAV:", "resourcetype" },
|
||||
{ "DAV:", "getetag"},
|
||||
{ "http://owncloud.org/ns", "id"},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
void set_errno_from_http_errcode( int err );
|
||||
void set_error_message( const char *msg );
|
||||
void set_errno_from_neon_errcode( int neon_code );
|
||||
int http_result_code_from_session(void);
|
||||
void set_errno_from_session(void);
|
||||
|
||||
time_t oc_httpdate_parse( const char *date );
|
||||
|
||||
char *_cleanPath( const char* uri );
|
||||
|
||||
int _stat_perms( int type );
|
||||
csync_vio_file_stat_t *resourceToFileStat( struct resource *res );
|
||||
|
||||
// Public API from vio
|
||||
csync_vio_handle_t *owncloud_opendir(const char *uri);
|
||||
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle);
|
||||
int owncloud_closedir(csync_vio_handle_t *dhandle);
|
||||
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf);
|
||||
int owncloud_commit(void);
|
||||
char *owncloud_error_string(void);
|
||||
void owncloud_init(void *userdata);
|
||||
int owncloud_set_property(const char *key, void *data);
|
||||
// Public API used by csync
|
||||
csync_vio_handle_t *owncloud_opendir(CSYNC* ctx, const char *uri);
|
||||
csync_vio_file_stat_t *owncloud_readdir(CSYNC* ctx, csync_vio_handle_t *dhandle);
|
||||
int owncloud_closedir(CSYNC* ctx, csync_vio_handle_t *dhandle);
|
||||
int owncloud_commit(CSYNC* ctx);
|
||||
void owncloud_destroy(CSYNC* ctx);
|
||||
char *owncloud_error_string(CSYNC* ctx);
|
||||
void owncloud_init(CSYNC* ctx);
|
||||
int owncloud_set_property(CSYNC* ctx, const char *key, void *data);
|
||||
|
||||
#endif /* CSYNC_OWNCLOUD_H */
|
||||
|
||||
201
csync/src/csync_owncloud_private.h
Normal file
201
csync/src/csync_owncloud_private.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CSYNC_OWNCLOUD_PRIVATE_H
|
||||
#define CSYNC_OWNCLOUD_PRIVATE_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "config_csync.h"
|
||||
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
|
||||
#define NE_LFS
|
||||
#endif
|
||||
|
||||
#include <neon/ne_basic.h>
|
||||
#include <neon/ne_socket.h>
|
||||
#include <neon/ne_session.h>
|
||||
#include <neon/ne_request.h>
|
||||
#include <neon/ne_props.h>
|
||||
#include <neon/ne_auth.h>
|
||||
#include <neon/ne_dates.h>
|
||||
#include <neon/ne_compress.h>
|
||||
#include <neon/ne_redirect.h>
|
||||
|
||||
|
||||
#include "c_rbtree.h"
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync.h"
|
||||
#include "csync_misc.h"
|
||||
#include "csync_macros.h"
|
||||
#include "c_private.h"
|
||||
#include "httpbf.h"
|
||||
|
||||
#include "vio/csync_vio_file_stat.h"
|
||||
#include "vio/csync_vio.h"
|
||||
|
||||
#include "csync_log.h"
|
||||
|
||||
#include "csync_owncloud.h"
|
||||
|
||||
|
||||
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
|
||||
|
||||
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
|
||||
|
||||
/* Struct with the WebDAV session */
|
||||
struct dav_session_s {
|
||||
ne_session *ctx;
|
||||
char *user;
|
||||
char *pwd;
|
||||
|
||||
char *proxy_type;
|
||||
char *proxy_host;
|
||||
int proxy_port;
|
||||
char *proxy_user;
|
||||
char *proxy_pwd;
|
||||
|
||||
char *session_key;
|
||||
|
||||
char *error_string;
|
||||
|
||||
int read_timeout;
|
||||
|
||||
bool no_recursive_propfind;
|
||||
|
||||
csync_owncloud_redirect_callback_t redir_callback;
|
||||
};
|
||||
|
||||
struct csync_owncloud_ctx_s {
|
||||
CSYNC *csync_ctx;
|
||||
|
||||
// For the PROPFIND results
|
||||
bool is_first_propfind;
|
||||
struct listdir_context *propfind_cache;
|
||||
c_rbtree_t *propfind_recursive_cache;
|
||||
int propfind_recursive_cache_depth;
|
||||
int propfind_recursive_cache_file_count;
|
||||
int propfind_recursive_cache_folder_count;
|
||||
|
||||
// For the WebDAV connection
|
||||
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
|
||||
int _connected; /* flag to indicate if a connection exists, ie.
|
||||
the dav_session is valid */
|
||||
};
|
||||
typedef struct csync_owncloud_ctx_s csync_owncloud_ctx_t;
|
||||
//typedef csync_owncloud_ctx_t* csync_owncloud_ctx_p;
|
||||
|
||||
enum resource_type {
|
||||
resr_normal = 0,
|
||||
resr_collection,
|
||||
resr_reference,
|
||||
resr_error
|
||||
};
|
||||
|
||||
/* The list of properties that is fetched in PropFind on a collection */
|
||||
static const ne_propname ls_props[] = {
|
||||
{ "DAV:", "getlastmodified" },
|
||||
{ "DAV:", "getcontentlength" },
|
||||
{ "DAV:", "resourcetype" },
|
||||
{ "DAV:", "getetag"},
|
||||
{ "http://owncloud.org/ns", "id"},
|
||||
{ "http://owncloud.org/ns", "dDU"},
|
||||
{ "http://owncloud.org/ns", "dDC"},
|
||||
{ "http://owncloud.org/ns", "permissions"},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* Struct to store data for each resource found during an opendir operation.
|
||||
* It represents a single file entry.
|
||||
*/
|
||||
typedef struct resource {
|
||||
char *uri; /* The complete uri */
|
||||
char *name; /* The filename only */
|
||||
|
||||
enum resource_type type;
|
||||
int64_t size;
|
||||
time_t modtime;
|
||||
char* md5;
|
||||
char file_id[FILE_ID_BUF_SIZE+1];
|
||||
// Those two are optional from the server. We can use those URL to download the file directly
|
||||
// without going through the ownCloud instance.
|
||||
char *directDownloadUrl;
|
||||
char *directDownloadCookies;
|
||||
// See https://github.com/owncloud/core/issues/8322
|
||||
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
|
||||
|
||||
struct resource *next;
|
||||
} resource;
|
||||
|
||||
/* Struct to hold the context of a WebDAV PropFind operation to fetch
|
||||
* a directory listing from the server.
|
||||
*/
|
||||
struct listdir_context {
|
||||
struct resource *list; /* The list of result resources */
|
||||
struct resource *currResource; /* A pointer to the current resource */
|
||||
char *target; /* Request-URI of the PROPFIND */
|
||||
unsigned int result_count; /* number of elements stored in list */
|
||||
int ref; /* reference count, only destroy when it reaches 0 */
|
||||
};
|
||||
|
||||
|
||||
/* Values are propfind_recursive_element: */
|
||||
struct propfind_recursive_element {
|
||||
struct resource *self;
|
||||
struct resource *children;
|
||||
struct propfind_recursive_element *parent;
|
||||
};
|
||||
typedef struct propfind_recursive_element propfind_recursive_element_t;
|
||||
|
||||
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx);
|
||||
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi);
|
||||
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi);
|
||||
struct listdir_context *get_listdir_context_from_cache(csync_owncloud_ctx_t *ctx, const char *curi);
|
||||
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi);
|
||||
|
||||
void set_errno_from_http_errcode( int err );
|
||||
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg );
|
||||
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code );
|
||||
int http_result_code_from_session(csync_owncloud_ctx_t *ctx);
|
||||
void set_errno_from_session(csync_owncloud_ctx_t *ctx);
|
||||
|
||||
time_t oc_httpdate_parse( const char *date );
|
||||
|
||||
char *_cleanPath( const char* uri );
|
||||
|
||||
void fill_webdav_properties_into_resource(struct resource* newres, const ne_prop_result_set *set);
|
||||
|
||||
void resourceToFileStat( csync_vio_file_stat_t *lfs, struct resource *res );
|
||||
void resource_free(struct resource* o);
|
||||
struct resource* resource_dup(struct resource* o);
|
||||
void free_fetchCtx( struct listdir_context *ctx );
|
||||
|
||||
const char* csync_owncloud_get_platform(void);
|
||||
|
||||
#endif // CSYNC_OWNCLOUD_PRIVATE_H
|
||||
@@ -20,42 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "csync_owncloud.h"
|
||||
|
||||
c_rbtree_t *propfind_recursive_cache = NULL;
|
||||
int propfind_recursive_cache_depth = 0;
|
||||
int propfind_recursive_cache_file_count = 0;
|
||||
int propfind_recursive_cache_folder_count = 0;
|
||||
|
||||
|
||||
static struct resource* resource_dup(struct resource* o) {
|
||||
struct resource *r = c_malloc (sizeof( struct resource ));
|
||||
ZERO_STRUCTP(r);
|
||||
|
||||
r->uri = c_strdup(o->uri);
|
||||
r->name = c_strdup(o->name);
|
||||
r->type = o->type;
|
||||
r->size = o->size;
|
||||
r->modtime = o->modtime;
|
||||
if( o->md5 ) {
|
||||
r->md5 = c_strdup(o->md5);
|
||||
}
|
||||
r->next = o->next;
|
||||
csync_vio_set_file_id(r->file_id, o->file_id);
|
||||
|
||||
return r;
|
||||
}
|
||||
static void resource_free(struct resource* o) {
|
||||
struct resource* old = NULL;
|
||||
while (o)
|
||||
{
|
||||
old = o;
|
||||
o = o->next;
|
||||
SAFE_FREE(old->uri);
|
||||
SAFE_FREE(old->name);
|
||||
SAFE_FREE(old->md5);
|
||||
SAFE_FREE(old);
|
||||
}
|
||||
}
|
||||
#include "csync_owncloud_private.h"
|
||||
|
||||
static void _tree_destructor(void *data) {
|
||||
propfind_recursive_element_t *element = data;
|
||||
@@ -64,27 +29,27 @@ static void _tree_destructor(void *data) {
|
||||
SAFE_FREE(element);
|
||||
}
|
||||
|
||||
void clear_propfind_recursive_cache(void)
|
||||
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx)
|
||||
{
|
||||
if (propfind_recursive_cache) {
|
||||
if (ctx->propfind_recursive_cache) {
|
||||
DEBUG_WEBDAV("clear_propfind_recursive_cache Invalidating..");
|
||||
c_rbtree_destroy(propfind_recursive_cache, _tree_destructor);
|
||||
propfind_recursive_cache = NULL;
|
||||
c_rbtree_destroy(ctx->propfind_recursive_cache, _tree_destructor);
|
||||
ctx->propfind_recursive_cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi)
|
||||
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi)
|
||||
{
|
||||
propfind_recursive_element_t *element = NULL;
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
struct resource *iterator, *r;
|
||||
|
||||
if (!propfind_recursive_cache) {
|
||||
if (!ctx->propfind_recursive_cache) {
|
||||
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No cache");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache, curi));
|
||||
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache, curi));
|
||||
if (!element) {
|
||||
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No element %s in cache found", curi);
|
||||
return NULL;
|
||||
@@ -128,83 +93,53 @@ static int _data_cmp(const void *a, const void *b) {
|
||||
const propfind_recursive_element_t *elementB = b;
|
||||
return ne_path_compare(elementA->self->uri, elementB->self->uri);
|
||||
}
|
||||
static void propfind_results_recursive(void *userdata,
|
||||
static void propfind_results_recursive_callback(void *userdata,
|
||||
const ne_uri *uri,
|
||||
const ne_prop_result_set *set)
|
||||
{
|
||||
struct resource *newres = 0;
|
||||
const char *clength, *modtime, *file_id = NULL;
|
||||
const char *resourcetype = NULL;
|
||||
const char *md5sum = NULL;
|
||||
|
||||
const ne_status *status = NULL;
|
||||
char *path = ne_path_unescape( uri->path );
|
||||
char *parentPath;
|
||||
char *propfindRootUri = (char*) userdata;
|
||||
propfind_recursive_element_t *element = NULL;
|
||||
propfind_recursive_element_t *pElement = NULL;
|
||||
int depth = 0;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
|
||||
(void) status;
|
||||
(void) propfindRootUri;
|
||||
|
||||
if (!propfind_recursive_cache) {
|
||||
c_rbtree_create(&propfind_recursive_cache, _key_cmp, _data_cmp);
|
||||
if (!ctx->propfind_recursive_cache) {
|
||||
c_rbtree_create(&ctx->propfind_recursive_cache, _key_cmp, _data_cmp);
|
||||
}
|
||||
|
||||
/* Fill the resource structure with the data about the file */
|
||||
newres = c_malloc(sizeof(struct resource));
|
||||
ZERO_STRUCTP(newres);
|
||||
|
||||
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
|
||||
newres->name = c_basename( path );
|
||||
fill_webdav_properties_into_resource(newres, set);
|
||||
|
||||
modtime = ne_propset_value( set, &ls_props[0] );
|
||||
clength = ne_propset_value( set, &ls_props[1] );
|
||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||
file_id = ne_propset_value( set, &ls_props[4] );
|
||||
|
||||
newres->type = resr_normal;
|
||||
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||
newres->type = resr_collection;
|
||||
propfind_recursive_cache_folder_count++;
|
||||
if( newres->type == resr_collection) {
|
||||
ctx->propfind_recursive_cache_folder_count++;
|
||||
} else {
|
||||
/* DEBUG_WEBDAV("propfind_results_recursive %s [%d]", newres->uri, newres->type); */
|
||||
propfind_recursive_cache_file_count++;
|
||||
ctx->propfind_recursive_cache_file_count++;
|
||||
}
|
||||
|
||||
if (modtime) {
|
||||
newres->modtime = oc_httpdate_parse(modtime);
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
|
||||
newres->size = 0;
|
||||
if (clength) {
|
||||
newres->size = atoll(clength);
|
||||
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
|
||||
}
|
||||
|
||||
if( md5sum ) {
|
||||
newres->md5 = csync_normalize_etag(md5sum);
|
||||
}
|
||||
|
||||
csync_vio_set_file_id(newres->file_id, file_id);
|
||||
/*
|
||||
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
|
||||
*/
|
||||
|
||||
/* Create new item in rb tree */
|
||||
if (newres->type == resr_collection) {
|
||||
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
|
||||
/* Check if in rb tree */
|
||||
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,uri->path));
|
||||
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,uri->path));
|
||||
/* If not, create a new item and insert it */
|
||||
if (!element) {
|
||||
element = c_malloc(sizeof(propfind_recursive_element_t));
|
||||
element->self = resource_dup(newres);
|
||||
element->self->next = 0;
|
||||
element->children = NULL;
|
||||
element->parent = NULL;
|
||||
c_rbtree_insert(propfind_recursive_cache, element);
|
||||
c_rbtree_insert(ctx->propfind_recursive_cache, element);
|
||||
/* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */
|
||||
}
|
||||
}
|
||||
@@ -214,7 +149,7 @@ static void propfind_results_recursive(void *userdata,
|
||||
if (parentPath) {
|
||||
propfind_recursive_element_t *parentElement = NULL;
|
||||
|
||||
parentElement = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,parentPath));
|
||||
parentElement = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,parentPath));
|
||||
free(parentPath);
|
||||
|
||||
if (parentElement) {
|
||||
@@ -230,9 +165,9 @@ static void propfind_results_recursive(void *userdata,
|
||||
depth++;
|
||||
pElement = pElement->parent;
|
||||
}
|
||||
if (depth > propfind_recursive_cache_depth) {
|
||||
if (depth > ctx->propfind_recursive_cache_depth) {
|
||||
DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth);
|
||||
propfind_recursive_cache_depth = depth;
|
||||
ctx->propfind_recursive_cache_depth = depth;
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
|
||||
@@ -244,7 +179,7 @@ static void propfind_results_recursive(void *userdata,
|
||||
newres = NULL;
|
||||
}
|
||||
|
||||
void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi)
|
||||
{
|
||||
int ret = 0;
|
||||
ne_propfind_handler *hdl = NULL;
|
||||
@@ -256,10 +191,10 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);
|
||||
|
||||
/* do a propfind request and parse the results in the results function, set as callback */
|
||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
||||
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||
|
||||
if(hdl) {
|
||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
|
||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive_callback, ctx);
|
||||
request = ne_propfind_get_request( hdl );
|
||||
req_status = ne_get_status( request );
|
||||
}
|
||||
@@ -271,14 +206,14 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
||||
req_status->reason_phrase);
|
||||
ret = NE_CONNECT;
|
||||
set_error_message(req_status->reason_phrase);
|
||||
set_error_message(ctx, req_status->reason_phrase);
|
||||
}
|
||||
DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
|
||||
} else {
|
||||
if( ret == NE_ERROR && req_status->code == 404) {
|
||||
errno = ENOENT;
|
||||
} else {
|
||||
set_errno_from_neon_errcode(ret);
|
||||
set_errno_from_neon_errcode(ctx, ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +228,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
||||
content_type ? content_type: "<empty>");
|
||||
errno = ERRNO_WRONG_CONTENT;
|
||||
set_error_message("Server error: PROPFIND reply is not XML formatted!");
|
||||
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
|
||||
ret = NE_CONNECT;
|
||||
}
|
||||
}
|
||||
@@ -301,7 +236,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
if( ret != NE_OK ) {
|
||||
const char *err = NULL;
|
||||
|
||||
err = ne_get_error( dav_session.ctx );
|
||||
err = ne_get_error( ctx->dav_session.ctx );
|
||||
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
||||
}
|
||||
|
||||
@@ -316,22 +251,21 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
}
|
||||
|
||||
/* Called by owncloud_opendir()->fetch_resource_list() to fill the cache */
|
||||
extern struct listdir_context *propfind_cache;
|
||||
void fill_recursive_propfind_cache(const char *uri, const char *curi) {
|
||||
fetch_resource_list_recursive(uri, curi);
|
||||
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi) {
|
||||
fetch_resource_list_recursive(ctx, uri, curi);
|
||||
|
||||
if (propfind_recursive_cache_depth <= 2) {
|
||||
if (ctx->propfind_recursive_cache_depth <= 2) {
|
||||
DEBUG_WEBDAV("fill_recursive_propfind_cache %s Server maybe did not give us an 'infinity' depth result", curi);
|
||||
/* transform the cache to the normal cache in propfind_cache */
|
||||
propfind_cache = get_listdir_context_from_recursive_cache(curi);
|
||||
ctx->propfind_cache = get_listdir_context_from_recursive_cache(ctx, curi);
|
||||
/* clear the cache, it is bogus since the server returned only results for Depth 1 */
|
||||
clear_propfind_recursive_cache();
|
||||
clear_propfind_recursive_cache(ctx);
|
||||
} else {
|
||||
DEBUG_WEBDAV("fill_recursive_propfind_cache %s We received %d elements deep for 'infinity' depth (%d folders, %d files)",
|
||||
curi,
|
||||
propfind_recursive_cache_depth,
|
||||
propfind_recursive_cache_folder_count,
|
||||
propfind_recursive_cache_file_count);
|
||||
ctx->propfind_recursive_cache_depth,
|
||||
ctx->propfind_recursive_cache_folder_count,
|
||||
ctx->propfind_recursive_cache_file_count);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
*/
|
||||
|
||||
#include "csync_owncloud.h"
|
||||
#include "csync_owncloud_private.h"
|
||||
|
||||
#include "csync_misc.h"
|
||||
|
||||
void set_error_message( const char *msg )
|
||||
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg )
|
||||
{
|
||||
SAFE_FREE(dav_session.error_string);
|
||||
SAFE_FREE(ctx->dav_session.error_string);
|
||||
if( msg )
|
||||
dav_session.error_string = c_strdup(msg);
|
||||
ctx->dav_session.error_string = c_strdup(msg);
|
||||
}
|
||||
|
||||
void set_errno_from_http_errcode( int err ) {
|
||||
@@ -104,12 +106,12 @@ void set_errno_from_http_errcode( int err ) {
|
||||
errno = new_errno;
|
||||
}
|
||||
|
||||
int http_result_code_from_session() {
|
||||
const char *p = ne_get_error( dav_session.ctx );
|
||||
int http_result_code_from_session(csync_owncloud_ctx_t *ctx) {
|
||||
const char *p = ne_get_error( ctx->dav_session.ctx );
|
||||
char *q;
|
||||
int err;
|
||||
|
||||
set_error_message(p); /* remember the error message */
|
||||
set_error_message(ctx, p); /* remember the error message */
|
||||
|
||||
err = strtol(p, &q, 10);
|
||||
if (p == q) {
|
||||
@@ -118,8 +120,8 @@ int http_result_code_from_session() {
|
||||
return err;
|
||||
}
|
||||
|
||||
void set_errno_from_session() {
|
||||
int err = http_result_code_from_session();
|
||||
void set_errno_from_session(csync_owncloud_ctx_t *ctx) {
|
||||
int err = http_result_code_from_session(ctx);
|
||||
|
||||
if( err == EIO || err == ERRNO_ERROR_STRING) {
|
||||
errno = err;
|
||||
@@ -128,7 +130,7 @@ void set_errno_from_session() {
|
||||
}
|
||||
}
|
||||
|
||||
void set_errno_from_neon_errcode( int neon_code ) {
|
||||
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code ) {
|
||||
|
||||
if( neon_code != NE_OK ) {
|
||||
DEBUG_WEBDAV("Neon error code was %d", neon_code);
|
||||
@@ -137,7 +139,7 @@ void set_errno_from_neon_errcode( int neon_code ) {
|
||||
switch(neon_code) {
|
||||
case NE_OK: /* Success, but still the possiblity of problems */
|
||||
case NE_ERROR: /* Generic error; use ne_get_error(session) for message */
|
||||
set_errno_from_session(); /* Something wrong with http communication */
|
||||
set_errno_from_session(ctx); /* Something wrong with http communication */
|
||||
break;
|
||||
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
|
||||
errno = ERRNO_LOOKUP_ERROR;
|
||||
@@ -279,19 +281,9 @@ time_t oc_httpdate_parse( const char *date ) {
|
||||
/*
|
||||
* helper: convert a resource struct to file_stat struct.
|
||||
*/
|
||||
csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
|
||||
void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
|
||||
{
|
||||
csync_vio_file_stat_t *lfs = NULL;
|
||||
|
||||
if( ! res ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lfs = c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
if (lfs == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(lfs);
|
||||
|
||||
lfs->name = c_strdup( res->name );
|
||||
|
||||
@@ -312,30 +304,177 @@ csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
if( res->md5 ) {
|
||||
lfs->etag = c_strdup(res->md5);
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
||||
}
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
||||
|
||||
csync_vio_file_stat_set_file_id(lfs, res->file_id);
|
||||
|
||||
return lfs;
|
||||
}
|
||||
|
||||
/* WebDAV does not deliver permissions. Set a default here. */
|
||||
int _stat_perms( int type ) {
|
||||
int ret = 0;
|
||||
|
||||
if( type == CSYNC_VIO_FILE_TYPE_DIRECTORY ) {
|
||||
/* DEBUG_WEBDAV("Setting mode in stat (dir)"); */
|
||||
/* directory permissions */
|
||||
ret = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR /* directory, rwx for user */
|
||||
| S_IRGRP | S_IXGRP /* rx for group */
|
||||
| S_IROTH | S_IXOTH; /* rx for others */
|
||||
} else {
|
||||
/* regualar file permissions */
|
||||
/* DEBUG_WEBDAV("Setting mode in stat (file)"); */
|
||||
ret = S_IFREG | S_IRUSR | S_IWUSR /* regular file, user read & write */
|
||||
| S_IRGRP /* group read perm */
|
||||
| S_IROTH; /* others read perm */
|
||||
if (res->directDownloadUrl) {
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL;
|
||||
lfs->directDownloadUrl = c_strdup(res->directDownloadUrl);
|
||||
}
|
||||
if (res->directDownloadCookies) {
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES;
|
||||
lfs->directDownloadCookies = c_strdup(res->directDownloadCookies);
|
||||
}
|
||||
if (strlen(res->remotePerm) > 0) {
|
||||
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERM;
|
||||
strncpy(lfs->remotePerm, res->remotePerm, sizeof(lfs->remotePerm));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fill_webdav_properties_into_resource(struct resource* newres, const ne_prop_result_set *set)
|
||||
{
|
||||
const char *clength, *modtime, *file_id = NULL;
|
||||
const char *directDownloadUrl = NULL;
|
||||
const char *directDownloadCookies = NULL;
|
||||
const char *resourcetype = NULL;
|
||||
const char *etag = NULL;
|
||||
const char *perm = NULL;
|
||||
|
||||
modtime = ne_propset_value( set, &ls_props[0] );
|
||||
clength = ne_propset_value( set, &ls_props[1] );
|
||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||
etag = ne_propset_value( set, &ls_props[3] );
|
||||
file_id = ne_propset_value( set, &ls_props[4] );
|
||||
directDownloadUrl = ne_propset_value( set, &ls_props[5] );
|
||||
directDownloadCookies = ne_propset_value( set, &ls_props[6] );
|
||||
perm = ne_propset_value( set, &ls_props[7] );
|
||||
|
||||
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||
newres->type = resr_collection;
|
||||
} else {
|
||||
newres->type = resr_normal;
|
||||
}
|
||||
|
||||
if (modtime) {
|
||||
newres->modtime = oc_httpdate_parse(modtime);
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
|
||||
newres->size = 0;
|
||||
if (clength) {
|
||||
newres->size = atoll(clength);
|
||||
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
|
||||
}
|
||||
|
||||
if( etag ) {
|
||||
newres->md5 = csync_normalize_etag(etag);
|
||||
}
|
||||
|
||||
csync_vio_set_file_id(newres->file_id, file_id);
|
||||
/*
|
||||
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
|
||||
*/
|
||||
|
||||
if (directDownloadUrl) {
|
||||
newres->directDownloadUrl = c_strdup(directDownloadUrl);
|
||||
}
|
||||
if (directDownloadCookies) {
|
||||
newres->directDownloadCookies = c_strdup(directDownloadCookies);
|
||||
}
|
||||
if (perm && !perm[0]) {
|
||||
// special meaning for our code: server returned permissions but are empty
|
||||
// meaning only reading is allowed for this resource
|
||||
newres->remotePerm[0] = ' ';
|
||||
// see _csync_detect_update()
|
||||
} else if (perm && strlen(perm) < sizeof(newres->remotePerm)) {
|
||||
strncpy(newres->remotePerm, perm, sizeof(newres->remotePerm));
|
||||
} else {
|
||||
// old server, keep newres->remotePerm empty
|
||||
}
|
||||
}
|
||||
|
||||
struct resource* resource_dup(struct resource* o) {
|
||||
struct resource *r = c_malloc (sizeof( struct resource ));
|
||||
ZERO_STRUCTP(r);
|
||||
|
||||
r->uri = c_strdup(o->uri);
|
||||
r->name = c_strdup(o->name);
|
||||
r->type = o->type;
|
||||
r->size = o->size;
|
||||
r->modtime = o->modtime;
|
||||
if( o->md5 ) {
|
||||
r->md5 = c_strdup(o->md5);
|
||||
}
|
||||
if (o->directDownloadUrl) {
|
||||
r->directDownloadUrl = c_strdup(o->directDownloadUrl);
|
||||
}
|
||||
if (o->directDownloadCookies) {
|
||||
r->directDownloadCookies = c_strdup(o->directDownloadCookies);
|
||||
}
|
||||
if (o->remotePerm) {
|
||||
strncpy(r->remotePerm, o->remotePerm, sizeof(r->remotePerm));
|
||||
}
|
||||
r->next = o->next;
|
||||
csync_vio_set_file_id(r->file_id, o->file_id);
|
||||
|
||||
return r;
|
||||
}
|
||||
void resource_free(struct resource* o) {
|
||||
struct resource* old = NULL;
|
||||
while (o)
|
||||
{
|
||||
old = o;
|
||||
o = o->next;
|
||||
SAFE_FREE(old->uri);
|
||||
SAFE_FREE(old->name);
|
||||
SAFE_FREE(old->md5);
|
||||
SAFE_FREE(old->directDownloadUrl);
|
||||
SAFE_FREE(old->directDownloadCookies);
|
||||
SAFE_FREE(old);
|
||||
}
|
||||
}
|
||||
|
||||
void free_fetchCtx( struct listdir_context *ctx )
|
||||
{
|
||||
struct resource *newres, *res;
|
||||
if( ! ctx ) return;
|
||||
newres = ctx->list;
|
||||
res = newres;
|
||||
|
||||
ctx->ref--;
|
||||
if (ctx->ref > 0) return;
|
||||
|
||||
SAFE_FREE(ctx->target);
|
||||
|
||||
while( res ) {
|
||||
SAFE_FREE(res->uri);
|
||||
SAFE_FREE(res->name);
|
||||
SAFE_FREE(res->md5);
|
||||
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
|
||||
SAFE_FREE(res->directDownloadUrl);
|
||||
SAFE_FREE(res->directDownloadCookies);
|
||||
|
||||
newres = res->next;
|
||||
SAFE_FREE(res);
|
||||
res = newres;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
|
||||
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
|
||||
// extend as required
|
||||
const char* csync_owncloud_get_platform() {
|
||||
#if defined (_WIN32)
|
||||
return "Windows";
|
||||
#elif defined(__APPLE__)
|
||||
return "Macintosh";
|
||||
#elif defined(__gnu_linux__)
|
||||
return "Linux";
|
||||
#elif defined(__DragonFly__)
|
||||
/* might also define __FreeBSD__ */
|
||||
return "DragonFlyBSD";
|
||||
#elif defined(__FreeBSD__)
|
||||
return "FreeBSD";
|
||||
#elif defined(__NetBSD__)
|
||||
return "NetBSD";
|
||||
#elif defined(__OpenBSD__)
|
||||
return "OpenBSD";
|
||||
#elif defined(sun) || defined(__sun)
|
||||
return "Solaris";
|
||||
#else
|
||||
return "Unknown OS";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -61,18 +61,6 @@
|
||||
*/
|
||||
#define MAX_DEPTH 50
|
||||
|
||||
/**
|
||||
* Maximum time difference between two replicas in seconds
|
||||
*/
|
||||
#define MAX_TIME_DIFFERENCE 10
|
||||
|
||||
/**
|
||||
* Maximum size of a buffer for transfer
|
||||
*/
|
||||
#ifndef MAX_XFER_BUF_SIZE
|
||||
#define MAX_XFER_BUF_SIZE (16 * 1024)
|
||||
#endif
|
||||
|
||||
#define CSYNC_STATUS_INIT 1 << 0
|
||||
#define CSYNC_STATUS_UPDATE 1 << 1
|
||||
#define CSYNC_STATUS_RECONCILE 1 << 2
|
||||
@@ -90,6 +78,8 @@ enum csync_replica_e {
|
||||
|
||||
typedef struct csync_file_stat_s csync_file_stat_t;
|
||||
|
||||
struct csync_owncloud_ctx_s; // csync_owncloud.c
|
||||
|
||||
/**
|
||||
* @brief csync public structure
|
||||
*/
|
||||
@@ -104,7 +94,6 @@ struct csync_s {
|
||||
char *file;
|
||||
sqlite3 *db;
|
||||
int exists;
|
||||
int disabled;
|
||||
|
||||
sqlite3_stmt* by_hash_stmt;
|
||||
sqlite3_stmt* by_fileid_stmt;
|
||||
@@ -128,20 +117,11 @@ struct csync_s {
|
||||
c_list_t *ignored_cleanup;
|
||||
} remote;
|
||||
|
||||
struct {
|
||||
int sync_symbolic_links;
|
||||
char *config_dir;
|
||||
bool local_only_mode;
|
||||
int timeout;
|
||||
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
|
||||
iconv_t iconv_cd;
|
||||
#endif
|
||||
} options;
|
||||
|
||||
struct {
|
||||
uid_t uid;
|
||||
uid_t euid;
|
||||
} pwd;
|
||||
iconv_t iconv_cd;
|
||||
} options;
|
||||
#endif
|
||||
|
||||
/* replica we are currently walking */
|
||||
enum csync_replica_e current;
|
||||
@@ -162,6 +142,8 @@ struct csync_s {
|
||||
volatile int abort;
|
||||
void *rename_info;
|
||||
int read_from_db_disabled;
|
||||
|
||||
struct csync_owncloud_ctx_s *owncloud_context;
|
||||
};
|
||||
|
||||
|
||||
@@ -174,8 +156,6 @@ struct csync_file_stat_s {
|
||||
int64_t size; /* u64 */
|
||||
size_t pathlen; /* u64 */
|
||||
uint64_t inode; /* u64 */
|
||||
uid_t uid; /* u32 */
|
||||
gid_t gid; /* u32 */
|
||||
mode_t mode; /* u32 */
|
||||
int nlink; /* u32 */
|
||||
int type; /* u32 */
|
||||
@@ -185,6 +165,10 @@ struct csync_file_stat_s {
|
||||
char *destpath; /* for renames */
|
||||
const char *etag;
|
||||
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
|
||||
char *directDownloadUrl;
|
||||
char *directDownloadCookies;
|
||||
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
|
||||
|
||||
CSYNC_STATUS error_status;
|
||||
|
||||
enum csync_instructions_e instruction; /* u32 */
|
||||
|
||||
@@ -184,6 +184,7 @@ 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_etag = true;
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
other->instruction = CSYNC_INSTRUCTION_RENAME;
|
||||
@@ -193,6 +194,7 @@ 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_etag = 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!");
|
||||
|
||||
@@ -58,28 +58,6 @@ int csync_get_statedb_exists(CSYNC *ctx) {
|
||||
return ctx->statedb.exists;
|
||||
}
|
||||
|
||||
/* Set the hide attribute in win32. That makes it invisible in normal explorers */
|
||||
static void _csync_win32_hide_file( const char *file ) {
|
||||
#ifdef _WIN32
|
||||
mbchar_t *fileName;
|
||||
DWORD dwAttrs;
|
||||
|
||||
if( !file ) return;
|
||||
|
||||
fileName = c_utf8_to_locale( file );
|
||||
dwAttrs = GetFileAttributesW(fileName);
|
||||
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
}
|
||||
}
|
||||
c_free_locale_string(fileName);
|
||||
#else
|
||||
(void) file;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _csync_check_db_integrity(sqlite3 *db) {
|
||||
c_strlist_t *result = NULL;
|
||||
int rc = -1;
|
||||
@@ -168,7 +146,7 @@ static int _csync_statedb_check(const char *statedb) {
|
||||
rc = sqlite3_open(statedb, &db);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_close(db);
|
||||
_csync_win32_hide_file(statedb);
|
||||
csync_win32_set_file_hidden(statedb, true);
|
||||
return 1;
|
||||
}
|
||||
sqlite3_close(db);
|
||||
@@ -322,8 +300,6 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
|
||||
name = (const char*) sqlite3_column_text(stmt, 2);
|
||||
memcpy((*st)->path, (len ? name : ""), len + 1);
|
||||
(*st)->inode = sqlite3_column_int64(stmt,3);
|
||||
(*st)->uid = sqlite3_column_int(stmt, 4);
|
||||
(*st)->gid = sqlite3_column_int(stmt, 5);
|
||||
(*st)->mode = sqlite3_column_int(stmt, 6);
|
||||
(*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
|
||||
|
||||
@@ -337,6 +313,11 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
|
||||
if(column_count > 10 && sqlite3_column_text(stmt,10)) {
|
||||
csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
|
||||
}
|
||||
if(column_count > 11 && sqlite3_column_text(stmt,11)) {
|
||||
strncpy((*st)->remotePerm,
|
||||
(char*) sqlite3_column_text(stmt, 11),
|
||||
REMOTE_PERM_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -476,7 +457,7 @@ char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid FROM metadata WHERE path LIKE(?)"
|
||||
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM metadata WHERE path LIKE(?)"
|
||||
|
||||
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
int rc;
|
||||
|
||||
@@ -254,20 +254,22 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||
goto out;
|
||||
}
|
||||
bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
|
||||
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|
||||
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
|
||||
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
|
||||
&& c_streq(fs->file_id, tmp->file_id) && !ctx->read_from_db_disabled) {
|
||||
&& !metadata_differ && !ctx->read_from_db_disabled) {
|
||||
/* If both etag and file id are equal for a directory, read all contents from
|
||||
* the database.
|
||||
* The comparison of file id ensure that we fetch all the file id when upgrading from
|
||||
* owncloud 5 to owncloud 6.
|
||||
* The metadata comparison ensure that we fetch all the file id or permission when
|
||||
* upgrading owncloud
|
||||
*/
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
|
||||
ctx->remote.read_from_db = true;
|
||||
}
|
||||
|
||||
if (!c_streq(fs->file_id, tmp->file_id) && ctx->current == REMOTE_REPLICA) {
|
||||
/* file id has changed. Which means we need to update the DB.
|
||||
* (upgrade from owncloud 5 to owncloud 6 for instence) */
|
||||
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_etag = true;
|
||||
}
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
@@ -364,8 +366,6 @@ out:
|
||||
st->mode = fs->mode;
|
||||
st->size = fs->size;
|
||||
st->modtime = fs->mtime;
|
||||
st->uid = fs->uid;
|
||||
st->gid = fs->gid;
|
||||
st->nlink = fs->nlink;
|
||||
st->type = type;
|
||||
st->etag = NULL;
|
||||
@@ -374,6 +374,17 @@ out:
|
||||
st->etag = c_strdup(fs->etag);
|
||||
}
|
||||
csync_vio_set_file_id(st->file_id, fs->file_id);
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
|
||||
SAFE_FREE(st->directDownloadUrl);
|
||||
st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
|
||||
}
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
|
||||
SAFE_FREE(st->directDownloadCookies);
|
||||
st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
|
||||
}
|
||||
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
|
||||
strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
|
||||
}
|
||||
|
||||
fastout: /* target if the file information is read from database into st */
|
||||
st->phash = h;
|
||||
@@ -589,9 +600,14 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* == see if really stat has to be called. */
|
||||
fs = csync_vio_file_stat_new();
|
||||
res = csync_vio_stat(ctx, filename, fs);
|
||||
/* Only for the local replica we have to stat(), for the remote one we have all data already */
|
||||
if (ctx->replica == LOCAL_REPLICA) {
|
||||
fs = csync_vio_file_stat_new();
|
||||
res = csync_vio_stat(ctx, filename, fs);
|
||||
} else {
|
||||
fs = dirent;
|
||||
res = 0;
|
||||
}
|
||||
|
||||
if( res == 0) {
|
||||
switch (fs->type) {
|
||||
@@ -646,7 +662,10 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
previous_fs->child_modified = ctx->current_fs->child_modified;
|
||||
}
|
||||
|
||||
csync_vio_file_stat_destroy(fs);
|
||||
/* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */
|
||||
if (ctx->replica == LOCAL_REPLICA) {
|
||||
csync_vio_file_stat_destroy(fs);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
||||
@@ -674,8 +693,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
|
||||
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->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
|
||||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW)) {
|
||||
ctx->current_fs->should_update_etag = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,59 +128,6 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
|
||||
csync_vio_file_stat_t *vfs = NULL;
|
||||
|
||||
if (st == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vfs = csync_vio_file_stat_new();
|
||||
if (vfs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
vfs->acl = NULL;
|
||||
if (st->pathlen > 0) {
|
||||
vfs->name = c_strdup(st->path);
|
||||
}
|
||||
vfs->uid = st->uid;
|
||||
vfs->gid = st->gid;
|
||||
|
||||
vfs->atime = 0;
|
||||
vfs->mtime = st->modtime;
|
||||
vfs->ctime = 0;
|
||||
|
||||
vfs->size = st->size;
|
||||
vfs->blksize = 0; /* Depricated. */
|
||||
vfs->blkcount = 0;
|
||||
|
||||
vfs->mode = st->mode;
|
||||
vfs->device = 0;
|
||||
vfs->inode = st->inode;
|
||||
vfs->nlink = st->nlink;
|
||||
|
||||
/* fields. */
|
||||
vfs->fields = CSYNC_VIO_FILE_STAT_FIELDS_TYPE
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_INODE
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_SIZE
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_MTIME
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_UID
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_GID;
|
||||
|
||||
if (st->type == CSYNC_FTW_TYPE_DIR)
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
|
||||
else if (st->type == CSYNC_FTW_TYPE_FILE)
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
else if (st->type == CSYNC_FTW_TYPE_SLINK)
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
|
||||
else
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
|
||||
return vfs;
|
||||
}
|
||||
|
||||
bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
|
||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
|
||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
|
||||
|
||||
@@ -32,8 +32,5 @@ void csync_memstat_check(void);
|
||||
|
||||
void csync_win32_set_file_hidden( const char *file, bool hidden );
|
||||
|
||||
/* Convert a csync_file_stat_t to csync_vio_file_stat_t */
|
||||
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st);
|
||||
|
||||
bool csync_file_locked_or_open( const char *dir, const char *fname);
|
||||
#endif /* _CSYNC_UTIL_H */
|
||||
|
||||
@@ -20,8 +20,6 @@ set(CSTDLIB_LINK_LIBRARIES
|
||||
|
||||
set(cstdlib_SRCS
|
||||
c_alloc.c
|
||||
c_dir.c
|
||||
c_file.c
|
||||
c_list.c
|
||||
c_path.c
|
||||
c_rbtree.c
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_private.h"
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_dir.h"
|
||||
#include "c_string.h"
|
||||
|
||||
int c_mkdirs(const char *path, mode_t mode) {
|
||||
int tmp;
|
||||
csync_stat_t sb;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
mbchar_t *swpath = NULL;
|
||||
|
||||
if (path == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_tstat(wpath, &sb) == 0) {
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = strlen(path);
|
||||
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
|
||||
while(tmp > 0 && path[tmp - 1] != '/') --tmp;
|
||||
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
|
||||
|
||||
if (tmp > 0) {
|
||||
char subpath[tmp + 1];
|
||||
memcpy(subpath, path, tmp);
|
||||
subpath[tmp] = '\0';
|
||||
swpath = c_utf8_to_locale(subpath);
|
||||
if (_tstat(swpath, &sb) == 0) {
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
c_free_locale_string(swpath);
|
||||
c_free_locale_string(wpath);
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
} else if (errno != ENOENT) {
|
||||
c_free_locale_string(wpath);
|
||||
c_free_locale_string(swpath);
|
||||
return -1;
|
||||
} else if (c_mkdirs(subpath, mode) < 0) {
|
||||
c_free_locale_string(swpath);
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
tmp = _tmkdir(wpath, mode);
|
||||
|
||||
c_free_locale_string(swpath);
|
||||
c_free_locale_string(wpath);
|
||||
|
||||
if ((tmp < 0) && (errno == EEXIST)) {
|
||||
return 0;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int c_rmdirs(const char *path) {
|
||||
_TDIR *d;
|
||||
struct _tdirent *dp;
|
||||
csync_stat_t sb;
|
||||
char *fname = NULL;
|
||||
mbchar_t *wfname = NULL;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
char *rd_name = NULL;
|
||||
|
||||
if ((d = _topendir(wpath)) != NULL) {
|
||||
while( _tstat(wpath, &sb) == 0) {
|
||||
/* if we can remove the directory we're done */
|
||||
if (_trmdir(wpath) == 0) {
|
||||
break;
|
||||
}
|
||||
switch (errno) {
|
||||
case ENOTEMPTY:
|
||||
case EEXIST:
|
||||
case EBADF:
|
||||
break; /* continue */
|
||||
default:
|
||||
_tclosedir(d);
|
||||
c_free_locale_string(wpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((dp = _treaddir(d)) != NULL) {
|
||||
size_t len;
|
||||
rd_name = c_utf8_from_locale(dp->d_name);
|
||||
/* skip '.' and '..' */
|
||||
if( c_streq( rd_name, "." ) || c_streq( rd_name, ".." ) ) {
|
||||
c_free_locale_string(rd_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
len = strlen(path) + strlen(rd_name) + 2;
|
||||
fname = c_malloc(len);
|
||||
if (fname == NULL) {
|
||||
_tclosedir(d);
|
||||
c_free_locale_string(rd_name);
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
snprintf(fname, len, "%s/%s", path, rd_name);
|
||||
wfname = c_utf8_to_locale(fname);
|
||||
|
||||
/* stat the file */
|
||||
if (_tstat(wfname, &sb) != -1) {
|
||||
#ifdef __unix__
|
||||
if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
|
||||
#else
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
#endif
|
||||
if (_trmdir(wfname) < 0) { /* can't be deleted */
|
||||
if (errno == EACCES) {
|
||||
_tclosedir(d);
|
||||
SAFE_FREE(fname);
|
||||
c_free_locale_string(wfname);
|
||||
c_free_locale_string(rd_name);
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
c_rmdirs(fname);
|
||||
}
|
||||
} else {
|
||||
_tunlink(wfname);
|
||||
}
|
||||
} /* lstat */
|
||||
SAFE_FREE(fname);
|
||||
c_free_locale_string(wfname);
|
||||
c_free_locale_string(rd_name);
|
||||
} /* readdir */
|
||||
|
||||
_trewinddir(d);
|
||||
}
|
||||
} else {
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
c_free_locale_string(wpath);
|
||||
_tclosedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_isdir(const char *path) {
|
||||
csync_stat_t sb;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
int re = 0;
|
||||
|
||||
if (path != NULL) {
|
||||
if (_tstat (wpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
re = 1;
|
||||
}
|
||||
}
|
||||
c_free_locale_string(wpath);
|
||||
return re;
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_dir.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc directory function
|
||||
*
|
||||
* @defgroup cynDirInternals cynapses libc directory functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_DIR_H
|
||||
#define _C_DIR_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create parent directories as needed.
|
||||
*
|
||||
* The newly created directory will be owned by the effective user ID of the
|
||||
* process.
|
||||
*
|
||||
* @param path The path to the directory to create.
|
||||
*
|
||||
* @param mode Specifies the permissions to use. It is modified
|
||||
* by the process's umask in the usual way: the
|
||||
* permissions of the created file are (mode & ~umask).
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set:
|
||||
* - EACCES The parent directory does not allow write
|
||||
* permission to the process, or one of the directories
|
||||
* - ENOTDIR if durl is not a directory
|
||||
* - EINVAL NULL durl passed or smbc_init not called.
|
||||
* - ENOMEM Insufficient memory was available.
|
||||
*
|
||||
* @see mkdir()
|
||||
*/
|
||||
int c_mkdirs(const char *path, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Remove the directory and subdirectories including the content.
|
||||
*
|
||||
* This removes all directories and files recursivly.
|
||||
*
|
||||
* @param dir The directory to remove recusively.
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set.
|
||||
*/
|
||||
int c_rmdirs(const char *dir);
|
||||
|
||||
/**
|
||||
* @brief Check if a path is a directory.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a directory, 0 if the path doesn't exist, is a
|
||||
* file or can't be accessed.
|
||||
*/
|
||||
int c_isdir(const char *path);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CDIR_H */
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "c_file.h"
|
||||
#include "c_string.h"
|
||||
|
||||
#include "c_private.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
/* check if path is a symlink */
|
||||
int c_islink(const char *path) {
|
||||
int re = 0;
|
||||
|
||||
mbchar_t *wpath = 0;
|
||||
DWORD dwAttrs;
|
||||
WIN32_FIND_DATAW FindFileData;
|
||||
HANDLE hFind;
|
||||
|
||||
wpath = c_utf8_to_locale(path);
|
||||
|
||||
dwAttrs = GetFileAttributesW(wpath);
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
|
||||
if ((dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
hFind = FindFirstFileW(wpath, &FindFileData );
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
if( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
(FindFileData.dwReserved0 & IO_REPARSE_TAG_SYMLINK) ) {
|
||||
re = 1;
|
||||
}
|
||||
}
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
c_free_locale_string(wpath);
|
||||
return re;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if path is a file */
|
||||
int c_isfile(const char *path) {
|
||||
csync_stat_t sb;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
|
||||
int re = _tstat(wpath, &sb);
|
||||
c_free_locale_string(wpath);
|
||||
|
||||
if (re< 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __unix__
|
||||
if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
|
||||
#else
|
||||
if (S_ISREG(sb.st_mode)) {
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy file from src to dst, overwrites dst */
|
||||
#ifdef _WIN32
|
||||
int c_copy(const char* src, const char *dst, mode_t mode) {
|
||||
int rc = -1;
|
||||
mbchar_t *wsrc = 0;
|
||||
mbchar_t *wdst = 0;
|
||||
(void) mode; /* unused on win32 */
|
||||
if(src && dst) {
|
||||
wsrc = c_utf8_to_locale(src);
|
||||
wdst = c_utf8_to_locale(dst);
|
||||
if (CopyFileW(wsrc, wdst, FALSE)) {
|
||||
rc = 0;
|
||||
}
|
||||
c_free_locale_string(wsrc);
|
||||
c_free_locale_string(wdst);
|
||||
if( rc < 0 ) {
|
||||
errno = GetLastError();
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
int c_copy(const char* src, const char *dst, mode_t mode) {
|
||||
int srcfd = -1;
|
||||
int dstfd = -1;
|
||||
int rc = -1;
|
||||
ssize_t bread, bwritten;
|
||||
csync_stat_t sb;
|
||||
char buf[4096];
|
||||
|
||||
if (c_streq(src, dst)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
srcfd = open(src, O_RDONLY, 0);
|
||||
if (srcfd < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _tfstat(srcfd, &sb);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
errno = EISDIR;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
mode = sb.st_mode;
|
||||
}
|
||||
|
||||
dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
|
||||
if (dstfd < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _tfstat(dstfd, &sb);
|
||||
if (rc == 0) {
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
errno = EISDIR;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bread = read(srcfd, buf, sizeof(buf));
|
||||
if (bread == 0) {
|
||||
/* done */
|
||||
break;
|
||||
} else if (bread < 0) {
|
||||
errno = ENODATA;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bwritten = write(dstfd, buf, bread);
|
||||
if (bwritten < 0) {
|
||||
errno = ENODATA;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bread != bwritten) {
|
||||
errno = EFAULT;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __unix__
|
||||
fsync(dstfd);
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (srcfd >= 0) {
|
||||
close(srcfd);
|
||||
}
|
||||
if (dstfd >= 0) {
|
||||
close(dstfd);
|
||||
}
|
||||
if (rc < 0 && c_isfile(dst)) {
|
||||
unlink(dst);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int c_rename( const char *src, const char *dst ) {
|
||||
mbchar_t *nuri = NULL;
|
||||
mbchar_t *ouri = NULL;
|
||||
int rc = 0;
|
||||
|
||||
nuri = c_utf8_to_locale(dst);
|
||||
if (nuri == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ouri = c_utf8_to_locale(src);
|
||||
if (ouri == NULL) {
|
||||
c_free_locale_string(nuri);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
#define MAX_TRIES_RENAME 3
|
||||
int err = 0;
|
||||
int cnt = 0;
|
||||
|
||||
do {
|
||||
BOOL ok;
|
||||
ok = MoveFileExW(ouri,
|
||||
nuri,
|
||||
MOVEFILE_COPY_ALLOWED +
|
||||
MOVEFILE_REPLACE_EXISTING +
|
||||
MOVEFILE_WRITE_THROUGH);
|
||||
if (!ok) {
|
||||
/* error */
|
||||
err = GetLastError();
|
||||
if( (err == ERROR_ACCESS_DENIED ||
|
||||
err == ERROR_LOCK_VIOLATION ||
|
||||
err == ERROR_SHARING_VIOLATION) && cnt < MAX_TRIES_RENAME ) {
|
||||
cnt++;
|
||||
Sleep(cnt*100);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} while( 1 );
|
||||
if( err != 0 ) {
|
||||
errno = err;
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
rc = rename(ouri, nuri);
|
||||
#endif
|
||||
|
||||
c_free_locale_string(nuri);
|
||||
c_free_locale_string(ouri);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int c_compare_file( const char *f1, const char *f2 ) {
|
||||
mbchar_t *wf1, *wf2;
|
||||
int fd1 = -1, fd2 = -1;
|
||||
size_t size1, size2;
|
||||
char buffer1[BUFFER_SIZE];
|
||||
char buffer2[BUFFER_SIZE];
|
||||
csync_stat_t stat1;
|
||||
csync_stat_t stat2;
|
||||
|
||||
int rc = -1;
|
||||
|
||||
if(f1 == NULL || f2 == NULL) return -1;
|
||||
|
||||
wf1 = c_utf8_to_locale(f1);
|
||||
if(wf1 == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wf2 = c_utf8_to_locale(f2);
|
||||
if(wf2 == NULL) {
|
||||
c_free_locale_string(wf1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_fmode = _O_BINARY;
|
||||
#endif
|
||||
|
||||
fd1 = _topen(wf1, O_RDONLY);
|
||||
if(fd1 < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd2 = _topen(wf2, O_RDONLY);
|
||||
if(fd2 < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* compare size first. */
|
||||
rc = _tfstat(fd1, &stat1);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _tfstat(fd2, &stat2);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if sizes are different, the files can not be equal. */
|
||||
if (stat1.st_size != stat2.st_size) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while( (size1 = read(fd1, buffer1, BUFFER_SIZE)) > 0 ) {
|
||||
size2 = read( fd2, buffer2, BUFFER_SIZE );
|
||||
|
||||
if( size1 != size2 ) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
if(memcmp(buffer1, buffer2, size1) != 0) {
|
||||
/* buffers are different */
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
|
||||
out:
|
||||
|
||||
if(fd1 > -1) close(fd1);
|
||||
if(fd2 > -1) close(fd2);
|
||||
|
||||
c_free_locale_string( wf1 );
|
||||
c_free_locale_string( wf2 );
|
||||
return rc;
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_file.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc file function
|
||||
*
|
||||
* @defgroup cynFileInternals cynapses libc file functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_FILE_H
|
||||
#define _C_FILE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef BUFFER_SIZE
|
||||
#define BUFFER_SIZE (16 * 1024)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief Check if a path is a link.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a symbolic link, 0 if the path doesn't
|
||||
* exist or is something else.
|
||||
*/
|
||||
int c_islink(const char *path);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Check if a path is a regular file or a link.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a file, 0 if the path doesn't exist, is
|
||||
* something else or can't be accessed.
|
||||
*/
|
||||
int c_isfile(const char *path);
|
||||
|
||||
/**
|
||||
* @brief copy a file from source to destination.
|
||||
*
|
||||
* @param src Path to the source file
|
||||
* @param dst Path to the destination file
|
||||
* @param mode File creation mode of the destination. If mode is 0 then the
|
||||
* mode from the source will be used.
|
||||
*
|
||||
* @return 0 on success, less than 0 on error with errno set.
|
||||
* EISDIR if src or dst is a file.
|
||||
*/
|
||||
int c_copy(const char *src, const char *dst, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Compare the content of two files byte by byte.
|
||||
* @param f1 Path of file 1
|
||||
* @param f2 Path of file 2
|
||||
*
|
||||
* @return 0 if the files differ, 1 if the files are equal or -1 on
|
||||
* error with errno set.
|
||||
*/
|
||||
int c_compare_file( const char *f1, const char *f2 );
|
||||
|
||||
/**
|
||||
* @brief move a file from source to destination.
|
||||
*
|
||||
* @param src Path to the source file
|
||||
* @param dst Path to the destination file
|
||||
*
|
||||
* @return 0 on success, less than 0 on error with errno set.
|
||||
*/
|
||||
int c_rename( const char *src, const char *dst );
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_FILE_H */
|
||||
|
||||
@@ -23,45 +23,9 @@
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_dir.h"
|
||||
#include "c_file.h"
|
||||
#include "c_list.h"
|
||||
#include "c_path.h"
|
||||
#include "c_rbtree.h"
|
||||
#include "c_string.h"
|
||||
#include "c_time.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#ifndef UNIT_TESTING
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#endif
|
||||
#define malloc(x) DO_NOT_CALL_MALLOC__USE_C_MALLOC_INSTEAD
|
||||
|
||||
#ifdef calloc
|
||||
#undef calloc
|
||||
#endif
|
||||
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_C_CALLOC_INSTEAD
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef realloc
|
||||
#undef realloc
|
||||
#endif
|
||||
#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_C_REALLOC_INSTEAD
|
||||
|
||||
#ifdef dirname
|
||||
#undef dirname
|
||||
#endif
|
||||
#define dirname(x) DO_NOT_CALL_MALLOC__USE_C_DIRNAME_INSTEAD
|
||||
|
||||
#ifdef basename
|
||||
#undef basename
|
||||
#endif
|
||||
#define basename(x) DO_NOT_CALL_MALLOC__USE_C_BASENAME_INSTEAD
|
||||
|
||||
#ifdef strdup
|
||||
#undef strdup
|
||||
#endif
|
||||
#define strdup(x) DO_NOT_CALL_STRDUP__USE_C_STRDUP_INSTEAD
|
||||
|
||||
|
||||
@@ -117,81 +117,6 @@ char *c_basename (const char *path) {
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
|
||||
char *c_tmpname(const char *templ) {
|
||||
char *tmp = NULL;
|
||||
char *target = NULL;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
||||
if (!templ) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If the template does not contain the XXXXXX it will be appended. */
|
||||
if( !strstr( templ, "XXXXXX" )) {
|
||||
/* split up the path */
|
||||
char *path = c_dirname(templ);
|
||||
char *base = c_basename(templ);
|
||||
|
||||
if (!base) {
|
||||
if (path) {
|
||||
SAFE_FREE(path);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
/* Create real hidden files for unixoide. */
|
||||
if( path ) {
|
||||
#ifdef _WIN32
|
||||
rc = asprintf(&target, "%s/%s.~XXXXXX", path, base);
|
||||
#else
|
||||
rc = asprintf(&target, "%s/.%s.~XXXXXX", path, base);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
rc = asprintf(&target, "%s.~XXXXXX", base);
|
||||
#else
|
||||
rc = asprintf(&target, ".%s.~XXXXXX", base);
|
||||
#endif
|
||||
|
||||
}
|
||||
SAFE_FREE(path);
|
||||
SAFE_FREE(base);
|
||||
|
||||
if (rc < 0) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
target = c_strdup(templ);
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
goto err;
|
||||
}
|
||||
tmp = strstr( target, "XXXXXX" );
|
||||
if (!tmp) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
#ifdef _WIN32
|
||||
/* in win32 MAX_RAND is 32767, thus we can not shift that far,
|
||||
* otherwise the last three chars are 0
|
||||
*/
|
||||
int hexdigit = (rand() >> (i * 2)) & 0x1f;
|
||||
#else
|
||||
int hexdigit = (rand() >> (i * 5)) & 0x1f;
|
||||
#endif
|
||||
tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
|
||||
}
|
||||
|
||||
return target;
|
||||
|
||||
err:
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int c_parse_uri(const char *uri,
|
||||
char **scheme,
|
||||
char **user, char **passwd,
|
||||
@@ -470,84 +395,3 @@ int c_parse_uri(const char *uri,
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* http://refactormycode.com/codes/1345-extracting-directory-filename-and-extension-from-a-path
|
||||
* Allocate a block of memory that holds the PATHINFO at the beginning
|
||||
* followed by the actual path. Two extra bytes are allocated (+3 instead
|
||||
* of just +1) to deal with shifting the filename and extension to protect the trailing '/'
|
||||
* and the leading '.'. These extra bytes also double as the empty string, as
|
||||
* well as a pad to keep from reading past the memory block.
|
||||
*
|
||||
*/
|
||||
C_PATHINFO * c_split_path(const char* pathSrc)
|
||||
{
|
||||
size_t length = strlen(pathSrc);
|
||||
size_t len=0;
|
||||
C_PATHINFO * pathinfo = (C_PATHINFO *) c_malloc(sizeof(C_PATHINFO) + length + 3);
|
||||
|
||||
if (pathinfo)
|
||||
{
|
||||
char * path = (char *) &pathinfo[1]; // copy of the path
|
||||
char * theEnd = &path[length + 1]; // second null terminator
|
||||
char * extension;
|
||||
char * lastSep;
|
||||
|
||||
// Copy the original string and double null terminate it.
|
||||
strcpy(path, pathSrc);
|
||||
*theEnd = '\0';
|
||||
pathinfo->directory = theEnd; // Assume no path
|
||||
pathinfo->extension = theEnd; // Assume no extension
|
||||
pathinfo->filename = path; // Assume filename only
|
||||
|
||||
lastSep = strrchr(path, '/');
|
||||
if (lastSep)
|
||||
{
|
||||
pathinfo->directory = path; // Pick up the path
|
||||
|
||||
memmove(lastSep + 1, lastSep, strlen(lastSep));
|
||||
*lastSep++ ='/';
|
||||
*lastSep++ ='\0'; // Truncate directory
|
||||
|
||||
pathinfo->filename = lastSep; // Pick up name after path
|
||||
}
|
||||
|
||||
// Start at the second character of the filename to handle
|
||||
// filenames that start with '.' like ".login".
|
||||
// We don't overrun the buffer in the cases of an empty path
|
||||
// or a path that looks like "/usr/bin/" because of the extra
|
||||
// byte.
|
||||
|
||||
|
||||
extension = strrchr(&pathinfo->filename[1], '.');
|
||||
if (extension)
|
||||
{
|
||||
// Shift the extension over to protect the leading '.' since
|
||||
// we need to truncate the filename.
|
||||
memmove(extension + 1, extension, strlen(extension));
|
||||
pathinfo->extension = extension + 1;
|
||||
|
||||
*extension = '\0'; // Truncate filename
|
||||
}
|
||||
else
|
||||
{
|
||||
len=strlen(pathinfo->filename);
|
||||
if(len>1)
|
||||
{
|
||||
//tmp files from kate/kwrite "somefile~": '~' should be the extension
|
||||
if(pathinfo->filename[len-1]=='~')
|
||||
{
|
||||
extension = &pathinfo->filename[len-1];
|
||||
memmove(extension + 1, extension, strlen(extension));
|
||||
pathinfo->extension = extension + 1;
|
||||
*extension = '\0'; // Truncate filename
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pathinfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,19 +66,6 @@ char *c_dirname(const char *path);
|
||||
*/
|
||||
char *c_basename (const char *path);
|
||||
|
||||
/**
|
||||
* @brief Make a temporary filename.
|
||||
*
|
||||
* @param templ The template to replace. If the template contains six X like
|
||||
* 'XXXXXX', these are replaced by a random string. If not, the
|
||||
* templ is interpreted as a path, and a name to a hidden file
|
||||
* with six random is returned.
|
||||
* The caller has to free the memory.
|
||||
*
|
||||
* @return a poitner to the random hidden filename or NULL.
|
||||
*/
|
||||
char *c_tmpname(const char *templ);
|
||||
|
||||
/**
|
||||
* @brief parse a uri and split it into components.
|
||||
*
|
||||
@@ -120,15 +107,6 @@ typedef struct
|
||||
char * extension;
|
||||
} C_PATHINFO;
|
||||
|
||||
/**
|
||||
* @brief Extracting directory, filename and extension from a path.
|
||||
*
|
||||
* @param pathSrc The path to parse.
|
||||
*
|
||||
* @return Returns a C_PATHINFO structure that should be freed using SAFE_FREE().
|
||||
*/
|
||||
C_PATHINFO * c_split_path(const char* pathSrc);
|
||||
|
||||
|
||||
/**
|
||||
* }@
|
||||
|
||||
@@ -239,69 +239,6 @@ void c_strlist_destroy(c_strlist_t *strlist) {
|
||||
SAFE_FREE(strlist);
|
||||
}
|
||||
|
||||
char *c_strreplace(char *src, const char *pattern, const char *repl) {
|
||||
char *p = NULL;
|
||||
|
||||
while ((p = strstr(src, pattern)) != NULL) {
|
||||
size_t of = p - src;
|
||||
size_t l = strlen(src);
|
||||
size_t pl = strlen(pattern);
|
||||
size_t rl = strlen(repl);
|
||||
|
||||
if (rl > pl) {
|
||||
src = (char *) c_realloc(src, strlen(src) + rl - pl + 1);
|
||||
}
|
||||
|
||||
if (rl != pl) {
|
||||
memmove(src + of + rl, src + of + pl, l - of - pl + 1);
|
||||
}
|
||||
|
||||
strncpy(src + of, repl, rl);
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
char *c_uppercase(const char* str) {
|
||||
char *new;
|
||||
char *p;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = c_strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = new; *p; p++) {
|
||||
*p = toupper(*p);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
char *c_lowercase(const char* str) {
|
||||
char *new;
|
||||
char *p;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = c_strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = new; *p; p++) {
|
||||
*p = tolower(*p);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Convert a wide multibyte String to UTF8 */
|
||||
char* c_utf8_from_locale(const mbchar_t *wstr)
|
||||
{
|
||||
|
||||
@@ -119,37 +119,6 @@ void c_strlist_clear(c_strlist_t *strlist);
|
||||
*/
|
||||
void c_strlist_destroy(c_strlist_t *strlist);
|
||||
|
||||
/**
|
||||
* @breif Replace a string with another string in a source string.
|
||||
*
|
||||
* @param src String to search for pattern.
|
||||
*
|
||||
* @param pattern Pattern to search for in the source string.
|
||||
*
|
||||
* @param repl The string which which should replace pattern if found.
|
||||
*
|
||||
* @return Return a pointer to the source string.
|
||||
*/
|
||||
char *c_strreplace(char *src, const char *pattern, const char *repl);
|
||||
|
||||
/**
|
||||
* @brief Uppercase a string.
|
||||
*
|
||||
* @param str The String to uppercase.
|
||||
*
|
||||
* @return The malloced uppered string or NULL on error.
|
||||
*/
|
||||
char *c_uppercase(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Lowercase a string.
|
||||
*
|
||||
* @param str The String to lowercase.
|
||||
*
|
||||
* @return The malloced lowered string or NULL on error.
|
||||
*/
|
||||
char *c_lowercase(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Convert a platform locale string to utf8.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_util.h"
|
||||
@@ -44,7 +45,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
|
||||
if(ctx->remote.read_from_db) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
|
||||
}
|
||||
return owncloud_opendir(name);
|
||||
return owncloud_opendir(ctx, name);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
return csync_vio_local_opendir(name);
|
||||
@@ -69,7 +70,7 @@ int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||
if( ctx->remote.read_from_db ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
|
||||
}
|
||||
rc = owncloud_closedir(dhandle);
|
||||
rc = owncloud_closedir(ctx, dhandle);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
rc = csync_vio_local_closedir(dhandle);
|
||||
@@ -87,7 +88,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
|
||||
if( ctx->remote.read_from_db ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
|
||||
}
|
||||
return owncloud_readdir(dhandle);
|
||||
return owncloud_readdir(ctx, dhandle);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
return csync_vio_local_readdir(dhandle);
|
||||
@@ -106,7 +107,8 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||
|
||||
switch(ctx->replica) {
|
||||
case REMOTE_REPLICA:
|
||||
rc = owncloud_stat(uri, buf);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
|
||||
assert(ctx->replica != REMOTE_REPLICA);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
rc = csync_vio_local_stat(uri, buf);
|
||||
@@ -121,21 +123,9 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *csync_vio_get_status_string(CSYNC *ctx) {
|
||||
if(ctx->error_string) {
|
||||
return ctx->error_string;
|
||||
}
|
||||
return owncloud_error_string();
|
||||
}
|
||||
|
||||
int csync_vio_set_property(CSYNC* ctx, const char* key, void* data) {
|
||||
(void) ctx;
|
||||
return owncloud_set_property(key, data);
|
||||
}
|
||||
|
||||
int csync_vio_commit(CSYNC *ctx) {
|
||||
(void) ctx;
|
||||
return owncloud_commit();
|
||||
return owncloud_error_string(ctx);
|
||||
}
|
||||
|
||||
@@ -39,10 +39,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
|
||||
|
||||
int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf);
|
||||
|
||||
int csync_vio_set_property(CSYNC *ctx, const char *key, void *data);
|
||||
|
||||
char *csync_vio_get_status_string(CSYNC *ctx);
|
||||
|
||||
int csync_vio_commit(CSYNC *ctx);
|
||||
|
||||
#endif /* _CSYNC_VIO_H */
|
||||
|
||||
@@ -22,14 +22,8 @@
|
||||
#include "vio/csync_vio_file_stat.h"
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||
csync_vio_file_stat_t *file_stat = NULL;
|
||||
|
||||
file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
if (file_stat == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
file_stat->etag = NULL;
|
||||
memset(file_stat->file_id, 0, FILE_ID_BUF_SIZE+1);
|
||||
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
ZERO_STRUCTP(file_stat);
|
||||
return file_stat;
|
||||
}
|
||||
|
||||
@@ -39,15 +33,11 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME) {
|
||||
SAFE_FREE(file_stat->u.symlink_name);
|
||||
}
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM) {
|
||||
SAFE_FREE(file_stat->u.checksum);
|
||||
}
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||
SAFE_FREE(file_stat->etag);
|
||||
}
|
||||
SAFE_FREE(file_stat->directDownloadUrl);
|
||||
SAFE_FREE(file_stat->directDownloadCookies);
|
||||
SAFE_FREE(file_stat->name);
|
||||
SAFE_FREE(file_stat);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
|
||||
#define FILE_ID_BUF_SIZE 21
|
||||
|
||||
// currently specified at https://github.com/owncloud/core/issues/8322 are 9 to 10
|
||||
#define REMOTE_PERM_BUF_SIZE 15
|
||||
|
||||
typedef struct csync_vio_file_stat_s csync_vio_file_stat_t;
|
||||
|
||||
enum csync_vio_file_flags_e {
|
||||
@@ -56,48 +59,44 @@ enum csync_vio_file_type_e {
|
||||
enum csync_vio_file_stat_fields_e {
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_NONE = 0,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS = 1 << 1,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_ATIME = 1 << 9,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_MTIME = 1 << 10,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_CTIME = 1 << 11,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
|
||||
// CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL = 1 << 19,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES = 1 << 20,
|
||||
CSYNC_VIO_FILE_STAT_FIELDS_PERM = 1 << 21 // remote oC perm
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct csync_vio_file_stat_s {
|
||||
union {
|
||||
char *symlink_name;
|
||||
char *checksum;
|
||||
} u;
|
||||
|
||||
void *acl;
|
||||
char *name;
|
||||
char *etag;
|
||||
char *etag; // FIXME: Should this be inlined like file_id and perm?
|
||||
char file_id[FILE_ID_BUF_SIZE+1];
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char *directDownloadUrl;
|
||||
char *directDownloadCookies;
|
||||
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
|
||||
|
||||
time_t atime;
|
||||
time_t mtime;
|
||||
time_t ctime;
|
||||
|
||||
int64_t size;
|
||||
int64_t blksize; /* will be removed in future, not used in csync */
|
||||
unsigned long blkcount; /* will be removed in future, not used in csync */
|
||||
|
||||
mode_t mode;
|
||||
|
||||
@@ -109,10 +108,6 @@ struct csync_vio_file_stat_s {
|
||||
enum csync_vio_file_type_e type;
|
||||
|
||||
enum csync_vio_file_flags_e flags;
|
||||
|
||||
void *reserved1;
|
||||
void *reserved2;
|
||||
void *reserved3;
|
||||
};
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void);
|
||||
|
||||
@@ -227,9 +227,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
|
||||
buf->mode = 666;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
|
||||
buf->device = fileInfo.dwVolumeSerialNumber;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE;
|
||||
|
||||
@@ -316,7 +313,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
|
||||
buf->mode = sb.st_mode;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE;
|
||||
|
||||
if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) {
|
||||
/* FIXME: handle symlink */
|
||||
@@ -332,11 +329,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->inode = sb.st_ino;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
|
||||
|
||||
/* Both values are only initialized to zero as they are not used in csync */
|
||||
/* They are deprecated and will be rmemoved later. */
|
||||
buf->blksize = 0;
|
||||
buf->blkcount = 0;
|
||||
|
||||
buf->atime = sb.st_atime;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
|
||||
|
||||
@@ -349,12 +341,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->nlink = sb.st_nlink;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
|
||||
|
||||
buf->uid = sb.st_uid;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID;
|
||||
|
||||
buf->gid = sb.st_gid;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID;
|
||||
|
||||
buf->size = sb.st_size;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ set(TEST_TARGET_LIBRARIES ${TORTURE_LIBRARY})
|
||||
|
||||
# std
|
||||
add_cmocka_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_dir std_tests/check_std_c_dir.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_file std_tests/check_std_c_file.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_list std_tests/check_std_c_list.c ${TEST_TARGET_LIBRARIES})
|
||||
add_cmocka_test(check_std_c_path std_tests/check_std_c_path.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
@@ -36,9 +36,6 @@ static void setup(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
@@ -55,9 +52,6 @@ static void setup_module(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_init(csync);
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ static void check_csync_destroy_null(void **state)
|
||||
static void check_csync_create(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
char confdir[1024] = {0};
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
@@ -46,9 +45,6 @@ static void check_csync_create(void **state)
|
||||
rc = csync_create(&csync, "/tmp/csync1", "/tmp/csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
snprintf(confdir, sizeof(confdir), "%s/%s", getenv("HOME"), CSYNC_CONF_DIR);
|
||||
assert_string_equal(csync->options.config_dir, confdir);
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
@@ -32,10 +32,6 @@ static void setup(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
free(csync->options.config_dir);
|
||||
csync->options.config_dir = c_strdup("/tmp/check_csync1/");
|
||||
assert_non_null(csync->options.config_dir);
|
||||
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
@@ -46,10 +42,6 @@ static void setup_init(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
free(csync->options.config_dir);
|
||||
csync->options.config_dir = c_strdup("/tmp/check_csync1/");
|
||||
assert_non_null(csync->options.config_dir);
|
||||
|
||||
rc = csync_exclude_load(csync, SOURCEDIR "/../sync-exclude.lst");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
|
||||
@@ -36,9 +36,6 @@ static void setup(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
@@ -55,9 +52,6 @@ static void setup_module(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,6 @@ static void setup(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ static void setup(void **state) {
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_set_config_dir(csync, "/tmp/check_csync1/");
|
||||
|
||||
csync->statedb.file = c_strdup( TESTDB );
|
||||
*state = csync;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync/");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_init(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_init(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
|
||||
@@ -60,8 +58,6 @@ static void setup_ftw(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_create(&csync, "/tmp", "/tmp");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_set_config_dir(csync, "/tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_init(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
|
||||
@@ -124,8 +120,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
|
||||
fs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
|
||||
fs->mode = 0644;
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
|
||||
if (inode == 0) {
|
||||
fs->inode = 619070;
|
||||
@@ -146,17 +140,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
|
||||
}
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
|
||||
|
||||
fs->uid = 1000;
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID;
|
||||
|
||||
fs->gid = 1000;
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID;
|
||||
|
||||
fs->blkcount = 312;
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT;
|
||||
|
||||
fs->blksize = 4096;
|
||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE;
|
||||
|
||||
if (mtime == 0) {
|
||||
fs->atime = fs->ctime = fs->mtime = time(&t);
|
||||
|
||||
@@ -34,6 +34,7 @@ use LWP::UserAgent;
|
||||
use LWP::Protocol::https;
|
||||
use HTTP::Request::Common qw( POST GET DELETE );
|
||||
use File::Basename;
|
||||
use IO::Handle;
|
||||
|
||||
use Encode qw(from_to);
|
||||
use utf8;
|
||||
@@ -60,7 +61,7 @@ our $infoCnt = 1;
|
||||
our %config;
|
||||
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT = qw( initTesting createRemoteDir createLocalDir cleanup csync
|
||||
@EXPORT = qw( initTesting createRemoteDir removeRemoteDir createLocalDir cleanup csync
|
||||
assertLocalDirs assertLocalAndRemoteDir glob_put put_to_dir
|
||||
putToDirLWP localDir remoteDir localCleanup createLocalFile md5OfFile
|
||||
remoteCleanup server initLocalDir initRemoteDir moveRemoteFile
|
||||
@@ -179,6 +180,32 @@ sub initLocalDir
|
||||
mkdir ($localDir, 0777 );
|
||||
}
|
||||
|
||||
sub removeRemoteDir($;$)
|
||||
{
|
||||
my ($dir, $optionsRef) = @_;
|
||||
|
||||
my $url = testDirUrl() . $dir;
|
||||
|
||||
if( $optionsRef && $optionsRef->{user} && $optionsRef->{passwd} ) {
|
||||
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
|
||||
-user=> $optionsRef->{user},
|
||||
-pass=> $optionsRef->{passwd} );
|
||||
if( $optionsRef->{url} ) {
|
||||
$url = $optionsRef->{url} . $dir;
|
||||
}
|
||||
}
|
||||
|
||||
$d->open( $owncloud );
|
||||
print $d->message . "\n";
|
||||
|
||||
my $re = $d->delete( $url );
|
||||
if( $re == 0 ) {
|
||||
print "Failed to remove directory <$url>:" . $d->message() ."\n";
|
||||
}
|
||||
|
||||
return $re;
|
||||
}
|
||||
|
||||
sub createRemoteDir(;$$)
|
||||
{
|
||||
my ($dir, $optionsRef) = @_;
|
||||
@@ -199,7 +226,7 @@ sub createRemoteDir(;$$)
|
||||
|
||||
my $re = $d->mkcol( $url );
|
||||
if( $re == 0 ) {
|
||||
print "Failed to create directory <$url>: $d->message() \n";
|
||||
print "Failed to create directory <$url>: " . $d->message() ."\n";
|
||||
exit 1;
|
||||
}
|
||||
$d->open( $url );
|
||||
@@ -577,7 +604,7 @@ sub createLocalFile( $$ )
|
||||
my $minimum = 32;
|
||||
my $range = 96;
|
||||
|
||||
for (my $bytes = 0; $bytes < $size; $bytes += 4) {
|
||||
for (my $bytes = 0; $bytes < $size-1; $bytes += 4) {
|
||||
my $rand = int(rand($range ** 4));
|
||||
my $string = '';
|
||||
for (1..4) {
|
||||
@@ -587,6 +614,9 @@ sub createLocalFile( $$ )
|
||||
print FILE $string;
|
||||
$md5->add($string);
|
||||
}
|
||||
my $s = "\n";
|
||||
print FILE $s;
|
||||
$md5->add($s);
|
||||
close FILE;
|
||||
return $md5->hexdigest;
|
||||
}
|
||||
@@ -605,13 +635,22 @@ sub md5OfFile( $ )
|
||||
return $hash;
|
||||
}
|
||||
|
||||
sub moveRemoteFile($$)
|
||||
sub moveRemoteFile($$;$)
|
||||
{
|
||||
my ($from, $to) = @_;
|
||||
|
||||
my ($from, $to, $no_testdir) = @_;
|
||||
|
||||
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
|
||||
-user=> $user,
|
||||
-pass=> $passwd );
|
||||
|
||||
my $fromUrl = testDirUrl(). $from;
|
||||
my $toUrl = testDirUrl() . $to;
|
||||
|
||||
if( $no_testdir ) {
|
||||
$fromUrl = $from;
|
||||
$toUrl = $to;
|
||||
}
|
||||
|
||||
$d->move($fromUrl, $toUrl);
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ glob_put( 'toremote1/rtl1/rtl11/*', "remoteToLocal1/rtl1/rtl11/" );
|
||||
glob_put( 'toremote1/rtl2/*', "remoteToLocal1/rtl2/" );
|
||||
glob_put( 'toremote1/rtl4/*', "remoteToLocal1/rtl4/" );
|
||||
|
||||
|
||||
# call csync, sync local t1 to remote t1
|
||||
csync();
|
||||
|
||||
@@ -74,9 +75,19 @@ foreach my $file ( <./tolocal1/*> ) {
|
||||
print "Copying $file to $locDir\n";
|
||||
copy( $file, $locDir );
|
||||
}
|
||||
|
||||
# Also add a file with symbols
|
||||
my $symbolName = "a\%b#c\$d-e";
|
||||
system( "echo \"my symbols\" >> $locDir/$symbolName" );
|
||||
|
||||
#Also on the server
|
||||
put_to_dir( "$locDir/$symbolName", 'remoteToLocal1' );
|
||||
|
||||
|
||||
csync( );
|
||||
print "\nAssert local and remote dirs.\n";
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
assert( ! -e localDir().$symbolName );
|
||||
|
||||
# move a local file
|
||||
printInfo( "Move a file locally." );
|
||||
@@ -112,8 +123,9 @@ assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
# The previous sync should have updated the etags, and this should NOT be a conflict
|
||||
printInfo( "Update the file again");
|
||||
system("echo more data >> " . localDir() . "remoteToLocal1/kernelcrash.txt");
|
||||
system("echo corruption >> " . localDir() . "remoteToLocal1/kraft_logo.gif");
|
||||
createLocalFile( localDir() . "remoteToLocal1/kernelcrash.txt", 2136 );
|
||||
createLocalFile( localDir() . "remoteToLocal1/kraft_logo.gif", 2332 );
|
||||
system( "sleep 2 && touch " . localDir() . "remoteToLocal1/kernelcrash.txt" );
|
||||
csync( );
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
@@ -185,12 +185,35 @@ assertLocalAndRemoteDir( 'remoteToLocal1', 1);
|
||||
printInfo("Move a file from the server");
|
||||
$inode = getInode('remoteToLocal1/rtl2/kb1_local_gone.jpg');
|
||||
moveRemoteFile( 'remoteToLocal1/rtl2/kb1_local_gone.jpg', 'remoteToLocal1/rtl2/kb1_local_gone2.jpg');
|
||||
|
||||
#also create a new directory localy for the next test
|
||||
mkdir( localDir().'superNewDir' );
|
||||
createLocalFile(localDir(). 'superNewDir/f1', 1234 );
|
||||
createLocalFile(localDir(). 'superNewDir/f2', 1324 );
|
||||
my $superNewDirInode = getInode('superNewDir');
|
||||
|
||||
|
||||
csync();
|
||||
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
|
||||
assertLocalAndRemoteDir( '', 1);
|
||||
$inode2 = getInode('remoteToLocal1/rtl2/kb1_local_gone2.jpg');
|
||||
assert( $inode == $inode2, "Inode has changed 3!");
|
||||
|
||||
|
||||
printInfo("Move a newly created directory");
|
||||
moveRemoteFile('superNewDir', 'superNewDirRenamed');
|
||||
#also add new files in new directory
|
||||
createLocalFile(localDir(). 'superNewDir/f3' , 2456 );
|
||||
$inode = getInode('superNewDir/f3');
|
||||
|
||||
csync();
|
||||
assertLocalAndRemoteDir( '', 1);
|
||||
my $file = localDir() . 'superNewDir';
|
||||
assert( ! -e $file );
|
||||
|
||||
$inode2 = getInode('superNewDirRenamed/f3');
|
||||
assert( $inode == $inode2, "Inode of f3 changed");
|
||||
$inode2 = getInode('superNewDirRenamed');
|
||||
assert( $superNewDirInode == $inode2, "Inode of superNewDir changed");
|
||||
|
||||
cleanup();
|
||||
|
||||
|
||||
@@ -67,6 +67,13 @@ system( "rm -rf " . localDir() . 'remoteToLocal1' );
|
||||
system( "echo \"my file\" >> /tmp/myfile.txt" );
|
||||
put_to_dir( '/tmp/myfile.txt', 'remoteToLocal1/rtl1/rtl11' );
|
||||
|
||||
# Also add a file with symbols
|
||||
my $symbolName = "a\%b#c\$d-e";
|
||||
|
||||
system( "echo \"my symbols\" >> /tmp/$symbolName" );
|
||||
put_to_dir( "/tmp/$symbolName", 'remoteToLocal1/rtl1/rtl11' );
|
||||
|
||||
|
||||
my $fileid = remoteFileId( 'remoteToLocal1/rtl1/', 'rtl11' );
|
||||
my $fid2 = remoteFileId( 'remoteToLocal1/rtl1/', 'La ced' );
|
||||
assert($fid2 eq "" or $fileid ne $fid2, "File IDs are equal" );
|
||||
@@ -90,6 +97,9 @@ printInfo("Move file and create another one with the same name.");
|
||||
move( localDir() . 'newdir/myfile.txt', localDir() . 'newdir/oldfile.txt' );
|
||||
system( "echo \"super new\" >> " . localDir() . 'newdir/myfile.txt' );
|
||||
|
||||
#Move a file with symbols as well
|
||||
move( localDir() . "newdir/$symbolName", localDir() . "newdir/$symbolName.new" );
|
||||
|
||||
#Add some files for the next test.
|
||||
system( "echo \"un\" > " . localDir() . '1.txt' );
|
||||
system( "echo \"deux\" > " . localDir() . '2.txt' );
|
||||
|
||||
@@ -30,11 +30,20 @@ use ownCloud::Test;
|
||||
use strict;
|
||||
|
||||
print "Hello, this is t5, a tester for syncing of files in Shares\n";
|
||||
# stat error occours on windsows when the file is busy for example
|
||||
|
||||
initTesting();
|
||||
|
||||
# Create empty test dirs.
|
||||
csync();
|
||||
|
||||
my $share_dir = "share_source";
|
||||
my $sharee = { user => configValue('share_user'),
|
||||
passwd => configValue('share_passwd'),
|
||||
url => server() };
|
||||
|
||||
# first remove a possibly left over share dir.
|
||||
printInfo( "Remove possibly left over share dir" );
|
||||
removeRemoteDir( $share_dir, $sharee );
|
||||
|
||||
printInfo( "Create a share." );
|
||||
my $shareId = createShare( $share_dir, 31 );
|
||||
@@ -42,24 +51,53 @@ print "Created share with id <$shareId>\n";
|
||||
|
||||
assert( $shareId > 0 );
|
||||
|
||||
my $sharee = { user => configValue('share_user'),
|
||||
passwd => configValue('share_passwd'),
|
||||
url => server() };
|
||||
# put a couple of files into the shared directory in the sharer account
|
||||
glob_put( 'sharing/*', $share_dir, $sharee);
|
||||
|
||||
# now user kf has a new directory in shared.
|
||||
# Move the shared dir remotely into the test dir, otherwise the script
|
||||
# has a hard time to find it.
|
||||
moveRemoteFile( server() . $share_dir, localDir(), 1 );
|
||||
|
||||
# call csync, sync local t1 to remote t1
|
||||
printInfo("Initial sync, sync stuff down.");
|
||||
csync( server()."Shared" );
|
||||
assertLocalAndRemoteDir( 'Shared', 0, server() );
|
||||
csync();
|
||||
|
||||
|
||||
assertLocalAndRemoteDir( '', 0 );
|
||||
|
||||
# Local file to a read/write share should be synced up
|
||||
printInfo("Put a file into the share.");
|
||||
createLocalFile( localDir(). $share_dir . "/foobar.txt", 8094 );
|
||||
csync( server()."Shared" );
|
||||
assertLocalAndRemoteDir( 'Shared', 0, server() );
|
||||
createLocalFile(localDir() . "$share_dir/foobar.txt", 8094 );
|
||||
csync( );
|
||||
assertLocalAndRemoteDir( '', 0 );
|
||||
|
||||
# now move the file locally and sync
|
||||
printInfo("Move the file locally and sync.");
|
||||
my $cmd = "mv " . localDir() . "$share_dir/foobar.txt ". localDir() . "$share_dir/moved_file.txt";
|
||||
system( $cmd );
|
||||
csync( );
|
||||
assertLocalAndRemoteDir( '', 0 );
|
||||
|
||||
# now create aother directory and redo
|
||||
printInfo("Create another directory and file");
|
||||
my $cmd = "mkdir ". localDir() . "$share_dir/newDir";
|
||||
system( $cmd );
|
||||
createLocalFile( localDir() . "$share_dir/newDir/a_file.bin", 5321 );
|
||||
csync( );
|
||||
assertLocalAndRemoteDir( '', 0 );
|
||||
|
||||
# Remove the local file again
|
||||
printInfo("Remove the local file again.");
|
||||
unlink( localDir() . "$share_dir/newDir/a_file.bin" );
|
||||
csync( );
|
||||
assertLocalAndRemoteDir( '', 0 );
|
||||
|
||||
# Remove the local directory again
|
||||
printInfo("Remove the local directory again.");
|
||||
rmdir( localDir() . "$share_dir/newDir" );
|
||||
csync( );
|
||||
assertLocalAndRemoteDir( '', 0 );
|
||||
|
||||
|
||||
|
||||
printInfo("Remove a Share.");
|
||||
|
||||
@@ -33,6 +33,34 @@ print "Hello, this is t6, a tester for csync with ownCloud.\n";
|
||||
|
||||
initTesting();
|
||||
|
||||
sub createPostUpdateScript()
|
||||
{
|
||||
my $srcFile = localDir()."BIG.file";
|
||||
my $cred = configValue("user") . ":" . configValue("passwd");
|
||||
my $cmd = "curl -T $srcFile -u $cred " . testDirUrl();
|
||||
my $script = "/tmp/post_update_script.sh";
|
||||
open SC, ">$script" || die("Can not create script file");
|
||||
print SC "#!/bin/bash\n";
|
||||
print SC "$cmd\n";
|
||||
close SC;
|
||||
chmod 0755, $script;
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
sub getETagFromJournal($)
|
||||
{
|
||||
my ($num) = @_;
|
||||
|
||||
my $sql = "sqlite3 " . localDir() . ".csync_journal.db \"SELECT md5 FROM metadata WHERE path='BIG.file';\"";
|
||||
open(my $fh, '-|', $sql) or die $!;
|
||||
my $etag = <$fh>;
|
||||
close $fh;
|
||||
print "$num etag: $etag";
|
||||
|
||||
return $etag;
|
||||
}
|
||||
|
||||
sub chunkFileTest( $$ )
|
||||
{
|
||||
my ($name, $size) = @_;
|
||||
@@ -63,7 +91,27 @@ sub chunkFileTest( $$ )
|
||||
printInfo("Big file that needs chunking with default chunk size");
|
||||
chunkFileTest( "BIG.file", 23251233 );
|
||||
|
||||
# Set a custom chunk size in environment.
|
||||
printInfo("Update the existing file and trigger reupload");
|
||||
# change the existing file again -> update
|
||||
chunkFileTest( "BIG.file", 21762122 );
|
||||
|
||||
printInfo("Cause a precondition failed error");
|
||||
# Now overwrite the existing file to change it
|
||||
createLocalFile( localDir()."BIG.file", 21832199 );
|
||||
# and create a post update script
|
||||
my $script = createPostUpdateScript();
|
||||
$ENV{'OWNCLOUD_POST_UPDATE_SCRIPT'} = $script;
|
||||
|
||||
# Save the etag before the sync
|
||||
my $firstETag = getETagFromJournal('First');
|
||||
csync(); # Sync, which ends in a precondition failed error
|
||||
# get the etag again. It has to be unchanged because of the error.
|
||||
my $secondETag = getETagFromJournal('Second');
|
||||
assert( $firstETag eq $secondETag, "Different ETags, no precondition error." );
|
||||
|
||||
unlink($script);
|
||||
|
||||
# Set a custom chunk size in environment.
|
||||
my $ChunkSize = 1*1024*1024;
|
||||
$ENV{'OWNCLOUD_CHUNK_SIZE'} = $ChunkSize;
|
||||
|
||||
|
||||
256
csync/tests/ownCloud/t7.pl
Executable file
256
csync/tests/ownCloud/t7.pl
Executable file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Test script for the ownCloud module of csync.
|
||||
# This script requires a running ownCloud instance accessible via HTTP.
|
||||
# It does quite some fancy tests and asserts the results.
|
||||
#
|
||||
# Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
use lib ".";
|
||||
|
||||
use Carp::Assert;
|
||||
use File::Copy;
|
||||
use ownCloud::Test;
|
||||
|
||||
use strict;
|
||||
|
||||
print "Hello, this is t7, a tester for syncing of files in read only directory\n";
|
||||
|
||||
# Check if the expected rows in the DB are non-empty. Note that in some cases they might be, then we cannot use this function
|
||||
# https://github.com/owncloud/mirall/issues/2038
|
||||
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 $result = `$cmd`;
|
||||
assert($result == "0");
|
||||
}
|
||||
|
||||
# IMPORTANT NOTE :
|
||||
print "This test use the OWNCLOUD_TEST_PERMISSIONS environement variable and _PERM_xxx_ on filenames to set the permission. ";
|
||||
print "It does not rely on real permission set on the server. This test is just for testing the propagation choices\n";
|
||||
# "It would be nice" to have a test that test with real permissions on the server
|
||||
|
||||
$ENV{OWNCLOUD_TEST_PERMISSIONS} = "1";
|
||||
|
||||
initTesting();
|
||||
|
||||
printInfo( "Init" );
|
||||
|
||||
#create some files localy
|
||||
my $tmpdir = "/tmp/t7/";
|
||||
mkdir($tmpdir);
|
||||
createLocalFile( $tmpdir . "normalFile_PERM_WVND_.data", 100 );
|
||||
createLocalFile( $tmpdir . "cannotBeRemoved_PERM_WVN_.data", 101 );
|
||||
createLocalFile( $tmpdir . "canBeRemoved_PERM_D_.data", 102 );
|
||||
my $md5CanotBeModified = createLocalFile( $tmpdir . "canotBeModified_PERM_DVN_.data", 103 );
|
||||
createLocalFile( $tmpdir . "canBeModified_PERM_W_.data", 104 );
|
||||
|
||||
#put them in some directories
|
||||
createRemoteDir( "normalDirectory_PERM_CKDNV_" );
|
||||
glob_put( "$tmpdir/*", "normalDirectory_PERM_CKDNV_" );
|
||||
createRemoteDir( "readonlyDirectory_PERM_M_" );
|
||||
glob_put( "$tmpdir/*", "readonlyDirectory_PERM_M_" );
|
||||
createRemoteDir( "readonlyDirectory_PERM_M_/subdir_PERM_CK_" );
|
||||
createRemoteDir( "readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_" );
|
||||
glob_put( "$tmpdir/normalFile_PERM_WVND_.data", "readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_" );
|
||||
|
||||
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
system("sleep 1"); #make sure changes have different mtime
|
||||
|
||||
printInfo( "Do some changes and see how they propagate" );
|
||||
|
||||
#1. remove the file than cannot be removed
|
||||
# (they should be recovered)
|
||||
unlink( localDir() . 'normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data' );
|
||||
unlink( localDir() . 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
|
||||
|
||||
#2. remove the file that can be removed
|
||||
# (they should properly be gone)
|
||||
unlink( localDir() . 'normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data' );
|
||||
unlink( localDir() . 'readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data' );
|
||||
|
||||
#3. Edit the files that cannot be modified
|
||||
# (they should be recovered, and a conflict shall be created)
|
||||
system("echo 'modified' > ". localDir() . "normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN_.data");
|
||||
system("echo 'modified_' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
|
||||
|
||||
#4. Edit other files
|
||||
# (they should be uploaded)
|
||||
system("echo '__modified' > ". localDir() . "normalDirectory_PERM_CKDNV_/canBeModified_PERM_W_.data");
|
||||
system("echo '__modified_' > ". localDir() . "readonlyDirectory_PERM_M_/canBeModified_PERM_W_.data");
|
||||
|
||||
#5. Create a new file in a read only folder
|
||||
# (they should not be uploaded)
|
||||
createLocalFile( localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data", 105 );
|
||||
|
||||
#6. Create a new file in a read only folder
|
||||
# (should be uploaded)
|
||||
createLocalFile( localDir() . "normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data", 106 );
|
||||
|
||||
#do the sync
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
|
||||
#1.
|
||||
# File should be recovered
|
||||
assert( -e localDir(). 'normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data' );
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
|
||||
|
||||
#2.
|
||||
# File should be deleted
|
||||
assert( !-e localDir() . 'normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data' );
|
||||
assert( !-e localDir() . 'readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data' );
|
||||
|
||||
#3.
|
||||
# File should be recovered
|
||||
assert($md5CanotBeModified eq md5OfFile( localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN_.data' ));
|
||||
assert($md5CanotBeModified eq md5OfFile( localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data' ));
|
||||
# and conflict created
|
||||
# TODO check that the conflict file has the right content
|
||||
assert( -e glob(localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN__conflict-*.data' ) );
|
||||
assert( -e glob(localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' ) );
|
||||
# remove the conflicts for the next assertLocalAndRemoteDir
|
||||
system("rm " . localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN__conflict-*.data' );
|
||||
system("rm " . localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
|
||||
|
||||
#4. File should be updated, that's tested by assertLocalAndRemoteDir
|
||||
|
||||
#5.
|
||||
# The file should not exist on the remote
|
||||
# TODO: test that the file is NOT on the server
|
||||
# but still be there
|
||||
assert( -e localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data" );
|
||||
# remove it so assertLocalAndRemoteDir succeed.
|
||||
unlink(localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data");
|
||||
|
||||
#6.
|
||||
# the file should be in the server and local
|
||||
assert( -e localDir() . "normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data" );
|
||||
|
||||
|
||||
### Both side should still be the same
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
printInfo( "remove the read only directory" );
|
||||
# -> It must be recovered
|
||||
system("rm -r " . localDir().'readonlyDirectory_PERM_M_' );
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
#######################################################################
|
||||
printInfo( "move a directory in a outside read only folder" );
|
||||
system("sqlite3 " . localDir().'.csync_journal.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_' );
|
||||
|
||||
# two syncs may be necessary for now: https://github.com/owncloud/mirall/issues/2038
|
||||
csync();
|
||||
csync();
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
# old name restored
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/' );
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
|
||||
|
||||
# new still exist
|
||||
assert( -e localDir(). 'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
|
||||
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
printInfo( "rename a directory in a read only folder and move a directory to a read-only" );
|
||||
|
||||
# do a sync to update the database
|
||||
csync();
|
||||
|
||||
#1. rename a directory in a read only folder
|
||||
#Missing directory should be restored
|
||||
#new directory should stay but not be uploaded
|
||||
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'readonlyDirectory_PERM_M_/newname_PERM_CK_' );
|
||||
|
||||
#2. move a directory from read to read only (move the directory from previous step)
|
||||
system("mv " . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_ ' . localDir().'readonlyDirectory_PERM_M_/moved_PERM_CK_' );
|
||||
|
||||
# two syncs may be necessary for now: https://github.com/owncloud/mirall/issues/2038
|
||||
csync();
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
#1.
|
||||
# old name restored
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
|
||||
|
||||
# new still exist
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/newname_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
|
||||
# but is not on server: so remove for assertLocalAndRemoteDir
|
||||
system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/newname_PERM_CK_");
|
||||
|
||||
#2.
|
||||
# old removed
|
||||
assert( ! -e localDir(). 'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/' );
|
||||
# new still there
|
||||
assert( -e localDir(). 'readonlyDirectory_PERM_M_/moved_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
|
||||
#but not on server
|
||||
system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/moved_PERM_CK_");
|
||||
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
|
||||
|
||||
cleanup();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
110
csync/tests/ownCloud/t8.pl
Executable file
110
csync/tests/ownCloud/t8.pl
Executable file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Test script for the ownCloud module of csync.
|
||||
# This script requires a running ownCloud instance accessible via HTTP.
|
||||
# It does quite some fancy tests and asserts the results.
|
||||
#
|
||||
# Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
use lib ".";
|
||||
|
||||
use Carp::Assert;
|
||||
use File::Copy;
|
||||
use ownCloud::Test;
|
||||
|
||||
use strict;
|
||||
|
||||
print "Hello, this is t8, a tester for syncing of files on a case sensitive FS\n";
|
||||
|
||||
|
||||
# The test is run on a 'normal' file system, but we tell pwncloud that it is case preserving anyway
|
||||
$ENV{OWNCLOUD_TEST_CASE_PRESERVING} = "1";
|
||||
|
||||
# FIXME! the code does not work with parallelism
|
||||
$ENV{OWNCLOUD_MAX_PARALLEL}="1";
|
||||
|
||||
initTesting();
|
||||
|
||||
printInfo( "Syncing two files with the same name that differ with case" );
|
||||
|
||||
#create some files localy
|
||||
my $tmpdir = "/tmp/t8/";
|
||||
mkdir($tmpdir);
|
||||
createLocalFile( $tmpdir . "HELLO.dat", 100 );
|
||||
createLocalFile( $tmpdir . "Hello.dat", 150 );
|
||||
createLocalFile( $tmpdir . "Normal.dat", 110 );
|
||||
|
||||
#put them in some directories
|
||||
createRemoteDir( "dir" );
|
||||
glob_put( "$tmpdir/*", "dir" );
|
||||
|
||||
csync();
|
||||
|
||||
# Check that only one of the two file was synced.
|
||||
# The one that exist here is undefined, the current implementation will take the
|
||||
# first one alphabetically, but the other one would also be fine. What's imporant
|
||||
# is that there is only one.
|
||||
assert( -e localDir() . 'dir/HELLO.dat' );
|
||||
assert( !-e localDir() . 'dir/Hello.dat' );
|
||||
|
||||
printInfo( "Remove one file should remove it on the server and download the other one" );
|
||||
unlink( localDir() . 'dir/HELLO.dat' );
|
||||
|
||||
csync();
|
||||
assert( -e localDir() . 'dir/Hello.dat' );
|
||||
assert( !-e localDir() . 'dir/HELLO.dat' );
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
printInfo( "Renaming one file to the same name as another one with different casing" );
|
||||
moveRemoteFile( 'dir/Hello.dat', 'dir/NORMAL.dat');
|
||||
|
||||
csync();
|
||||
|
||||
#It should not have do the move
|
||||
assert( -e localDir() . 'dir/Hello.dat' );
|
||||
assert( !-e localDir() . 'dir/NORMAL.dat' );
|
||||
assert( -e localDir() . 'dir/Normal.dat' );
|
||||
|
||||
printInfo( "Another directory with the same name but different casing is created" );
|
||||
|
||||
createRemoteDir( "DIR" );
|
||||
glob_put( "$tmpdir/*", "DIR" );
|
||||
|
||||
csync();
|
||||
|
||||
assert( !-e localDir() . 'DIR' );
|
||||
|
||||
|
||||
printInfo( "Remove the old dir localy" );
|
||||
|
||||
system("rm -r " . localDir() . "dir");
|
||||
|
||||
csync();
|
||||
|
||||
# now DIR was fetched
|
||||
assert( -e localDir() . 'DIR' );
|
||||
assert( -e localDir() . 'DIR/HELLO.dat' );
|
||||
assert( !-e localDir() . 'DIR/Hello.dat' );
|
||||
assert( !-e localDir() . 'dir' );
|
||||
|
||||
# dir/NORMAL.dat is still on the server
|
||||
|
||||
cleanup();
|
||||
system("rm -r " . $tmpdir);
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "std/c_private.h"
|
||||
#include "std/c_dir.h"
|
||||
#include "std/c_string.h"
|
||||
|
||||
const char *check_dir = "/tmp/check/c_mkdirs//with/check//";
|
||||
const char *check_file = "/tmp/check/c_mkdirs/with/check/foobar.txt";
|
||||
|
||||
static void setup(void **state) {
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_mkdirs(check_dir, 0755);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("touch /tmp/check/c_mkdirs/with/check/foobar.txt");
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_rmdirs(check_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static int test_dir(const char *path, mode_t mode) {
|
||||
csync_stat_t sb;
|
||||
if (lstat(path, &sb) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME */
|
||||
if ((sb.st_mode & mode) == mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void check_c_mkdirs_rmdirs(void **state)
|
||||
{
|
||||
csync_stat_t sb;
|
||||
int rc;
|
||||
mbchar_t *wcheck_dir;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_mkdirs(check_dir, 0755);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = test_dir(check_dir, 0755);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = c_rmdirs(check_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
wcheck_dir = c_utf8_to_locale(check_dir);
|
||||
rc = _tstat(wcheck_dir, &sb);
|
||||
c_free_locale_string(wcheck_dir);
|
||||
assert_int_equal(rc, -1);
|
||||
}
|
||||
|
||||
static void check_c_mkdirs_mode(void **state)
|
||||
{
|
||||
csync_stat_t sb;
|
||||
int rc;
|
||||
mbchar_t *wcheck_dir;
|
||||
|
||||
(void) state; /* unused */
|
||||
rc = c_mkdirs(check_dir, 0700);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = test_dir(check_dir, 0700);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = c_rmdirs(check_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
wcheck_dir = c_utf8_to_locale(check_dir);
|
||||
rc = _tstat(wcheck_dir, &sb);
|
||||
assert_int_equal(rc, -1);
|
||||
c_free_locale_string(wcheck_dir);
|
||||
}
|
||||
|
||||
static void check_c_mkdirs_existing_path(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_mkdirs(check_dir, 0755);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_c_mkdirs_file(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_mkdirs(check_file, 0755);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, ENOTDIR);
|
||||
}
|
||||
|
||||
static void check_c_mkdirs_null(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(c_mkdirs(NULL, 0755), -1);
|
||||
}
|
||||
|
||||
static void check_c_isdir(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(c_isdir(check_dir), 1);
|
||||
}
|
||||
|
||||
static void check_c_isdir_on_file(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(c_isdir(check_file), 0);
|
||||
}
|
||||
|
||||
static void check_c_isdir_null(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(c_isdir(NULL), 0);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_c_mkdirs_rmdirs),
|
||||
unit_test(check_c_mkdirs_mode),
|
||||
unit_test_setup_teardown(check_c_mkdirs_existing_path, setup, teardown),
|
||||
unit_test_setup_teardown(check_c_mkdirs_file, setup, teardown),
|
||||
unit_test(check_c_mkdirs_null),
|
||||
unit_test_setup_teardown(check_c_isdir, setup, teardown),
|
||||
unit_test_setup_teardown(check_c_isdir_on_file, setup, teardown),
|
||||
unit_test(check_c_isdir_null),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "std/c_private.h"
|
||||
#include "std/c_file.h"
|
||||
#include "std/c_string.h"
|
||||
|
||||
const char *check_dir = "/tmp/check";
|
||||
const char *check_src_file = "/tmp/check/foo.txt";
|
||||
const char *check_dst_file = "/tmp/check/bar.txt";
|
||||
|
||||
static int test_file(const char *path, mode_t mode) {
|
||||
csync_stat_t sb;
|
||||
mbchar_t *mbpath = c_utf8_to_locale(path);
|
||||
int rc = _tstat(mbpath, &sb);
|
||||
c_free_locale_string(mbpath);
|
||||
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! S_ISREG(sb.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sb.st_mode & mode) == mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = system("mkdir -p /tmp/check");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("echo 42 > /tmp/check/foo.txt");
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = system("rm -rf /tmp/check");
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_c_copy(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_copy(check_src_file, check_dst_file, 0644);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = test_file(check_dst_file, 0644);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_c_copy_same_file(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_copy(check_src_file, check_src_file, 0644);
|
||||
assert_int_equal(rc, -1);
|
||||
}
|
||||
|
||||
static void check_c_copy_isdir(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
rc = c_copy(check_src_file, check_dir, 0644);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EISDIR);
|
||||
|
||||
rc = c_copy(check_dir, check_dst_file, 0644);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, ENOENT);
|
||||
}
|
||||
|
||||
static void check_c_compare_file(void **state)
|
||||
{
|
||||
int rc;
|
||||
(void) state;
|
||||
|
||||
rc = c_copy(check_src_file, check_dst_file, 0644);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = c_compare_file( check_src_file, check_dst_file );
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
/* Check error conditions */
|
||||
rc = c_compare_file( NULL, check_dst_file );
|
||||
assert_int_equal(rc, -1);
|
||||
rc = c_compare_file( check_dst_file, NULL );
|
||||
assert_int_equal(rc, -1);
|
||||
rc = c_compare_file( NULL, NULL );
|
||||
assert_int_equal(rc, -1);
|
||||
|
||||
rc = c_compare_file( check_src_file, "/I_do_not_exist_in_the_filesystem.dummy");
|
||||
assert_int_equal(rc, -1);
|
||||
rc = c_compare_file( "/I_do_not_exist_in_the_filesystem.dummy", check_dst_file);
|
||||
assert_int_equal(rc, -1);
|
||||
|
||||
rc = system("echo \"hallo42\" > /tmp/check/foo.txt");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("echo \"hallo52\" > /tmp/check/bar.txt");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = c_compare_file( check_src_file, check_dst_file );
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* Create two 1MB random files */
|
||||
rc = system("dd if=/dev/urandom of=/tmp/check/foo.txt bs=1024 count=1024");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("dd if=/dev/urandom of=/tmp/check/bar.txt bs=1024 count=1024");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = c_compare_file( check_src_file, check_dst_file );
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* Create two 1MB random files with different size */
|
||||
rc = system("dd if=/dev/urandom of=/tmp/check/foo.txt bs=1024 count=1024");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("dd if=/dev/urandom of=/tmp/check/bar.txt bs=1024 count=1020");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = c_compare_file( check_src_file, check_dst_file );
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* compare two big files which are equal */
|
||||
rc = c_copy(check_src_file, check_dst_file, 0644);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = c_compare_file( check_src_file, check_dst_file );
|
||||
assert_int_equal(rc, 1);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_c_copy, setup, teardown),
|
||||
unit_test(check_c_copy_same_file),
|
||||
unit_test_setup_teardown(check_c_copy_isdir, setup, teardown),
|
||||
unit_test_setup_teardown(check_c_compare_file, setup, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
||||
|
||||
@@ -130,32 +130,6 @@ static void check_c_dirname_uri(void **state)
|
||||
free(dname);
|
||||
}
|
||||
|
||||
static void check_c_tmpname(void **state)
|
||||
{
|
||||
char tmpl[22]={0};
|
||||
char prev[22]={0};
|
||||
char *tmp;
|
||||
int i = 0;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
srand((unsigned)time(NULL));
|
||||
|
||||
/* remember the last random value and compare the new one against.
|
||||
* They may never be the same. */
|
||||
for(i = 0; i < 100; i++){
|
||||
strcpy(tmpl, "check_tmpname.XXXXXX");
|
||||
tmp = c_tmpname(tmpl);
|
||||
assert_non_null(tmp);
|
||||
|
||||
if (strlen(prev)) {
|
||||
assert_string_not_equal(tmp, prev);
|
||||
}
|
||||
strcpy(prev, tmp);
|
||||
SAFE_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_c_parse_uri(void **state)
|
||||
{
|
||||
const char *test_scheme = "git+ssh";
|
||||
@@ -204,7 +178,6 @@ int torture_run_tests(void)
|
||||
unit_test(check_c_dirname),
|
||||
unit_test(check_c_dirname_uri),
|
||||
unit_test(check_c_parse_uri),
|
||||
unit_test(check_c_tmpname),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
|
||||
@@ -113,85 +113,6 @@ static void check_c_strlist_expand(void **state)
|
||||
c_strlist_destroy(strlist);
|
||||
}
|
||||
|
||||
static void check_c_strreplace(void **state)
|
||||
{
|
||||
char *str = strdup("/home/%(USER)");
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_strreplace(str, "%(USER)", "csync");
|
||||
assert_string_equal(str, "/home/csync");
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void check_c_lowercase(void **state)
|
||||
{
|
||||
char *str;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_lowercase("LoWeRcASE");
|
||||
assert_string_equal(str, "lowercase");
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void check_c_lowercase_empty(void **state)
|
||||
{
|
||||
char *str;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_lowercase("");
|
||||
assert_string_equal(str, "");
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void check_c_lowercase_null(void **state)
|
||||
{
|
||||
char *str;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_lowercase(NULL);
|
||||
assert_null(str);
|
||||
}
|
||||
|
||||
static void check_c_uppercase(void **state)
|
||||
{
|
||||
char *str;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_uppercase("upperCASE");
|
||||
assert_string_equal(str, "UPPERCASE");
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void check_c_uppercase_empty(void **state)
|
||||
{
|
||||
char *str;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_uppercase("");
|
||||
assert_string_equal(str, "");
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void check_c_uppercase_null(void **state)
|
||||
{
|
||||
char *str;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
str = c_uppercase(NULL);
|
||||
assert_null(str);
|
||||
}
|
||||
|
||||
|
||||
int torture_run_tests(void)
|
||||
@@ -203,13 +124,6 @@ int torture_run_tests(void)
|
||||
unit_test(check_c_strlist_new),
|
||||
unit_test(check_c_strlist_add),
|
||||
unit_test(check_c_strlist_expand),
|
||||
unit_test(check_c_strreplace),
|
||||
unit_test(check_c_lowercase),
|
||||
unit_test(check_c_lowercase_empty),
|
||||
unit_test(check_c_lowercase_null),
|
||||
unit_test(check_c_uppercase),
|
||||
unit_test(check_c_uppercase_empty),
|
||||
unit_test(check_c_uppercase_null),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
|
||||
@@ -4,7 +4,7 @@ if(SPHINX_FOUND)
|
||||
set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees")
|
||||
# HTML output directory
|
||||
set(SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html")
|
||||
set(SPHINX_MAN_DIR "${CMAKE_CURRENT_BINARY_DIR}/man")
|
||||
set(SPHINX_MAN_DIR "${CMAKE_CURRENT_BINARY_DIR}/man1")
|
||||
set(SPHINX_PDF_DIR "${CMAKE_CURRENT_BINARY_DIR}/latex")
|
||||
set(SPHINX_QCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/qthelp")
|
||||
set(SPHINX_HTMLHELP_DIR "${CMAKE_CURRENT_BINARY_DIR}/htmlhelp")
|
||||
|
||||
@@ -1,45 +1,42 @@
|
||||
Setting up an Account
|
||||
=====================
|
||||
|
||||
If no account has been configured, the ownCloud Client will automatically
|
||||
assist in connecting to your ownCloud server after the application has been
|
||||
started.
|
||||
If no account has been configured, the ownCloud Client automatically assist in
|
||||
connecting to your ownCloud server after the application has been started.
|
||||
|
||||
As a first step, specify the URL to your Server. This is the same address
|
||||
that is used in the browser.
|
||||
To set up an account:
|
||||
|
||||
1. Specify the URL to your Server. This is the same address that is used in the browser.
|
||||
|
||||
.. image:: images/wizard_url.png
|
||||
:scale: 50 %
|
||||
|
||||
.. note:: Make sure to use ``https://`` if the server supports it. Otherwise,
|
||||
your password and all data will be transferred to the server unencrypted.
|
||||
This makes it easy for third parties to intercept your communication, and
|
||||
getting hold of your password!
|
||||
your password and all data will be transferred to the server unencrypted. This
|
||||
makes it easy for third parties to intercept your communication, and getting
|
||||
hold of your password!
|
||||
|
||||
Next, enter the username and password. These are the same credentials used
|
||||
to log into the web interface.
|
||||
2. Enter the username and password. These are the same credentials used to log into the web interface.
|
||||
|
||||
.. image:: images/wizard_user.png
|
||||
:scale: 50 %
|
||||
|
||||
Finally, choose the folder that ownCloud Client is supposed to sync the
|
||||
contents of your ownCloud account with. By default, this is a folder
|
||||
called `ownCloud`, which will be created in the home directory.
|
||||
3. Choose the folder with which you want the ownCloud Client to synchronize the
|
||||
contents of your ownCloud account. By default, this is a folder called
|
||||
`ownCloud`. This folder is created in the home directory.
|
||||
|
||||
.. image:: images/wizard_targetfolder.png
|
||||
:scale: 50 %
|
||||
|
||||
At this time, the synchronization between the root directories of the
|
||||
ownCloud server will begin.
|
||||
The synchronization between the root directories of the ownCloud server begins.
|
||||
|
||||
.. image:: images/wizard_overview.png
|
||||
:scale: 50 %
|
||||
|
||||
If selecting a local folder that already contains data, there are
|
||||
two options that exist.
|
||||
When selecting a local folder that already contains data, you can choose from two options:
|
||||
|
||||
* Keep local data: If selected, the files in the local folder on the
|
||||
client will be synced up to the ownCloud server.
|
||||
* Start a clean sync: If selected, all files in the local folder on
|
||||
the client will be deleted and therefore not synced to the ownCloud
|
||||
server.
|
||||
* :guilabel:`Keep local data`: When selected, the files in the local folder on
|
||||
the client are synchronized to the ownCloud server.
|
||||
|
||||
* :guilabel:`Start a clean sync`: When selected, all files in the local folder on the
|
||||
client are deleted. These files are not syncrhonized to the ownCloud server.
|
||||
|
||||
@@ -1,88 +1,96 @@
|
||||
Appendix B: Architecture
|
||||
========================
|
||||
Appendix B: History and Architecture
|
||||
====================================
|
||||
|
||||
.. index:: architecture
|
||||
.. index:: architecture
|
||||
|
||||
The ownCloud project provides desktop sync clients to synchronize the
|
||||
contents of local directories on the desktop machines to the ownCloud.
|
||||
ownCloud provides desktop sync clients to synchronize the contents of local
|
||||
directories from computers, tablets, and handheld devices to the ownCloud
|
||||
server.
|
||||
|
||||
The syncing is done with csync_, a bidirectional file synchronizing tool which
|
||||
provides both a command line client as well as a library. A special module for
|
||||
csync was written to synchronize with ownCloud’s built-in WebDAV server.
|
||||
Synchronization is accomplished using csync_, a bidirectional file
|
||||
synchronizing tool that provides both a command line client as well as a
|
||||
library. A special module for csync was written to synchronize with the
|
||||
ownCloud built-in WebDAV server.
|
||||
|
||||
The ownCloud sync client is based on a tool called mirall initially written by
|
||||
Duncan Mac Vicar. Later Klaas Freitag joined the project and enhanced it to work
|
||||
with ownCloud server.
|
||||
The ownCloud sync client is based on a tool called *mirall*, initially written
|
||||
by Duncan Mac Vicar. Later Klaas Freitag joined the project and enhanced it to
|
||||
function with the ownCloud server.
|
||||
|
||||
ownCloud Client is written in C++ using the `Qt Framework`_. As a result, the
|
||||
ownCloud Client runs on the three important platforms Linux, Windows and MacOS.
|
||||
The ownCloud Client software is written in C++ using the `Qt Framework`_. As a
|
||||
result, the ownCloud Client runs on Linux, Windows, and MacOS.
|
||||
|
||||
.. _csync: http://www.csync.org
|
||||
.. _`Qt Framework`: http://www.qt-project.org
|
||||
|
||||
The Sync Process
|
||||
----------------
|
||||
The Synchronization Process
|
||||
---------------------------
|
||||
|
||||
First it is important to recall what syncing is: It tries to keep the files
|
||||
on two repositories the same. That means if a file is added to one repository
|
||||
it is going to be copied to the other repository. If a file is changed on one
|
||||
repository, the change is propagated to the other repository. Also, if a file
|
||||
is deleted on one side, it is deleted on the other. As a matter of fact, in
|
||||
ownCloud syncing we do not have a typical client/server system where the
|
||||
server is always master.
|
||||
The process of synchronization keeps files in two separate repositories the same. When syncrhonized:
|
||||
|
||||
This is the major difference to other systems like a file backup where just
|
||||
changes and new files are propagated but files never get deleted.
|
||||
- If a file is added to one repository it is copied to the other synchronized repository.
|
||||
- When a file is changed in one repository, the change is propagated to any
|
||||
syncrhonized other repositories- If a file is deleted in one repository, it
|
||||
is deleted in any other.
|
||||
|
||||
The ownCloud Client checks both repositories for changes frequently after a
|
||||
certain time span. That is refered to as a sync run. In between the local
|
||||
repository is monitored by a file system monitor system that starts a sync run
|
||||
immediately if something was edited, added or removed.
|
||||
It is important to note that the ownCloud synchronization process does not use
|
||||
a typical client/server system where the server is always master. This is a
|
||||
major difference between the ownCloud syncrhonizatin process and other systems
|
||||
like a file backup, where only changes to files or folders and the addition of
|
||||
new files are propagated, but these files and folders are never deleted unless
|
||||
explicitly deleted in the backup.
|
||||
|
||||
Sync by Time versus ETag
|
||||
------------------------
|
||||
.. index:: time stamps, file times, etag, unique id
|
||||
During synchronization, the ownCloud Client checks both repositories for
|
||||
changes frequently. This process is referred to as a *sync run*. In between
|
||||
sync runs, the local repository is monitored by a file system monitoring
|
||||
process that starts a sync run immediately if something was edited, added, or
|
||||
removed.
|
||||
|
||||
Until the release of ownCloud 4.5 and ownCloud Client 1.1, ownCloud employed
|
||||
a single file property to decide which file is newer and hence needs to be
|
||||
synced to the other repository: the files modification time.
|
||||
Synchronization by Time versus ETag
|
||||
-----------------------------------
|
||||
.. index:: time stamps, file times, etag, unique id
|
||||
|
||||
Until the release of ownCloud 4.5 and ownCloud Client 1.1, the ownCloud
|
||||
synchronization process employed a single file property -- the file modificatin
|
||||
time -- to decide which file was newer and needed to be synchronized to the
|
||||
other repository.
|
||||
|
||||
The *modification timestamp* is part of the files metadata. It is available on
|
||||
every relevant filesystem and is the natural indicator for a file change.
|
||||
Modification timestamps do not require special action to create and have
|
||||
a general meaning. One design goal of csync is to not require a special server
|
||||
component, that’s why it was chosen as the backend component.
|
||||
every relevant filesystem and is the typical indicator for a file change.
|
||||
Modification timestamps do not require special action to create, and have a
|
||||
general meaning. One design goal of csync is to not require a special server
|
||||
component. This design goal is why csync was chosen as the backend component.
|
||||
|
||||
To compare the modification times of two files from different systems,
|
||||
it is needed to operate on the same base. Before version 1.1.0,
|
||||
csync requires both sides running on the exact same time, which can
|
||||
be achieved through enterprise standard `NTP time synchronisation`_ on all
|
||||
machines.
|
||||
To compare the modification times of two files from different systems, csync
|
||||
must operate on the same base. Before ownCloud Client version 1.1.0, csync
|
||||
required both device repositories to run on the exact same time. This
|
||||
requirement was achieved through the use of enterprise standard `NTP time
|
||||
synchronisation`_ on all machines.
|
||||
|
||||
Since this strategy is rather fragile without NTP, ownCloud 4.5 introduced a
|
||||
unique number, which changes whenever the file changes. Although it is a unique
|
||||
value, it is not a hash of the file, but a randomly chosen number, which it will
|
||||
transmit in the Etag_ field. Since the file number is guaranteed to change if
|
||||
the file changes, it can now be used to determine if one of the files has
|
||||
changed.
|
||||
Because this timing strategy is rather fragile without the use of NTP, ownCloud
|
||||
4.5 introduced a unique number (for each file?) that changes whenever the file
|
||||
changes. Although this number is a unique value, it is not a hash of the file.
|
||||
Instead, it is a randomly chosen number, that is transmitted in the Etag_
|
||||
field. Because the file number changes if the file changes, its use is
|
||||
guaranteed to determine if one of the files has changed and, thereby, launching
|
||||
a synchronization process.
|
||||
|
||||
.. note:: ownCloud Client 1.1 and newer require file ID capabilities on the
|
||||
ownCloud server, hence using them with a server earlier than 4.5.0 is
|
||||
not supported.
|
||||
.. note:: ownCloud Client release 1.1 and later requires file ID capabilities
|
||||
on the ownCloud server. Servers that run with release earlier than 4.5.0 do
|
||||
not support using the file ID functionality.
|
||||
|
||||
Before the 1.3.0 release of the client the sync process might create faux
|
||||
conflict files if time deviates. The original and the conflict files only
|
||||
differed in the timestamp, but not in content. This behaviour was changed
|
||||
towards a binary check if the files are different.
|
||||
Before the 1.3.0 release of the Desktop Client, the synchronization process
|
||||
might create faux conflict files if time deviates. Original and changed files
|
||||
conflict only in their timestamp, but not in their content. This behaviour was
|
||||
changed to employ a binary check if files differ.
|
||||
|
||||
Just like files, directories also hold a unique id, which changes whenever
|
||||
one of the contained files or directories gets modified. Since this is a
|
||||
recursive process, it significantly reduces the effort required for a sync
|
||||
cycle, because the client will only walk directories with a modified unique id.
|
||||
Like files, directories also hold a unique ID that changes whenever one of the
|
||||
contained files or directories is modified. Because this is a recursive
|
||||
process, it significantly reduces the effort required for a synchronization
|
||||
cycle, because the client only analyzes directories with a modified ID.
|
||||
|
||||
|
||||
This table outlines the different sync methods attempted depending
|
||||
on server/client combination:
|
||||
The following table outlines the different synchronization methods used,
|
||||
depending on server/client combination:
|
||||
|
||||
.. index:: compatiblity table
|
||||
|
||||
@@ -98,10 +106,10 @@ on server/client combination:
|
||||
| 4.5 or later | 1.1 or later | File ID, Time Stamp |
|
||||
+--------------------+-------------------+----------------------------+
|
||||
|
||||
It is highly recommended to upgrade to ownCloud 4.5 or later with ownCloud
|
||||
Client 1.1 or later, since the time stamp-based sync mechanism can
|
||||
lead to data loss in certain edge-cases, especially when multiple clients
|
||||
are involved and one of them is not in sync with NTP time.
|
||||
We strongly recommend using ownCloud Server release 4.5 or later when using
|
||||
ownCloud Client 1.1 or later. Using incompatible time stamp-based
|
||||
synchronization mechanism can lead to data loss in rare cases, especially when
|
||||
multiple clients are involved and one utilizes a non-synchronized NTP time.
|
||||
|
||||
.. _`NTP time synchronisation`: http://en.wikipedia.org/wiki/Network_Time_Protocol
|
||||
.. _Etag: http://en.wikipedia.org/wiki/HTTP_ETag
|
||||
@@ -109,27 +117,28 @@ are involved and one of them is not in sync with NTP time.
|
||||
Comparison and Conflict Cases
|
||||
-----------------------------
|
||||
|
||||
In a sync run the client first has to detect if one of the two repositories have
|
||||
changed files. On the local repository, the client traverses the file
|
||||
tree and compares the modification time of each file with the value it was
|
||||
before. The previous value is stored in the client's database. If it is not, it
|
||||
means that the file has been added to the local repository. Note that on
|
||||
the local side, the modificaton time a good attribute to detect changes because
|
||||
it does not depend on time shifts and such.
|
||||
As mentioned above, during a *sync run* the client must first detect if one of
|
||||
the two repositories have changed files. On the local repository, the client
|
||||
traverses the file tree and compares the modification time of each file with an
|
||||
expected value stored in its database. If the value is not the same, the client
|
||||
determines that the file has been modified in the local repository.
|
||||
|
||||
For the remote (ie. ownCloud) repository, the client compares the ETag of each
|
||||
file with it's previous value. Again the previous value is queried from the
|
||||
database. If the ETag is still the same, the file has not changed.
|
||||
.. note:: On the local side, the modificaton time a good attribute to use for detecting changes, because
|
||||
the value does not depend on time shifts and such.
|
||||
|
||||
In case a file has changed on both, the local and the remote repository since
|
||||
the last sync run, it can not easily be decided which version of the file is
|
||||
the one that should be used. However, changes to any side must not be lost.
|
||||
For the remote (that is, ownCloud server) repository, the client compares the
|
||||
ETag of each file with its expected value. Again, the expected ETag value is
|
||||
queried from the client database. If the ETag is the same, the file has not
|
||||
changed and no synchronization occurs.
|
||||
|
||||
That is called a **conflict case**. The client solves it by creating a conflict
|
||||
file of the older of the two files and save the newer one under the original
|
||||
file name. Conflict files are always created on the client and never on the
|
||||
server. The conflict file has the same name as the original file appended with
|
||||
the timestamp of the conflict detection.
|
||||
In the event a file has changed on both the local and the remote repository
|
||||
since the last sync run, it can not easily be decided which version of the file
|
||||
is the one that should be used. However, changes to any side be lost. Instead,
|
||||
a *conflict case* is created. The client resolves this conflic by creating a
|
||||
conflict file of the older of the two files and saving the newer file under the
|
||||
original file name. Conflict files are always created on the client and never
|
||||
on the server. The conflict file uses the same name as the original file, but
|
||||
is appended with the timestamp of the conflict detection.
|
||||
|
||||
|
||||
.. _ignored-files-label:
|
||||
@@ -137,40 +146,40 @@ the timestamp of the conflict detection.
|
||||
Ignored Files
|
||||
-------------
|
||||
|
||||
ownCloud Client supports that certain files are excluded or ignored from
|
||||
the synchronization. There are a couple of system wide file patterns which
|
||||
come with the client. Custom patterns can be added by the user.
|
||||
The ownCloud Client supports the ability to exclude or ignore certain files
|
||||
from the synchronization process. Some system wide file patterns that are used
|
||||
to exclude or ignore files are included with the client by default and the
|
||||
ownCloud Client provides the ability to add custom patterns.
|
||||
|
||||
ownCloud Client will ignore the following files:
|
||||
By default, the ownCloud Client ignores the following files:
|
||||
|
||||
* Files matched by one of the pattern in :ref:`ignoredFilesEditor-label`
|
||||
* Files containing characters that do not work on certain file systems.
|
||||
Currently, these characters are: `\, :, ?, *, ", >, <, |`
|
||||
* Files starting in ``.csync_journal.db*`` (reserved for journalling)
|
||||
- Files matched by one of the patterns defined in :ref:`ignoredFilesEditor-label`.
|
||||
- Files containing characters that do not work on certain file systems (`\, :, ?, *, ", >, <, |`).
|
||||
* Files starting in ``.csync_journal.db*``, as these files are reserved for journalling.
|
||||
|
||||
If a pattern is checkmarked in the `ignoredFilesEditor-label` (or if a line in
|
||||
the exclude file starts with the character `]` directly followed
|
||||
by the file pattern), files matching this pattern are considered fleeting
|
||||
meta data. These files are ingored and *removed* by the client if found
|
||||
in the sync folder. This is suitable for meta files created by some
|
||||
If a pattern selected using a checkbox in the `ignoredFilesEditor-label` (or if
|
||||
a line in the exclude file starts with the character `]` directly followed by
|
||||
the file pattern), files matching the pattern are considered *fleeting meta
|
||||
data*. These files are ingored and *removed* by the client if found in the
|
||||
synchronized folder. This is suitable for meta files created by some
|
||||
applications that have no sustainable meaning.
|
||||
|
||||
If a pattern is ending with character `/` it means that only directories are
|
||||
matched. The pattern is only applied for directory components of the checked
|
||||
filename.
|
||||
If a pattern ends with the backslash (`/`) character, only directories are
|
||||
matched. The pattern is only applied for directory components of filenames
|
||||
selected using the checkbox.
|
||||
|
||||
To match file names against the exclude patterns, the unix standard C
|
||||
library function fnmatch is used. It checks the filename against the pattern
|
||||
using standard shell wildcard pattern matching. Check `The opengroup website
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01>`
|
||||
for the gory details.
|
||||
To match filenames against the exclude patterns, the unix standard C library
|
||||
function fnmatch is used. This procesx checks the filename against the
|
||||
specified pattern using standard shell wildcard pattern matching. For more
|
||||
information, please refer to `The opengroup website
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01>`.
|
||||
|
||||
The path that is checked is the relative path unter the sync root directory.
|
||||
The path that is checked is the relative path under the sync root directory.
|
||||
|
||||
**Pattern and File Match Examples:**
|
||||
|
||||
Examples:
|
||||
^^^^^^^^^
|
||||
+-----------+------------------------------+
|
||||
| Pattern | Matches |
|
||||
| Pattern | File Matches |
|
||||
+===========+==============================+
|
||||
| ``~$*`` | ``~$foo``, ``~$example.doc`` |
|
||||
+-----------+------------------------------+
|
||||
@@ -183,15 +192,17 @@ Examples:
|
||||
The Sync Journal
|
||||
----------------
|
||||
|
||||
The client stores the ETag number in a per-directory database,
|
||||
called the journal. It is a hidden file right in the directory
|
||||
to be synced.
|
||||
The client stores the ETag number in a per-directory database, called the
|
||||
*journal*. This database is a hidden file contained in the directory to be
|
||||
synchronized.
|
||||
|
||||
If the journal database gets removed, ownCloud Client's CSync backend will
|
||||
rebuild the database by comparing the files and their modification times. Thus
|
||||
it should be made sure that both server and client synchronized with NTP time
|
||||
before restarting the client after a database removal.
|
||||
If the journal database is removed, the ownCloud Client CSync backend rebuilds
|
||||
the database by comparing the files and their modification times. This process
|
||||
ensures that both server and client are synchronized using the appropriate NTP
|
||||
time before restarting the client following a database removal.
|
||||
|
||||
Pressing ``F5`` in the Account Settings Dialog that allows to "reset" the
|
||||
journal. That can be used to recreate the journal database. Use this only
|
||||
if advised to do so by the developer or support staff.
|
||||
Pressing ``F5`` while in the Account Settings Dialog enables you to "reset" the
|
||||
journal. This function can be used to recreate the journal database.
|
||||
|
||||
.. note:: We recommend that you use this function only when advised to do so by
|
||||
ownCloud support staff.
|
||||
|
||||
@@ -1,81 +1,126 @@
|
||||
The Automatic Updater
|
||||
=====================
|
||||
|
||||
To ensure you're always using the latest version of ownCloud Client, an
|
||||
auto-update mechanism has been added in Version 1.5.1. It will ensure
|
||||
that will automatically profit from the latest features and bugfixes.
|
||||
To ensure that you are always using the latest version of the ownCloud client,
|
||||
an auto-update mechanism has been added in Version 1.5.1. The Automatic Updater
|
||||
ensures that you automatically profit from the latest features and bugfixes.
|
||||
|
||||
The updater works differently depending on the operating system.
|
||||
.. note:: The Automatic Updater functions differently, depending on the operating system.
|
||||
|
||||
Basic Workflow
|
||||
--------------
|
||||
|
||||
The following sections describe how to use the Automatic Updater on different operating systems:
|
||||
|
||||
Windows
|
||||
^^^^^^^
|
||||
|
||||
ownCloud client will check for updates and download the update if one
|
||||
is available. You can view the status under ``Settings -> General -> Updates``.
|
||||
If an update is available and has been successfully downloaded, ownCloud
|
||||
Client will start a silent update prior to its next launch and then start itself.
|
||||
If the silent update fails, the client offers a manual download.
|
||||
The ownCloud client checks for updates and downloads them when available. You
|
||||
can view the update status under ``Settings -> General -> Updates`` in the
|
||||
ownCloud client.
|
||||
|
||||
.. note:: The user needs to be able to attain administrative privileges
|
||||
to successfully perform the update.
|
||||
If an update is available, and has been successfully downloaded, the ownCloud
|
||||
client starts a silent update prior to its next launch and then restarts
|
||||
itself. Should the silent update fail, the client offers a manual download.
|
||||
|
||||
.. note:: Administrative privileges are required to perform the update.
|
||||
|
||||
Mac OS X
|
||||
^^^^^^^^
|
||||
|
||||
If a new update is available, ownCloud client will ask the user to update
|
||||
to the latest version using a pop-up dialog. This is the default for Mac
|
||||
OS X applications which use the Sparkle framework.
|
||||
If a new update is available, the ownCloud client initializes a pop-up dialog
|
||||
to alert you of the update and requesting that you update to the latest
|
||||
version. Due to their use of the Sparkle frameworks, this is the default
|
||||
process for Mac OS X applications.
|
||||
|
||||
Linux
|
||||
^^^^^
|
||||
|
||||
Since distributions provide their own update tool, ownCloud Client on Linux
|
||||
will not perform any updates on its own. It will, however, check for the
|
||||
latest version and passively notify the user (``Settings -> General -> Updates``)
|
||||
if an update is available.
|
||||
Linux distributions provide their own update tool, so ownCloud clients that use
|
||||
the Linux operating system do not perform any updates on their own. Linux
|
||||
operating systems do, however, check for the latest version of the ownCloud
|
||||
client and passively notify the user (``Settings -> General -> Updates``) when
|
||||
an update is available.
|
||||
|
||||
|
||||
Preventing Auto Updates
|
||||
-----------------------
|
||||
Preventing Automatic Updates
|
||||
----------------------------
|
||||
|
||||
In controlled environment such as companies or universities, the auto-update
|
||||
mechanism might not be desired as it interferes with controlled deployment
|
||||
tools and policies. In this case, it is possible to disable the auto-updater
|
||||
entirely:
|
||||
In controlled environments, such as companies or universities, you might not
|
||||
want to enable the auto-update mechanism, as it interferes with controlled
|
||||
deployment tools and policies. To address this case, it is possible to disable
|
||||
the auto-updater entirely. The following sections describe how to disable the
|
||||
auto-update mechanism for different operating systems.
|
||||
|
||||
Windows
|
||||
^^^^^^^
|
||||
Preventing Automatic Updates in Windows Environents
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two alternative approaches:
|
||||
You can prevent automatic updates from occuring in Windows environments using
|
||||
one of two methods. The first method allows users to override the automatic
|
||||
update check mechanism whereas the second method prevents any manual overrides.
|
||||
|
||||
1. In ``HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud``, add a key ``skipUpdateCheck`` (of type DWORD) with the value 1 to the machine. This key
|
||||
can be manually overrideen by the same value in ``HKEY_CURRENT_USER``.
|
||||
To prevent automatic updates, but allow manual overrides:
|
||||
|
||||
2. In ``HKEY_LOCAL_MACHINE\Software\Policies\ownCloud\ownCloud``, add a key
|
||||
``skipUpdateCheck`` (of type DWORD) with the value 1 to the machine.
|
||||
Setting the value here cannot be overridden by the user and is the preferred
|
||||
way to control the updater behavior via Group Policies.
|
||||
1. Migrate to the following directory::
|
||||
|
||||
Mac OS X
|
||||
^^^^^^^^
|
||||
HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud
|
||||
|
||||
You can disable the update check via a system-wide ``.plist`` file located
|
||||
at ``/Library/Preferences/com.owncloud.desktopclient.plist``. Add a new root
|
||||
level item of type bool and the name ``skipUpdateCheck`` and set it to ``true``.
|
||||
You can also just copy the file
|
||||
``owncloud.app/Contents/Resources/deny_autoupdate_com.owncloud.desktopclient.plist```
|
||||
2. Add the key ``skipUpdateCheck`` (of type DWORD).
|
||||
|
||||
3. Specify a value of ``1`` to the machine.
|
||||
|
||||
To manually override this key, use the same value in ``HKEY_CURRENT_USER``.
|
||||
|
||||
To prevent automatic updates and disallow manual overrides:
|
||||
|
||||
.. note::This is the preferred method of controlling the updater behavior using Group Policies.
|
||||
|
||||
1. Migrate to the following directory::
|
||||
|
||||
HKEY_LOCAL_MACHINE\Software\Policies\ownCloud\ownCloud
|
||||
|
||||
2. Add the key ``skipUpdateCheck`` (of type DWORD).
|
||||
|
||||
3. Specify a value of ``1`` to the machine.
|
||||
|
||||
|
||||
Preventing Automatic Updates in Mac OS X Environments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can disable the automatic update mechanism in MAC OS X operating systems
|
||||
using the system-wide ``.plist`` file. To access this file:
|
||||
|
||||
1. Using the Windows explorer, migrate to the following location::
|
||||
|
||||
/Library/Preferences/
|
||||
|
||||
2. Locate and open the following file::
|
||||
|
||||
com.owncloud.desktopclient.plist
|
||||
|
||||
3. Add a new root level item of type ``bool``.
|
||||
|
||||
4. Name the item ``skipUpdateCheck``.
|
||||
|
||||
5. Set the item to ``true``.
|
||||
|
||||
Alternatively, you can copy the file
|
||||
``owncloud.app/Contents/Resources/deny_autoupdate_com.owncloud.desktopclient.plist``
|
||||
to ``/Library/Preferences/com.owncloud.desktopclient.plist``.
|
||||
|
||||
Linux
|
||||
^^^^^
|
||||
Preventing Automatic Updates in Linux Environments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Since there is no updating functionality, there is no need to remove the check.
|
||||
If you want to disable the check nontheless, open a file called
|
||||
``/etc/ownCloud/ownCloud.conf`` and add the following content::
|
||||
Because Linux does not provide automatic updating functionality, there is no
|
||||
need to remove the automatic-update check. However, if you want to disable
|
||||
this check:
|
||||
|
||||
[General]
|
||||
skipUpdateCheck=true
|
||||
1. Locate and open the following file::
|
||||
|
||||
/etc/ownCloud/ownCloud.conf
|
||||
|
||||
2. Add the following content to the file::
|
||||
|
||||
[General]
|
||||
skipUpdateCheck=true
|
||||
|
||||
|
||||
160
doc/building.rst
160
doc/building.rst
@@ -3,20 +3,20 @@
|
||||
Appendix A: Building the Client
|
||||
===============================
|
||||
|
||||
This section explains how to build the ownCloud Client from source
|
||||
for all major platforms. You should read this section if you want
|
||||
to development on the desktop client.
|
||||
This section explains how to build the ownCloud Client from source for all
|
||||
major platforms. You should read this section if you want to develop for the
|
||||
desktop client.
|
||||
|
||||
Note that the building instruction are subject to change as development
|
||||
proceeds. It is important to check the version which is to built.
|
||||
.. note:: Building instruction are subject to change as development proceeds.
|
||||
Please check the version for which you want to built.
|
||||
|
||||
This instructions were updated to work with ownCloud Client 1.5.
|
||||
The instructions contained in this topic were updated to work with version 1.5 of the ownCloud Client.
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
1. Add the `ownCloud repository from OBS`_.
|
||||
2. Install the dependencies (as root, or via sudo):
|
||||
2. Install the dependencies (as root, or using ``sudo``) using the following commands for your specific Linux distribution:
|
||||
|
||||
* Debian/Ubuntu: ``apt-get update; apt-get build-dep owncloud-client``
|
||||
* openSUSE: ``zypper ref; zypper si -d owncloud-client``
|
||||
@@ -27,47 +27,51 @@ Linux
|
||||
Mac OS X
|
||||
--------
|
||||
|
||||
Next to XCode (and the command line tools!), you will need some
|
||||
extra dependencies.
|
||||
In additon to needing XCode (along with the command line tools), developing in
|
||||
the MAC OS X environment requires extra dependencies. You can install these
|
||||
dependencies through MacPorts_ or Homebrew_. These dependencies are required
|
||||
only on the build machine, because non-standard libs are deployed in the app
|
||||
bundle.
|
||||
|
||||
You can install these dependencies via MacPorts_ or Homebrew_.
|
||||
This is only needed on the build machine, since non-standard libs
|
||||
will be deployed in the app bundle.
|
||||
The tested and preferred way to develop in this environment is through the use
|
||||
of HomeBrew_. The ownCloud team has its own repository containing non-standard
|
||||
recipes.
|
||||
|
||||
The tested and preferred way is to use HomeBrew_. The ownCloud team has
|
||||
its own repository which contains non-standard recipes. Add it with::
|
||||
To set up your build enviroment for development using HomeBrew_:
|
||||
|
||||
1. Add the ownCloud repository using the following command::
|
||||
|
||||
brew tap owncloud/owncloud
|
||||
|
||||
Next, install the missing dependencies::
|
||||
2. Install any missing dependencies::
|
||||
|
||||
brew install $(brew deps mirall)
|
||||
|
||||
|
||||
To build mirall, follow the `generic build instructions`_.
|
||||
|
||||
.. note::
|
||||
You should not call ``make install`` at any time, since the product of the
|
||||
mirall build is an app bundle. Call ``make package`` instead to create an
|
||||
install-ready disk image.
|
||||
.. note:: Because the product from the mirall build is an app bundle, do not
|
||||
call ``make install`` at any time. Instead, call ``make package`` to create an
|
||||
install-ready disk image.
|
||||
|
||||
Windows (cross-compile)
|
||||
Windows (Cross-Compile)
|
||||
-----------------------
|
||||
|
||||
Due to the amount of dependencies, building the client for Windows
|
||||
is **currently only supported on openSUSE**, by using the MinGW
|
||||
cross compiler. You can set up openSUSE 12.1, 12.2 or 13.1 in a virtual machine
|
||||
if you do not have it installed already.
|
||||
Due to the large number of dependencies, building the client for Windows is
|
||||
**currently only supported on openSUSE**, by using the MinGW cross compiler.
|
||||
You can set up openSUSE 12.1, 12.2, or 13.1 in a virtual machine if you do not
|
||||
have it installed already.
|
||||
|
||||
In order to cross-compile, the following repositories need to be added
|
||||
via YaST or ``zypper ar`` (adjust when using openSUSE 12.2 or 13.1)::
|
||||
To cross-compile:
|
||||
|
||||
zypper ar http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_13.1/windows:mingw:win32.repo
|
||||
zypper ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_13.1/windows:mingw.repo
|
||||
1. Add the following repositories using YaST or ``zypper ar`` (adjust when using openSUSE 12.2 or 13.1):
|
||||
|
||||
Next, install the cross-compiler packages and the cross-compiled dependencies::
|
||||
- ``zypper ar http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_13.1/windows:mingw:win32.repo``
|
||||
|
||||
zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
|
||||
- ``zypper ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_13.1/windows:mingw.repo``
|
||||
|
||||
2. Install the cross-compiler packages and the cross-compiled dependencies::
|
||||
|
||||
``zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
|
||||
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
|
||||
mingw32-headers mingw32-runtime site-config mingw32-libqt4-sql \
|
||||
mingw32-libqt4-sql-sqlite mingw32-sqlite mingw32-libsqlite-devel \
|
||||
@@ -78,74 +82,86 @@ Next, install the cross-compiler packages and the cross-compiled dependencies::
|
||||
mingw32-libpng-devel mingw32-libsqlite mingw32-qtkeychain \
|
||||
mingw32-qtkeychain-devel mingw32-dlfcn mingw32-libintl-devel \
|
||||
mingw32-libneon-devel mingw32-libopenssl-devel mingw32-libproxy-devel \
|
||||
mingw32-libxml2-devel mingw32-zlib-devel
|
||||
mingw32-libxml2-devel mingw32-zlib-devel``
|
||||
|
||||
For the installer, the NSIS installer package is also required::
|
||||
3. For the installer, install the NSIS installer package::
|
||||
|
||||
zypper install mingw32-cross-nsis
|
||||
``zypper install mingw32-cross-nsis``
|
||||
|
||||
.. Usually, the following would be needed as well, but due to a bug in mingw, they
|
||||
will currently not build properly from source.
|
||||
4. Install the following plugin::
|
||||
|
||||
mingw32-cross-nsis-plugin-processes mingw32-cross-nsis-plugin-uac
|
||||
``mingw32-cross-nsis-plugin-processes mingw32-cross-nsis-plugin-uac``
|
||||
|
||||
You will also need to manually download and install the following files with
|
||||
``rpm -ivh <package>`` (They will also work with openSUSE 12.2 and newer)::
|
||||
.. note:: This plugin is typically required. However, due to a current bug
|
||||
in ``mingw``, the plugins do not currently build properly from source.
|
||||
|
||||
rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-processes-0-1.1.x86_64.rpm
|
||||
rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-uac-0-3.1.x86_64.rpm
|
||||
5. Manually download and install the following files using ``rpm -ivh <package>``:
|
||||
|
||||
Now, follow the `generic build instructions`_, but pay attention to
|
||||
the following differences:
|
||||
..note:: These files operate using openSUSE 12.2 and newer.
|
||||
|
||||
For building for windows a special toolchain file has to be specified.
|
||||
That makes cmake finding the platform specific tools. This parameter
|
||||
has to be added to the call to cmake:
|
||||
- ``rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-processes-0-1.1.x86_64.rpm``
|
||||
|
||||
``-DCMAKE_TOOLCHAIN_FILE=../mirall/admin/win/Toolchain-mingw32-openSUSE.cmake``
|
||||
- ``rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-uac-0-3.1.x86_64.rpm``
|
||||
|
||||
Finally, just build by running ``make``. ``make package`` will produce
|
||||
an NSIS-based installer, provided the NSIS mingw32 packages are installed.
|
||||
6. Follow the `generic build instructions`_
|
||||
|
||||
.. note:: When building for Windows platforms, you must specify a special
|
||||
toolchain file that enables cmake to locate the platform-specific tools. To add
|
||||
this parameter to the call to cmake, enter
|
||||
``DCMAKE_TOOLCHAIN_FILE=../mirall/admin/win/Toolchain-mingw32-openSUSE.cmake``.
|
||||
|
||||
7. Build by running ``make``.
|
||||
|
||||
..note:: Using ``make package`` produces an NSIS-based installer, provided
|
||||
the NSIS mingw32 packages are installed.
|
||||
|
||||
Generic Build Instructions
|
||||
--------------------------
|
||||
.. _`generic build instructions`
|
||||
|
||||
Compared to previous versions building of Mirall has become more easy.
|
||||
CSync, which is the sync engine library of Mirall, is now part of the
|
||||
Mirall source repository, not, like it was before, a separate module.
|
||||
Compared to previous versions, building Mirall has become easier. Unlike
|
||||
earlier versions, CSync, which is the sync engine library of Mirall, is now
|
||||
part of the Mirall source repository and not a separate module.
|
||||
|
||||
Mirall can be downloaded at ownCloud's `Client Download Page`_.
|
||||
You can download Mirall from the ownCloud `Client Download Page`_.
|
||||
|
||||
If you want to build the leading edge version of the client, you should
|
||||
use the latest versions of Mirall via Git_, like so::
|
||||
To build the most up to date version of the client:
|
||||
|
||||
git clone git://github.com/owncloud/mirall.git
|
||||
1. Clone the latest versions of Mirall from Git_ as follows:
|
||||
|
||||
Next, create build directories::
|
||||
``git clone git://github.com/owncloud/mirall.git``
|
||||
|
||||
mkdir mirall-build
|
||||
2. Create build directories:
|
||||
|
||||
Now build mirall::
|
||||
``mkdir mirall-build``
|
||||
|
||||
cd ../mirall-build
|
||||
cmake -DCMAKE_BUILD_TYPE="Debug" ../mirall
|
||||
3. Build mirall:
|
||||
|
||||
Note that it is important to use absolute pathes for the include- and library
|
||||
directories. If this succeeds, call ``make``. The owncloud binary should appear
|
||||
in the ``bin`` directory. You can also run ``make install`` to install the client to
|
||||
``/usr/local/bin``.
|
||||
``cd ../mirall-build``
|
||||
``cmake -DCMAKE_BUILD_TYPE="Debug" ../mirall``
|
||||
|
||||
To build an installer/app bundle (requires the mingw32-cross-nsis packages on Windows)::
|
||||
..note:: You must use absolute pathes for the ``include`` and ``library`` directories.
|
||||
|
||||
make package
|
||||
4. Call ``make``.
|
||||
|
||||
Known cmake parameters:
|
||||
The owncloud binary appear in the ``bin`` directory.
|
||||
|
||||
* QTKEYCHAIN_LIBRARY=/path/to/qtkeychain.dylib -DQTKEYCHAIN_INCLUDE_DIR=/path/to/qtkeychain/: Use QtKeychain for stored credentials. When compiling with Qt5, the library is called qt5keychain.dylib. You need to compile QtKeychain with the same Qt version.
|
||||
* WITH_DOC=TRUE: create doc and manpages via running ``make``; also adds install statements to be able to install it via ``make install``.
|
||||
* CMAKE_PREFIX_PATH=/path/to/Qt5.2.0/5.2.0/yourarch/lib/cmake/ : to build with Qt5
|
||||
* BUILD_WITH_QT4=ON : to build with Qt4 even if Qt5 is found
|
||||
5. (Optional) Call ``make install`` to install the client to the ``/usr/local/bin`` directory.
|
||||
|
||||
6. (Optional) Call ``make package`` to build an installer/app bundle
|
||||
|
||||
..note:: This step requires the ``mingw32-cross-nsis`` packages be installed on Windows.
|
||||
|
||||
The following are known cmake parameters:
|
||||
|
||||
* ``QTKEYCHAIN_LIBRARY=/path/to/qtkeychain.dylib -DQTKEYCHAIN_INCLUDE_DIR=/path/to/qtkeychain/``:
|
||||
Used for stored credentials. When compiling with Qt5, the library is called ``qt5keychain.dylib.``
|
||||
You need to compile QtKeychain with the same Qt version.
|
||||
* ``WITH_DOC=TRUE``: Creates doc and manpages through running ``make``; also
|
||||
* adds install statements, providing the ability to install using ``make
|
||||
* install``.
|
||||
* ``CMAKE_PREFIX_PATH=/path/to/Qt5.2.0/5.2.0/yourarch/lib/cmake/``: Builds using Qt5.
|
||||
* ``BUILD_WITH_QT4=ON``: Builds using Qt4 (even if Qt5 is found).
|
||||
|
||||
.. _`ownCloud repository from OBS`: http://software.opensuse.org/download/package?project=isv:ownCloud:devel&package=owncloud-client
|
||||
.. _CSync: http://www.csync.org
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user