Comparar commits
215 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 305a4ceb9c | |||
| e718148b05 | |||
| caaec4a99f | |||
| a88b46137a | |||
| 7a436498f9 | |||
| fc96459997 | |||
| 19ca3150de | |||
| d8326b76ea | |||
| fbe5e8ff5a | |||
| 8febd90f2a | |||
| bf18ecae13 | |||
| 89971925ca | |||
| 2ba007ee4f | |||
| d1cc3c34c9 | |||
| de79f9338a | |||
| 5471bfd5a8 | |||
| 1543899795 | |||
| 6d94acee8f | |||
| 9ae4d45243 | |||
| 1cd5681967 | |||
| 7c36e5c0e6 | |||
| 1b62ed1e7e | |||
| 66595a3597 | |||
| 4960890d70 | |||
| 76f0f3cbf2 | |||
| f5f04bcc4b | |||
| c232411e96 | |||
| 7ec0c52439 | |||
| 2aef6a2174 | |||
| 6e0330ff65 | |||
| 3aa7178382 | |||
| b037e6356e | |||
| 824628061b | |||
| 449abace66 | |||
| 8cd1d43798 | |||
| acd3df33b6 | |||
| 1bc8fd9b49 | |||
| 12f5e4b46e | |||
| 21783ecef7 | |||
| 6d24bd0361 | |||
| 22c1629dd3 | |||
| 8df14ee845 | |||
| 550d6d66d1 | |||
| 7480d34742 | |||
| 04cc513bbd | |||
| f004d5085d | |||
| 3d0c009719 | |||
| 208011f6ab | |||
| f84e0010ee | |||
| c97f46d403 | |||
| 1fb52f0d8b | |||
| d4de024f15 | |||
| 1d9d88ca85 | |||
| 81d786733d | |||
| 336e74b992 | |||
| beb9300b4e | |||
| c35880d4f1 | |||
| d8ebebaf12 | |||
| af3fae9c28 | |||
| d3b72940fd | |||
| e8de3e855a | |||
| 71338000a4 | |||
| 8961e61f60 | |||
| d697969f36 | |||
| 51e9c5fd96 | |||
| 0202351a27 | |||
| 3477ea0eeb | |||
| 63cd5ef563 | |||
| 82c254fecf | |||
| 86bea9a9af | |||
| 88f26fb548 | |||
| a9f1de84f0 | |||
| 2f284209d8 | |||
| 09881040a3 | |||
| 9066ad5790 | |||
| 62d0e670dc | |||
| 40d765c73a | |||
| 23e0af5cc1 | |||
| 48864a6921 | |||
| 92f07cb60f | |||
| fbadadc377 | |||
| 9adc30ab9f | |||
| 8de3bda0b1 | |||
| 3c4f410a4e | |||
| 9c0a21a5fb | |||
| b735dc07d6 | |||
| 68c902e60b | |||
| e19214c3c4 | |||
| 02704cdf74 | |||
| a7d251f8fc | |||
| 7a8a3855b8 | |||
| 603a238eb9 | |||
| b7b6cf4b3f | |||
| c855b783d9 | |||
| f593fc8e4d | |||
| ae5cbb8451 | |||
| 041066a252 | |||
| 9ca82ba14d | |||
| b29a757b18 | |||
| 485a6926c5 | |||
| f3de6f46db | |||
| 1309dc27d9 | |||
| 31469d6a3e | |||
| 88776770f7 | |||
| bbf8b9f8dd | |||
| 6ff38d8005 | |||
| 6d13b5cc43 | |||
| 73ab2804c4 | |||
| db3d2eed5f | |||
| d995d1190f | |||
| 3217e42a0f | |||
| 1dd58a537e | |||
| b34afa1afc | |||
| b7c9fa6d5f | |||
| 61ad376bf4 | |||
| 407b3bebfe | |||
| f04c80dd0e | |||
| 1e788d3d60 | |||
| 83171bf025 | |||
| 2e51721851 | |||
| 4d4a0148e4 | |||
| b144a5bbf9 | |||
| 5225fe07e0 | |||
| 85cdbd1f1d | |||
| e4f8a136f1 | |||
| c263c38cdf | |||
| df8553e878 | |||
| bec66c85d4 | |||
| f9710cc1d5 | |||
| 6b041b0846 | |||
| d0c992c991 | |||
| 9ee86cf06b | |||
| 71a901a24e | |||
| 02355696ff | |||
| 38254125c9 | |||
| e5b3363ecf | |||
| 646eafb05d | |||
| 0880444e37 | |||
| 0a953b91f9 | |||
| b71881d300 | |||
| b91967f4d9 | |||
| c759e8bb8f | |||
| b83f6c0b3a | |||
| ade92d8ac1 | |||
| a5967e4ecd | |||
| 2f361278d2 | |||
| 319cf76417 | |||
| be7b08b50a | |||
| 2d234cd96f | |||
| 1230e87330 | |||
| b2966fecc7 | |||
| 4abe00ff6c | |||
| 61999a67cd | |||
| e1db834ec9 | |||
| 2caa69e0cb | |||
| c72c72a106 | |||
| 4a5ef8f173 | |||
| ed26bcb3e7 | |||
| 18e9357aaf | |||
| 46b8260693 | |||
| d5bd3190d4 | |||
| 8dbfcd782b | |||
| 70ff928381 | |||
| b48ab79a92 | |||
| 9a7fbd4f71 | |||
| ef3b4956ad | |||
| fd4642d827 | |||
| 6dd248e527 | |||
| 7d00c3646a | |||
| e355e12385 | |||
| 34b31c0146 | |||
| 3934fa019e | |||
| dc53e96f92 | |||
| 7fcf6f9f79 | |||
| b814b45e50 | |||
| ded8914df2 | |||
| bd48ab23c3 | |||
| 4e28ba73bb | |||
| 16cb37ecd0 | |||
| 7a7b0e8939 | |||
| d4d630b2e9 | |||
| a4f6370774 | |||
| 2ff27cdd63 | |||
| 2f81167164 | |||
| 6897c5d41f | |||
| 233450d850 | |||
| 7428a8fa63 | |||
| 18359d7871 | |||
| df12a58e3d | |||
| 4b3d124b5a | |||
| 51e941e7b5 | |||
| 62ea6f316f | |||
| 6605a89990 | |||
| 4cb9b3a85b | |||
| 806ab8ea46 | |||
| 582a8fe7fd | |||
| 08ca8b54b1 | |||
| abafbef985 | |||
| 6e10b8c5c4 | |||
| 06863ca9c6 | |||
| e49b8981dd | |||
| 24616bead4 | |||
| 2e91557c28 | |||
| 4d4eab8b1c | |||
| 13f9970257 | |||
| 4d4ae9374b | |||
| b8e20b412c | |||
| e36f3c5b10 | |||
| 8a55f831f4 | |||
| 0dcc9be5c1 | |||
| 5ee00a8df7 | |||
| 1af3d3f18b | |||
| f54248c0a7 | |||
| 2911c0e1c4 | |||
| 16d35c1489 |
@@ -108,7 +108,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()
|
||||
|
||||
@@ -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_MINOR 7 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "prealpha") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -111,8 +111,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
|
||||
@@ -151,6 +151,12 @@ UninstPage custom un.UnPageUserAppData un.UnPageUserAppDataLeave
|
||||
!include ${source_path}/admin/win/nsi/l10n/languages.nsh
|
||||
!include ${source_path}/admin/win/nsi/l10n/declarations.nsh
|
||||
|
||||
; Set version strings with english locale
|
||||
VIProductVersion "${VERSION}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "${APPLICATION_NAME}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "${APPLICATION_VENDOR}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION}"
|
||||
|
||||
!macro SETLANG un
|
||||
Function ${un}SetLang
|
||||
# load the selected language file
|
||||
@@ -407,15 +413,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${QT_DLL_PATH}\Qt5Xml.dll"
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng15-15.dll"
|
||||
File "${MING_BIN}\icudata51.dll"
|
||||
File "${MING_BIN}\icui18n51.dll"
|
||||
File "${MING_BIN}\icuuc51.dll"
|
||||
File "${MING_BIN}\libpng16-16.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}\libpng15-15.dll"
|
||||
File "${MING_BIN}\libproxy.dll"
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
@@ -442,6 +447,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
;MinGW stuff
|
||||
File "${MING_BIN}\libgcc_s_sjlj-1.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwinpthread-1.dll"
|
||||
|
||||
; CSync configs
|
||||
File "${SOURCE_PATH}/sync-exclude.lst"
|
||||
|
||||
@@ -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")
|
||||
@@ -65,10 +66,15 @@ endif()
|
||||
qt5_add_resources(${ARGN})
|
||||
endmacro()
|
||||
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
find_package(Qt5LinguistTools REQUIRED)
|
||||
macro(qt_add_translation)
|
||||
qt5_add_translation(${ARGN})
|
||||
endmacro()
|
||||
else()
|
||||
macro(qt_add_translation)
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
macro(qt_add_dbus_interface)
|
||||
qt5_add_dbus_interface(${ARGN})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#cmakedefine HAVE_UTIMES 1
|
||||
#cmakedefine HAVE_LSTAT 1
|
||||
#cmakedefine HAVE_FNMATCH 1
|
||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ICONV 1
|
||||
#cmakedefine HAVE_ICONV_CONST 1
|
||||
|
||||
@@ -31,5 +30,6 @@
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ASPRINTF 1
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
|
||||
@@ -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;
|
||||
@@ -209,9 +177,9 @@ int csync_init(CSYNC *ctx) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx->status = CSYNC_STATUS_INIT;
|
||||
ctx->remote.root_perms = 0;
|
||||
|
||||
csync_set_module_property(ctx, "csync_context", ctx);
|
||||
ctx->status = CSYNC_STATUS_INIT;
|
||||
|
||||
/* initialize random generator */
|
||||
srand(time(NULL));
|
||||
@@ -219,7 +187,6 @@ int csync_init(CSYNC *ctx) {
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
SAFE_FREE(config);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -234,7 +201,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 +214,6 @@ int csync_update(CSYNC *ctx) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
@@ -277,33 +242,26 @@ int csync_update(CSYNC *ctx) {
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
|
||||
csync_memstat_check();
|
||||
|
||||
if (rc < 0) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@@ -436,14 +394,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;
|
||||
@@ -466,7 +425,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);
|
||||
}
|
||||
@@ -599,6 +558,7 @@ static void _csync_clean_ctx(CSYNC *ctx)
|
||||
ctx->local.ignored_cleanup = 0;
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
SAFE_FREE(ctx->remote.root_perms);
|
||||
}
|
||||
|
||||
int csync_commit(CSYNC *ctx) {
|
||||
@@ -617,7 +577,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 : "");
|
||||
@@ -676,9 +636,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
|
||||
@@ -710,70 +671,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;
|
||||
@@ -789,15 +686,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;
|
||||
@@ -841,33 +729,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);
|
||||
@@ -912,6 +773,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);
|
||||
@@ -920,7 +783,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;
|
||||
}
|
||||
|
||||
@@ -229,6 +235,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
|
||||
type = CSYNC_FILE_EXCLUDE_LIST;
|
||||
if (strlen(pattern) < 1) {
|
||||
SAFE_FREE(pattern_stored);
|
||||
continue;
|
||||
}
|
||||
/* Ecludes starting with ']' means it can be cleanup */
|
||||
@@ -264,6 +271,9 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
|
||||
if (bname == NULL || dname == NULL) {
|
||||
match = CSYNC_NOT_EXCLUDED;
|
||||
SAFE_FREE(bname);
|
||||
SAFE_FREE(dname);
|
||||
SAFE_FREE(pattern_stored);
|
||||
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->code);
|
||||
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,10 +715,20 @@ 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;
|
||||
} else {
|
||||
/* The first item is the root item, memorize its permissions */
|
||||
if (!ctx->remote.root_perms) {
|
||||
if (strlen(currResource->remotePerm) > 0) {
|
||||
/* Only copy if permissions contain something. Empty string means server didn't return them */
|
||||
ctx->remote.root_perms = c_strdup(currResource->remotePerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the target URI */
|
||||
@@ -984,39 +738,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 +797,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 */
|
||||
|
||||
@@ -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,22 +165,21 @@ 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); */
|
||||
} else {
|
||||
/* DEBUG_WEBDAV("results_recursive No parent %s found for child %s", parentPath, newres->uri); */
|
||||
resource_free(newres);
|
||||
newres = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resource_free(newres);
|
||||
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;
|
||||
@@ -257,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 );
|
||||
}
|
||||
@@ -272,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,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;
|
||||
}
|
||||
}
|
||||
@@ -302,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>");
|
||||
}
|
||||
|
||||
@@ -317,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,178 @@ 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);
|
||||
}
|
||||
/* DEBUG_WEBDAV("fill_webdav_properties_into_resource %s >%p< ", newres->name, perm ); */
|
||||
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;
|
||||
@@ -126,22 +115,15 @@ struct csync_s {
|
||||
enum csync_replica_e type;
|
||||
int read_from_db;
|
||||
c_list_t *ignored_cleanup;
|
||||
const char *root_perms; /* Permission of the root folder. (Since the root folder is not in the db tree, we need to keep a separate entry.) */
|
||||
} remote;
|
||||
|
||||
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;
|
||||
|
||||
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
|
||||
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 +144,8 @@ struct csync_s {
|
||||
volatile int abort;
|
||||
void *rename_info;
|
||||
int read_from_db_disabled;
|
||||
|
||||
struct csync_owncloud_ctx_s *owncloud_context;
|
||||
};
|
||||
|
||||
|
||||
@@ -174,8 +158,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 +167,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!");
|
||||
@@ -238,8 +240,8 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
/* file on other replica is changed or new */
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_EVAL:
|
||||
if (other->type == CSYNC_VIO_FILE_TYPE_DIRECTORY &&
|
||||
cur->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
|
||||
if (other->type == CSYNC_FTW_TYPE_DIR &&
|
||||
cur->type == CSYNC_FTW_TYPE_DIR) {
|
||||
is_equal_files = (other->modtime == cur->modtime);
|
||||
} else {
|
||||
is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
|
||||
@@ -249,8 +251,12 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
|
||||
if( !cur->etag && other->etag ) cur->etag = c_strdup(other->etag);
|
||||
cur->should_update_etag = true; /* update DB */
|
||||
/* update DB with new etag from remote */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
other->should_update_etag = true;
|
||||
} else {
|
||||
cur->should_update_etag = true;
|
||||
}
|
||||
} else if(ctx->current == REMOTE_REPLICA) {
|
||||
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
|
||||
other->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
@@ -57,29 +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) return;
|
||||
|
||||
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;
|
||||
@@ -155,6 +133,8 @@ static int _csync_statedb_check(const char *statedb) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
/* if it comes here, the database is broken and should be recreated. */
|
||||
_tunlink(wstatedb);
|
||||
@@ -166,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);
|
||||
@@ -320,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);
|
||||
|
||||
@@ -335,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;
|
||||
@@ -474,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;
|
||||
@@ -529,7 +512,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
if( rc != SQLITE_DONE ) {
|
||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%ld entries read below path %s from db.", cnt, path);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
SAFE_FREE(likepath);
|
||||
|
||||
@@ -140,6 +140,14 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
/* This code should probably be in csync_exclude, but it does not have the fs parameter.
|
||||
Keep it here for now and TODO also find out if we want this for Windows
|
||||
https://github.com/owncloud/mirall/issues/2086 */
|
||||
if (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if file is excluded */
|
||||
excluded = csync_excluded(ctx, path,type);
|
||||
|
||||
@@ -254,26 +262,31 @@ 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;
|
||||
} else {
|
||||
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
|
||||
/* tmp might point to malloc mem, so free it here before reusing tmp */
|
||||
SAFE_FREE(tmp);
|
||||
|
||||
/* check if it's a file and has been renamed */
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
|
||||
@@ -361,8 +374,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;
|
||||
@@ -371,6 +382,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;
|
||||
@@ -586,9 +608,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) {
|
||||
@@ -643,7 +670,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)) {
|
||||
@@ -671,8 +701,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,12 +113,12 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
|
||||
fileName = c_utf8_to_locale( file );
|
||||
dwAttrs = GetFileAttributesW(fileName);
|
||||
|
||||
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;
|
||||
|
||||
if (h && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
} else if (!h && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs & ~FILE_ATTRIBUTE_HIDDEN );
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
if (h && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
} else if (!h && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs & ~FILE_ATTRIBUTE_HIDDEN );
|
||||
}
|
||||
}
|
||||
|
||||
c_free_locale_string(fileName);
|
||||
@@ -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 */
|
||||
|
||||
@@ -204,9 +204,9 @@ void hbf_free_transfer( hbf_transfer_t *transfer ) {
|
||||
|
||||
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
|
||||
hbf_block_t *block = transfer->block_arr[cnt];
|
||||
if( !block ) continue;
|
||||
if( block->http_error_msg ) free( block->http_error_msg );
|
||||
if( block->etag ) free( block->etag );
|
||||
if( block ) free(block);
|
||||
}
|
||||
free( transfer->block_arr );
|
||||
free( transfer->url );
|
||||
@@ -536,8 +536,8 @@ Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const cha
|
||||
} else {
|
||||
state = HBF_MEMORY_FAIL;
|
||||
}
|
||||
free( transfer_url );
|
||||
}
|
||||
free( transfer_url );
|
||||
}
|
||||
|
||||
/* do the source file validation finally (again). */
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -135,7 +135,8 @@ int c_utimes(const char *uri, const struct timeval *times) {
|
||||
if(!SetFileTime(hFile, NULL, &LastAccessTime, &LastModificationTime)) {
|
||||
//can this happen?
|
||||
errno=ENOENT;
|
||||
CloseHandle(hFile);
|
||||
CloseHandle(hFile);
|
||||
c_free_locale_string(wuri);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,12 +34,15 @@
|
||||
|
||||
#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 {
|
||||
CSYNC_VIO_FILE_FLAGS_NONE = 0,
|
||||
CSYNC_VIO_FILE_FLAGS_SYMLINK = 1 << 0,
|
||||
CSYNC_VIO_FILE_FLAGS_LOCAL = 1 << 1
|
||||
CSYNC_VIO_FILE_FLAGS_HIDDEN = 1 << 1
|
||||
};
|
||||
|
||||
enum csync_vio_file_type_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);
|
||||
|
||||
@@ -224,12 +224,10 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
break;
|
||||
} while (0);
|
||||
/* TODO Do we want to parse for CSYNC_VIO_FILE_FLAGS_HIDDEN ? */
|
||||
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;
|
||||
|
||||
@@ -240,7 +238,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
/* printf("Index: %I64i\n", FileIndex.QuadPart); */
|
||||
buf->inode = FileIndex.QuadPart;
|
||||
|
||||
buf->size = (fileInfo.nFileSizeHigh * (int64_t)(MAXDWORD+1)) + fileInfo.nFileSizeLow;
|
||||
buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
|
||||
/* Get the file time with a win32 call rather than through stat. See
|
||||
@@ -260,6 +258,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
|
||||
}
|
||||
|
||||
c_free_locale_string(wuri);
|
||||
CloseHandle(h);
|
||||
|
||||
return 0;
|
||||
@@ -315,7 +314,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 */
|
||||
@@ -323,6 +322,11 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
} else {
|
||||
buf->flags = CSYNC_VIO_FILE_FLAGS_NONE;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
if (sb.st_flags & UF_HIDDEN) {
|
||||
buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
|
||||
}
|
||||
#endif
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
|
||||
|
||||
buf->device = sb.st_dev;
|
||||
@@ -331,11 +335,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;
|
||||
|
||||
@@ -348,12 +347,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);
|
||||
|
||||
@@ -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." );
|
||||
|
||||
@@ -185,12 +185,34 @@ 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);
|
||||
assert( ! -e localDir().'superNewDir' );
|
||||
|
||||
$inode2 = getInode('superNewDir/f3');
|
||||
assert( $inode == $inode2, "Inode of f3 changed");
|
||||
$inode2 = getInode('superNewDir');
|
||||
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,7 +30,6 @@ 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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
ownCloud Client reads a configuration file.
|
||||
The ownCloud Client reads a configuration file. You can locate this configuration files as follows:
|
||||
|
||||
On Linux it can be found in:
|
||||
- On Linux distributions:
|
||||
``$HOME/.local/share/data/ownCloud/owncloud.cfg``
|
||||
|
||||
On Windows it can be found in:
|
||||
- In Microsoft Windows systems:
|
||||
``%LOCALAPPDATA%\ownCloud\owncloud.cfg``
|
||||
|
||||
On Mac it can be found in:
|
||||
- In MAC OS X systems:
|
||||
``$HOME/Library/Application Support/ownCloud``
|
||||
|
||||
|
||||
It contains settings in the ini file format known from Windows.
|
||||
The configuration file contains settings using the Microsoft Windows .ini file
|
||||
format. You can overwrite changes using the ownCloud configuration dialog.
|
||||
|
||||
.. note:: Changes here should be done carefully as wrong settings can cause disfunctionality.
|
||||
.. note:: Use caution when making changes to the ownCloud Client configuration
|
||||
file. Incorrect settings can produce unintended results.
|
||||
|
||||
.. note:: Changes may be overwritten by using ownCloud's configuration dialog.
|
||||
You can change the following configuration settings:
|
||||
|
||||
These are config settings that may be changed:
|
||||
- ``remotePollInterval`` (default: ``30000``) -- Specifies the poll time for the remote repository in milliseconds.
|
||||
|
||||
``remotePollInterval`` (default: ``30000``)
|
||||
Poll time for the remote repository in milliseconds
|
||||
|
||||
``maxLogLines`` (default: ``20000``)
|
||||
Maximum count of log lines shown in the log window
|
||||
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
FAQ
|
||||
===
|
||||
|
||||
Some files are continuously uploaded to the server even when they are not modified
|
||||
----------------------------------------------------------------------------------
|
||||
**Issue:**
|
||||
|
||||
Some files are continuously uploaded to the server, even when they are not modified.
|
||||
|
||||
**Resolution:**
|
||||
|
||||
It is possible that another program is changing the modification date of the file.
|
||||
|
||||
If the file is a ``.eml`` file, Windows automatically change all file all the time unless you remove
|
||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers`` from
|
||||
the windows registry.
|
||||
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/
|
||||
|
||||
|
||||
|
||||
If the file is uses the ``.eml`` extention, Windows automatically and
|
||||
continually changes all files, unless you remove
|
||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers`
|
||||
from the windows registry.
|
||||
|
||||
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/ for more information.
|
||||
|
||||
|
Depois Largura: | Altura: | Tamanho: 34 KiB |
|
Depois Largura: | Altura: | Tamanho: 21 KiB |
|
Depois Largura: | Altura: | Tamanho: 19 KiB |
|
Depois Largura: | Altura: | Tamanho: 30 KiB |
|
Depois Largura: | Altura: | Tamanho: 25 KiB |
|
Depois Largura: | Altura: | Tamanho: 33 KiB |
|
Depois Largura: | Altura: | Tamanho: 33 KiB |
|
Depois Largura: | Altura: | Tamanho: 28 KiB |
|
Depois Largura: | Altura: | Tamanho: 30 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.1 KiB |
|
Depois Largura: | Altura: | Tamanho: 43 KiB |
|
Depois Largura: | Altura: | Tamanho: 7.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 34 KiB |
|
Depois Largura: | Altura: | Tamanho: 33 KiB |
|
Depois Largura: | Altura: | Tamanho: 24 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 32 KiB |
|
Depois Largura: | Altura: | Tamanho: 40 KiB |
|
Depois Largura: | Altura: | Tamanho: 36 KiB |
|
Depois Largura: | Altura: | Tamanho: 32 KiB |
|
Depois Largura: | Altura: | Tamanho: 71 KiB |
|
Depois Largura: | Altura: | Tamanho: 46 KiB |
|
Depois Largura: | Altura: | Tamanho: 12 KiB |
|
Depois Largura: | Altura: | Tamanho: 66 KiB |
|
Depois Largura: | Altura: | Tamanho: 13 KiB |
@@ -4,11 +4,12 @@ Contents
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 3
|
||||
|
||||
introduction
|
||||
installing
|
||||
accountsetup
|
||||
visualtour
|
||||
navigating
|
||||
advancedusage
|
||||
autoupdate
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
.. _installing-linux:
|
||||
|
||||
Installing the Linux Desktop Client
|
||||
===================================
|
||||
|
||||
The ownCloud Desktop Client is provided for a wide range of Linux
|
||||
distributions. The following table provides a list of Linux operating systems
|
||||
and the specific distributions on which you can install the Desktop Client.
|
||||
|
||||
+------------------+-------------------------+
|
||||
| Operating System | Distribution |
|
||||
+==================+=========================+
|
||||
| CentOS (Redhat) | - Red Hat RHEL-6 |
|
||||
| | - CentOS CentOS-6 |
|
||||
+------------------+-------------------------+
|
||||
| Debian | - Debian 7.0 |
|
||||
| | - Fedora 19 |
|
||||
| | - Fedora 20 |
|
||||
+------------------+-------------------------+
|
||||
| openSUSE | - openSUSE |
|
||||
| | - Factory PPC |
|
||||
| | - openSUSE Factory ARM |
|
||||
| | - openSUSE Factory |
|
||||
| | - openSUSE 13.1 Ports |
|
||||
| | - openSUSE 13.1 |
|
||||
| | - openSUSE 12.3 Ports |
|
||||
| | - openSUSE 12.3 |
|
||||
| | - openSUSE 12.2 |
|
||||
+------------------+-------------------------+
|
||||
| SUSE (SLE) | - SLE 11 SP3 |
|
||||
+------------------+-------------------------+
|
||||
| Ubuntu | - xUbuntu 14.04 |
|
||||
| | - xUbuntu 13.10 |
|
||||
| | - xUbuntu 12.10 |
|
||||
| | - xUbuntu 12.04 |
|
||||
+------------------+-------------------------+
|
||||
|
||||
General instructions for how to install the ownCloud Desktop Client on any
|
||||
supported Linux distribution can be found on the `ownCloud download page
|
||||
<http://software.opensuse.org/download/package?project=isv:ownCloud:desktop&package=owncloud-client>`_.
|
||||
|
||||
Linux Installation Methods
|
||||
--------------------------
|
||||
|
||||
You can install the ownCloud Desktop Client using either of the following three methods:
|
||||
|
||||
- One Click Install (openSUSE and SUSE SLE distributions only) — Installs the
|
||||
ownCloud Desktop using a bundled installation package.
|
||||
- Adding the ownCloud package repository — Installs the ownCloud Desktop client
|
||||
using a Linux terminal and keeps it up to date using the distribution's
|
||||
package manager.
|
||||
|
||||
.. note::
|
||||
|
||||
Manual command line installation requires that you perform the installation as root.
|
||||
|
||||
- Binary package — Installs the ownCloud Desktop Client using a raw binary package.
|
||||
|
||||
Installing the Desktop Client on Redhat or CentOS Linux Operating Systems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To install the ownCloud Desktop Client on a Redhat or CentOS operating system manually:
|
||||
|
||||
1. Open a Linux terminal window.
|
||||
|
||||
2. Specify the directory in which you want to install the client.
|
||||
|
||||
``cd /etc/yum.repos.d/``
|
||||
|
||||
3. Choose and download the client for your specific distribution:
|
||||
|
||||
* Red Hat RHEL-6: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/RedHat_RHEL-6/isv:ownCloud:desktop.repo``
|
||||
* CentOS CentOS-6: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/CentOS_CentOS-6/isv:ownCloud:desktop.repo``
|
||||
|
||||
4. Install the client.
|
||||
|
||||
``yum install owncloud-client``
|
||||
|
||||
5. After the installation completes, go to Setting Up the ownCloud Desktop Client.
|
||||
|
||||
**Installing the Desktop Client on Debian 7.0 Linux Operating Systems Manually**
|
||||
|
||||
To install the ownCloud Desktop Client on the Debian 7.0 distribution manually:
|
||||
|
||||
1. Open a Linux terminal window.
|
||||
|
||||
2. Download the client.
|
||||
|
||||
``echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Debian_7.0/ /' >> /etc/apt/sources.list.d/owncloud-client.list``
|
||||
|
||||
3. Download the package lists from any repositories and updates them to ensure the latest package versions and their dependencies.
|
||||
|
||||
``apt-get update``
|
||||
|
||||
4. Install the client.
|
||||
|
||||
``apt-get install owncloud-client``
|
||||
|
||||
5. (Optional) Download the apt-key for the Debian repository
|
||||
|
||||
``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/Debian_7.0/Release.key``
|
||||
|
||||
6. After the installation completes, go to Setting Up the ownCloud Desktop Client.
|
||||
|
||||
Installing the Desktop Client on Fedora Linux Operating Systems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To install the ownCloud Desktop Client on the Fedora operating system manually:
|
||||
|
||||
1. Open a Linux terminal window.
|
||||
2. Specify the directory in which you want to install the client.
|
||||
|
||||
cd /etc/yum.repos.d/
|
||||
|
||||
3. Choose and download the client for your specific distribution
|
||||
|
||||
* Fedora 19: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/Fedora_19/isv:ownCloud:desktop.repo``
|
||||
* Fedora 20: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/Fedora_20/isv:ownCloud:desktop.repo``
|
||||
|
||||
4. Install the client.
|
||||
|
||||
``yum install owncloud-client``
|
||||
|
||||
5. After the installation completes, go to Setting Up the ownCloud Desktop Client.
|
||||
|
||||
Installing the Desktop Client on openSUSE Linux Operating Systems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To install the ownCloud Desktop Client on the openSUSE operating system manually:
|
||||
|
||||
1. Open a Linux terminal window.
|
||||
|
||||
2. Choose and download the client for your specific distribution:
|
||||
|
||||
* Factory PPC: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_Factory_PPC/isv:ownCloud:desktop.repo``
|
||||
* **Factory ARM**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_Factory_ARM/isv:ownCloud:desktop.repo``
|
||||
* **Factory**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_Factory/isv:ownCloud:desktop.repo``
|
||||
* **13.1 Ports**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_13.1_Ports/isv:ownCloud:desktop.repo``
|
||||
* **13.1**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_13.1/isv:ownCloud:desktop.repo``
|
||||
* **12.3 Ports**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_12.3_Ports/isv:ownCloud:desktop.repo``
|
||||
* **12.3**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_12.3/isv:ownCloud:desktop.repo``
|
||||
* **12.2**: ``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/openSUSE_12.2/isv:ownCloud:desktop.repo``
|
||||
|
||||
3. Download any package metadata from the medium and store it in local cache.
|
||||
|
||||
``zypper refresh``
|
||||
|
||||
4. Install the client.
|
||||
|
||||
``zypper install owncloud-client``
|
||||
|
||||
5. After the installation completes, go to Setting Up the ownCloud Desktop Client.
|
||||
|
||||
Installing the Desktop Client on SLE Linux Operating Systems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To install the ownCloud Desktop Client on the SUSE Linux Enterprise (SLE) operating system.
|
||||
|
||||
1. Open a Linux terminal window.
|
||||
|
||||
2. Download the client.
|
||||
|
||||
``zypper addrepo http://download.opensuse.org/repositories/isv:ownCloud:desktop/SLE_11_SP3/isv:ownCloud:desktop.repo``
|
||||
|
||||
3. Download any package metadata from the medium and store it in local cache.
|
||||
|
||||
``zypper refresh``
|
||||
|
||||
4. Install the client.
|
||||
|
||||
``zypper install owncloud-client``
|
||||
|
||||
5. After the installation completes, go to Setting Up the ownCloud Desktop Client.
|
||||
|
||||
Installing the Desktop Client on Ubuntu Linux Operating Systems
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To install the ownCloud Desktop Client on the Ubuntu operating system:
|
||||
|
||||
1. Open a Linux terminal window.
|
||||
|
||||
2. Choose and download the client for your specific distribution:
|
||||
|
||||
* **xUbuntu 14.04**: ``sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/xUbuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"``
|
||||
* **xUbuntu 13.10**: ``sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/xUbuntu_13.10/ /' >> /etc/apt/sources.list.d/owncloud-client.list"``
|
||||
* **xUbuntu 12.10**: ``sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/xUbuntu_12.10/ /' >> /etc/apt/sources.list.d/owncloud-client.list"``
|
||||
* **xUbuntu 12.04**: ``sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/xUbuntu_12.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"``
|
||||
|
||||
3. Download the package lists from any repositories and updates them to ensure the latest package versions and their dependencies.
|
||||
|
||||
``apt-get update``
|
||||
|
||||
4. Install the client.
|
||||
|
||||
``sudo apt-get install owncloud-client``
|
||||
|
||||
5. (Optional) Download the apt-key for the Ubuntu repository:
|
||||
|
||||
* **xUbuntu 14.04**: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/xUbuntu_14.04/Release.key``
|
||||
* **xUbuntu 13.10**: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/xUbuntu_13.10/Release.key``
|
||||
* **xUbuntu 12.10**: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/xUbuntu_12.10/Release.key``
|
||||
* **xUbuntu 12.04**: ``wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/xUbuntu_12.04/Release.key``
|
||||
|
||||
6. (Optional) Add the apt key.
|
||||
|
||||
``sudo apt-key add - < Release.key``
|
||||
|
||||
7. After the installation completes, go to `Setting Up the ownCloud Desktop Client`_.
|
||||
@@ -0,0 +1,4 @@
|
||||
.. _installing-macosx:
|
||||
|
||||
Installing the MAC OSX Desktop Client
|
||||
=====================================
|
||||
@@ -0,0 +1,102 @@
|
||||
.. _installing-windows:
|
||||
|
||||
Installing the Windows Desktop Client
|
||||
=====================================
|
||||
|
||||
The ownCloud desktop client for Windows is provided as a Nullsoft Scriptable Install System (NSIS) setup file for machine-wide installation.
|
||||
|
||||
To install the ownCloud desktop client:
|
||||
|
||||
1. Access the ownCloud website.
|
||||
|
||||
The ownCloud web page opens.
|
||||
|
||||
.. image:: images/oc_website.png
|
||||
|
||||
ownCloud Web Page
|
||||
|
||||
2. Select Products > Desktop Clients from the website menu.
|
||||
|
||||
The Desktop Client download page opens.
|
||||
|
||||
.. image:: images/oc_client_download_options.png
|
||||
|
||||
Desktop client download selections
|
||||
|
||||
3. Click the 'Download for Windows' option.
|
||||
The Desktop Client download page opens.
|
||||
|
||||
.. image:: images/oc_client_windows_download.png
|
||||
|
||||
ownCloud Windows Client Download
|
||||
|
||||
4. Click the 'download' button.
|
||||
|
||||
The Microsoft Windows client download begins. Depending on your browser
|
||||
settings, the client installation file might launch automatically.
|
||||
|
||||
5. Once the download completes, locate the client installation file in your system Downloads folder.
|
||||
|
||||
6. Double-click the client installation file to start the download.
|
||||
|
||||
The Open File - Security Warning dialog box opens.
|
||||
|
||||
.. image:: images/security_warning_windows.png
|
||||
|
||||
Open File - Security Warning dialog box
|
||||
|
||||
7. Click 'Run' in the dialog box to begin the installation.
|
||||
|
||||
On systems running virus protection software, you might have to verify
|
||||
that you want to install the ownCloud Desktop Client software.
|
||||
|
||||
8. Click 'Yes' to continue with the software installation.
|
||||
|
||||
The ownCloud Setup Wizard window opens.
|
||||
|
||||
.. image:: images/client_setup_wizard_main.png
|
||||
|
||||
ownCloud Setup Wizard Window
|
||||
|
||||
9. Click 'Next' to continue.
|
||||
|
||||
The Choose Components window opens.
|
||||
|
||||
.. image:: images/client_setup_wizard_components.png
|
||||
|
||||
Choose Components Window
|
||||
|
||||
10. Choose the components that you want to install for the Desktop Client.
|
||||
|
||||
All relevant components for your platform are selected by default.
|
||||
However, you can choose to exlude different components from the installation.
|
||||
|
||||
11. Click Next to continue.
|
||||
|
||||
The Choose Install Location window opens.
|
||||
|
||||
.. image:: images/client_setup_wizard_location.png
|
||||
|
||||
Choose Install Location window
|
||||
|
||||
12. Verify the destination folder for the Desktop Client installation and then click Install.
|
||||
|
||||
The Installing window opens.
|
||||
|
||||
.. image:: images/client_setup_wizard_install_progress.png
|
||||
|
||||
Installing window
|
||||
|
||||
13. Once the installation completes, click 'Next' to continue.
|
||||
|
||||
The Setup Wizard Completion window opens.
|
||||
|
||||
.. image:: images/client_setup_wizard_install_finish.png
|
||||
|
||||
Completion window
|
||||
|
||||
You can choose to launch the Desktop Client from this window or launch the application at another time.
|
||||
|
||||
14. Click 'Finish' to complete the installation.
|
||||
|
||||
After the installation completes, go to Setting Up the ownCloud Desktop Client.
|
||||
@@ -0,0 +1,13 @@
|
||||
Installing the Synchronization Client
|
||||
=====================================
|
||||
|
||||
The latest version of the ownCloud Synchronization Client can be obtained from
|
||||
the `ownCloud Website <http://www.owncloud.com>`_. You can download and install
|
||||
the client on Windows, MAC OSX, and various Linux software distrubutions. The
|
||||
following sections describe specific support and installation procedures for
|
||||
the different software platforms:
|
||||
|
||||
- :ref:`installing-windows`
|
||||
- :ref:`installing-macosx`
|
||||
- :ref:`installing-linux`
|
||||
|
||||
@@ -1,32 +1,14 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
The ownCloud Sync Client is a desktop program installed on a user’s computer.
|
||||
It allows a user to specify one or more directories on the local machine to
|
||||
sync to the ownCloud server. It allows the user to always have the latest
|
||||
files wherever they may be. When a change is made to the file on the
|
||||
computer, it will sync to the ownCloud server via the sync client.
|
||||
Available for Windows, MAC OS X, and various Linux distributions, the ownCloud
|
||||
Sync client is a desktop program installed on your computer. The client enables
|
||||
you to:
|
||||
|
||||
The ownCloud Sync Client is available for Windows, MAC OS X, and various
|
||||
Linux distributions.
|
||||
- Specify one or more directories on your computer that you want to synchronize
|
||||
to the ownCloud server.
|
||||
- Always have the latest files synchronized, wherever they are located.
|
||||
|
||||
Obtaining the Client
|
||||
--------------------
|
||||
Changes made to any synchronized file on the computer are automatically made to
|
||||
the files on the ownCloud server using the sync client.
|
||||
|
||||
The latest version of the Client can be obtained on the ownCloud web site.
|
||||
|
||||
ownCloud client for **Windows** is provided as a NSIS-based setup file for
|
||||
machine-wide install. Installing the ownCloud client on **Mac OS** follows
|
||||
the normal app bundle installation pattern:
|
||||
|
||||
1. Download the installation file: Click ``ownCloud-x.y.z.dmg``, a window with
|
||||
the ownCloud icon opens.
|
||||
2. In that window, drag the ownCloud application into the ``Applications``
|
||||
folder.
|
||||
3. On the right hand side From ``Applications``, choose ``ownCloud``.
|
||||
|
||||
The ownCloud client is also provided as in a convenient repository for a wide
|
||||
range of popular **Linux distributions**.
|
||||
|
||||
Supported distributions are Fedora, openSUSE, Ubuntu and Debian.
|
||||
To support other distributions, a is required, see :ref:`building-label`
|
||||
|
||||