Comparar commits
126 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 | |||
| 81d786733d | |||
| 336e74b992 | |||
| 8961e61f60 | |||
| 3477ea0eeb | |||
| 2f284209d8 | |||
| 09881040a3 | |||
| 9066ad5790 | |||
| 62d0e670dc | |||
| 48864a6921 | |||
| 92f07cb60f | |||
| fbadadc377 | |||
| 8de3bda0b1 | |||
| 3c4f410a4e | |||
| 9c0a21a5fb | |||
| b735dc07d6 | |||
| 68c902e60b | |||
| e19214c3c4 | |||
| 02704cdf74 | |||
| 71a901a24e | |||
| 02355696ff | |||
| 38254125c9 | |||
| e5b3363ecf | |||
| c759e8bb8f | |||
| b83f6c0b3a | |||
| ade92d8ac1 | |||
| a5967e4ecd | |||
| 2f361278d2 | |||
| 319cf76417 | |||
| be7b08b50a | |||
| 61999a67cd | |||
| 2caa69e0cb | |||
| 18e9357aaf | |||
| 46b8260693 | |||
| d5bd3190d4 | |||
| 8dbfcd782b | |||
| 70ff928381 | |||
| b48ab79a92 | |||
| 9a7fbd4f71 | |||
| ef3b4956ad | |||
| fd4642d827 | |||
| 6dd248e527 | |||
| 7d00c3646a | |||
| e355e12385 | |||
| 34b31c0146 | |||
| 3934fa019e | |||
| dc53e96f92 | |||
| 7fcf6f9f79 | |||
| bd48ab23c3 | |||
| 4e28ba73bb | |||
| 16cb37ecd0 | |||
| d4d630b2e9 | |||
| 2ff27cdd63 | |||
| 2f81167164 | |||
| 6897c5d41f | |||
| 233450d850 | |||
| 7428a8fa63 | |||
| 18359d7871 | |||
| df12a58e3d | |||
| 4b3d124b5a | |||
| 51e941e7b5 | |||
| 62ea6f316f | |||
| 4cb9b3a85b | |||
| 806ab8ea46 | |||
| 582a8fe7fd | |||
| 08ca8b54b1 | |||
| abafbef985 | |||
| 06863ca9c6 | |||
| e49b8981dd | |||
| 2e91557c28 | |||
| 4d4eab8b1c | |||
| 4d4ae9374b | |||
| b8e20b412c | |||
| e36f3c5b10 | |||
| 8a55f831f4 | |||
| 0dcc9be5c1 | |||
| 5ee00a8df7 | |||
| 1af3d3f18b | |||
| f54248c0a7 | |||
| 2911c0e1c4 | |||
| 16d35c1489 |
+1
-1
@@ -3,4 +3,4 @@
|
||||
url = https://github.com/owncloud/documentation
|
||||
[submodule "src/3rdparty/qtmacgoodies"]
|
||||
path = src/3rdparty/qtmacgoodies
|
||||
url = git://github.com/guruz/qtmacgoodies.git
|
||||
url = git://github.com/shadone/qtmacgoodies.git
|
||||
|
||||
+4
-1
@@ -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
-23
@@ -1,28 +1,6 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 1.6.4 (release 2014-10-xx)
|
||||
* Fix startup logic, fixes bug #1989
|
||||
* Fix raise dialog on X11
|
||||
* Win32: fix overflow when computing the size of file > 4GiB
|
||||
* Use a fixed function to get files modification time, the
|
||||
original one was broken for certain timezone issues, see
|
||||
core bug #9781 for details
|
||||
* Added some missing copyright headers
|
||||
* Avoid data corruption due to wrong error handling, bug #2280
|
||||
* Do improved request timeout handling to reduce the number of
|
||||
timed out jobs, bug #2155
|
||||
|
||||
version 1.6.3 (release 2014-09-03)
|
||||
* Fixed updater on OS X
|
||||
* Fixed memory leak in SSL button that could lead to quick memory draining
|
||||
* Fixed upload problem with files >4 GB
|
||||
* MacOSX, Linux: Bring Settings window to front properly
|
||||
* Branded clients: If no configuration is detected, try to import the data
|
||||
from a previously configured community edition.
|
||||
|
||||
version 1.6.2 (release 2014-07-28 )
|
||||
* Limit the HTTP buffer size when downloading to limit memory consumption.
|
||||
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.
|
||||
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
set( MIRALL_VERSION_MAJOR 1 )
|
||||
set( MIRALL_VERSION_MINOR 6 )
|
||||
set( MIRALL_VERSION_PATCH 4 )
|
||||
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 )
|
||||
|
||||
@@ -23,8 +23,6 @@ fix_frameworks() {
|
||||
mkdir -p "${FMWK_PATH}/Versions/${QT_FMWK_VERSION}/Resources/"
|
||||
cp -avf "${QT_FMWK_PATH}/${FMWK}/Contents/Info.plist" "${FMWK_PATH}/Versions/${QT_FMWK_VERSION}/Resources"
|
||||
(cd "${FMWK_PATH}" && ln -sf "Versions/${QT_FMWK_VERSION}/Resources" "Resources")
|
||||
(cd "${FMWK_PATH}" && ln -sf "Versions/${QT_FMWK_VERSION}/${FMWK_NAME}")
|
||||
(cd "${FMWK_PATH}/Versions" && ln -sf "${QT_FMWK_VERSION}" "Current")
|
||||
perl -pi -e "s/${FMWK_NAME}_debug/${FMWK_NAME}/" "${FMWK_PATH}/Resources/Info.plist"
|
||||
done
|
||||
}
|
||||
@@ -32,9 +30,6 @@ fix_frameworks() {
|
||||
mount="/Volumes/$(basename "$src_dmg"|sed 's,-\([0-9]\)\(.*\),,')"
|
||||
test -e "$tmp_dmg" && rm -rf "$tmp_dmg"
|
||||
hdiutil convert "$src_dmg" -format UDRW -o "$tmp_dmg"
|
||||
#signing adds data, add a bit of space
|
||||
sectors=$(hdiutil resize -limits "$tmp_dmg" |grep -v cur|cut -f2)
|
||||
hdiutil resize -sectors $(($sectors+(51200))) "$tmp_dmg"
|
||||
hdiutil attach "$tmp_dmg"
|
||||
pushd "$mount"
|
||||
fix_frameworks "$mount"/*.app `qmake -query QT_INSTALL_LIBS` "$mount"/*.app/Contents/Frameworks
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# Always include srcdir and builddir in include path
|
||||
# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in
|
||||
# about every subdir
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# define system dependent compiler flags
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
@@ -17,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")
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
if (UNIX)
|
||||
# Suffix for Linux
|
||||
SET(LIB_SUFFIX
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# Set system vars
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# This module defines
|
||||
# INOTIFY_INCLUDE_DIR, where to find inotify.h, etc.
|
||||
# INOTIFY_FOUND, If false, do not try to use inotify.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# FIND_PACKAGE_VERSION_CHECK(NAME (DEFAULT_MSG|"Custom failure message"))
|
||||
# This function is intended to be used in FindXXX.cmake modules files.
|
||||
# It handles NAME_FIND_VERSION and NAME_VERSION variables in a Module.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
find_program(PDFLATEX_EXECUTABLE NAMES pdflatex
|
||||
HINTS
|
||||
$ENV{PDFLATEX_DIR}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# - Try to find QtKeychain
|
||||
# Once done this will define
|
||||
# QTKEYCHAIN_FOUND - System has QtKeychain
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# - Try to find QtKeychain
|
||||
# Once done this will define
|
||||
# QTKEYCHAIN_FOUND - System has QtKeychain
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
find_program(SPHINX_EXECUTABLE NAMES sphinx-build
|
||||
HINTS
|
||||
$ENV{SPHINX_DIR}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# - macro_copy_file(_src _dst)
|
||||
# Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst}
|
||||
#
|
||||
|
||||
@@ -378,7 +378,6 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
; Make sure only to copy qt, not qt_help, etc
|
||||
File "${MING_SHARE}\qt5\translations\qt_??.qm"
|
||||
File "${MING_SHARE}\qt5\translations\qt_??_??.qm"
|
||||
File "${MING_SHARE}\qt5\translations\qtbase_*.qm"
|
||||
File "${MING_SHARE}\qt5\translations\qtkeychain_*.qm"
|
||||
|
||||
SetOutPath "$INSTDIR\platforms"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
include (MacroOptionalFindPackage)
|
||||
include (MacroLogFeature)
|
||||
|
||||
@@ -23,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")
|
||||
@@ -69,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})
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# -helper macro to add a "doc" target with CMake build system.
|
||||
# and configure doxy.config.in to doxy.config
|
||||
#
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# (c) 2014 Copyright ownCloud, Inc.
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION)
|
||||
@@ -10,9 +6,11 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
|
||||
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif(CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
# TODO: handle msvc compilers warnings?
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@ include(MacroCopyFile)
|
||||
if (NOT WIN32)
|
||||
find_package(Iconv)
|
||||
endif (NOT WIN32)
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
include(AddCMockaTest)
|
||||
endif (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
|
||||
include(ConfigureChecks.cmake)
|
||||
|
||||
@@ -47,9 +43,13 @@ endif (MEM_NULL_TESTS)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
if (UNIT_TESTING)
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
include(AddCMockaTest)
|
||||
add_subdirectory(tests)
|
||||
endif (CMOCKA_FOUND)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h)
|
||||
configure_file(config_test.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_test.h)
|
||||
|
||||
@@ -96,10 +96,10 @@ include_directories(
|
||||
)
|
||||
|
||||
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
|
||||
add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
|
||||
#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
|
||||
|
||||
target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES})
|
||||
target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
|
||||
#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${CSYNC_LIBRARY}
|
||||
|
||||
+32
-164
@@ -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;
|
||||
|
||||
@@ -278,27 +243,25 @@ int csync_update(CSYNC *ctx) {
|
||||
csync_memstat_check();
|
||||
|
||||
/* update detection for remote replica */
|
||||
if( ! ctx->options.local_only_mode ) {
|
||||
csync_gettime(&start);
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
csync_gettime(&start);
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
|
||||
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK)
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Update detection for remote replica took %.2f seconds "
|
||||
"walking %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
|
||||
csync_memstat_check();
|
||||
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK)
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
csync_gettime(&finish);
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
||||
"Update detection for remote replica took %.2f seconds "
|
||||
"walking %zu files.",
|
||||
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
|
||||
csync_memstat_check();
|
||||
|
||||
ctx->status |= CSYNC_STATUS_UPDATE;
|
||||
|
||||
return 0;
|
||||
@@ -431,14 +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;
|
||||
@@ -461,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);
|
||||
}
|
||||
@@ -594,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) {
|
||||
@@ -612,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 : "");
|
||||
@@ -671,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
|
||||
@@ -705,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;
|
||||
@@ -784,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;
|
||||
@@ -836,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);
|
||||
@@ -907,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);
|
||||
@@ -915,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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-104
@@ -44,13 +44,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* csync file declarations
|
||||
*/
|
||||
#define CSYNC_CONF_DIR ".ocsync"
|
||||
#define CSYNC_CONF_FILE "ocsync.conf"
|
||||
#define CSYNC_EXCLUDE_FILE "ocsync_exclude.conf"
|
||||
|
||||
/**
|
||||
* Instruction enum. In the file traversal structure, it describes
|
||||
* the csync state of a file.
|
||||
@@ -59,7 +52,7 @@ enum csync_status_codes_e {
|
||||
CSYNC_STATUS_OK = 0,
|
||||
|
||||
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
|
||||
just use in csync_status_ok */
|
||||
*/
|
||||
CSYNC_STATUS_UNSUCCESSFUL,
|
||||
CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */
|
||||
CSYNC_STATUS_STATEDB_LOAD_ERROR,
|
||||
@@ -172,13 +165,6 @@ struct csync_tree_walk_file_s {
|
||||
int64_t size;
|
||||
int64_t inode;
|
||||
time_t modtime;
|
||||
#ifdef _WIN32
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
#else
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
#endif
|
||||
mode_t mode;
|
||||
enum csync_ftw_type_e type;
|
||||
enum csync_instructions_e instruction;
|
||||
@@ -189,6 +175,9 @@ struct csync_tree_walk_file_s {
|
||||
const char *rename_path;
|
||||
const char *etag;
|
||||
const char *file_id;
|
||||
const char *remotePerm;
|
||||
char *directDownloadUrl;
|
||||
char *directDownloadCookies;
|
||||
struct {
|
||||
int64_t size;
|
||||
time_t modtime;
|
||||
@@ -214,14 +203,6 @@ typedef void (*csync_log_callback) (int verbosity,
|
||||
const char *buffer,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Check internal csync status.
|
||||
*
|
||||
* @param csync The context to check.
|
||||
*
|
||||
* @return true if status is error free, false for error states.
|
||||
*/
|
||||
bool csync_status_ok(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Allocate a csync context.
|
||||
@@ -333,62 +314,6 @@ int csync_add_exclude_list(CSYNC *ctx, const char *path);
|
||||
*/
|
||||
void csync_clear_exclude_list(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the config directory.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return The path of the config directory or NULL on error.
|
||||
*/
|
||||
const char *csync_get_config_dir(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Change the config directory.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @param path The path to the new config directory.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_set_config_dir(CSYNC *ctx, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Remove the complete config directory.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_remove_config_dir(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Enable the usage of the statedb. It is enabled by default.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_enable_statedb(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Disable the usage of the statedb. It is enabled by default.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_disable_statedb(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Check if the statedb usage is enabled.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return 1 if it is enabled, 0 if it is disabled.
|
||||
*/
|
||||
int csync_is_statedb_disabled(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the userdata saved in the context.
|
||||
*
|
||||
@@ -481,31 +406,6 @@ void *csync_get_log_userdata(void);
|
||||
*/
|
||||
int csync_set_log_userdata(void *data);
|
||||
|
||||
/**
|
||||
* @brief Get the path of the statedb file used.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
*
|
||||
* @return The path to the statedb file, NULL if an error occured.
|
||||
*/
|
||||
const char *csync_get_statedb_file(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* @brief Flag to tell csync that only a local run is intended. Call before csync_init
|
||||
*
|
||||
* @param local_only Bool flag to indicate local only mode.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int csync_set_local_only( CSYNC *ctx, bool local_only );
|
||||
|
||||
/**
|
||||
* @brief Retrieve the flag to tell csync that only a local run is intended.
|
||||
*
|
||||
* @return 1: stay local only, 0: local and remote mode
|
||||
*/
|
||||
bool csync_get_local_only( CSYNC *ctx );
|
||||
|
||||
/* Used for special modes or debugging */
|
||||
CSYNC_STATUS csync_get_status(CSYNC *ctx);
|
||||
|
||||
|
||||
@@ -20,12 +20,18 @@
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_exclude.h"
|
||||
@@ -217,7 +223,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
SAFE_FREE(bname);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
if (ctx->excludes == NULL) {
|
||||
if (ctx == NULL || ctx->excludes == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,52 +47,6 @@
|
||||
#include "csync_macros.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
char *csync_get_user_home_dir(void) {
|
||||
wchar_t tmp[MAX_PATH];
|
||||
char *szPath = NULL;
|
||||
|
||||
if( SHGetFolderPathW( NULL,
|
||||
CSIDL_PROFILE|CSIDL_FLAG_CREATE,
|
||||
NULL,
|
||||
0,
|
||||
tmp) == S_OK ) {
|
||||
szPath = c_utf8_from_locale(tmp);
|
||||
return szPath;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else /* ************* !WIN32 ************ */
|
||||
|
||||
#ifndef NSS_BUFLEN_PASSWD
|
||||
#define NSS_BUFLEN_PASSWD 4096
|
||||
#endif /* NSS_BUFLEN_PASSWD */
|
||||
|
||||
char *csync_get_user_home_dir(void) {
|
||||
const char *envp;
|
||||
struct passwd pwd;
|
||||
struct passwd *pwdbuf;
|
||||
char buf[NSS_BUFLEN_PASSWD];
|
||||
int rc;
|
||||
|
||||
envp = getenv("HOME");
|
||||
if (envp != NULL && envp[0] != '\0') {
|
||||
return c_strdup(envp);
|
||||
}
|
||||
|
||||
/* Still nothing found, read the password file */
|
||||
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||
if (rc != 0) {
|
||||
return c_strdup(pwd.pw_dir);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* ************* WIN32 ************ */
|
||||
|
||||
#ifdef HAVE_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
||||
#endif
|
||||
|
||||
char *csync_get_user_home_dir(void);
|
||||
|
||||
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
|
||||
|
||||
/**
|
||||
|
||||
+165
-400
@@ -20,79 +20,10 @@
|
||||
*/
|
||||
|
||||
#include "csync_owncloud.h"
|
||||
#include "csync_owncloud_private.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
* free the fetchCtx
|
||||
*/
|
||||
static void free_fetchCtx( struct listdir_context *ctx )
|
||||
{
|
||||
struct resource *newres, *res;
|
||||
if( ! ctx ) return;
|
||||
newres = ctx->list;
|
||||
res = newres;
|
||||
|
||||
ctx->ref--;
|
||||
if (ctx->ref > 0) return;
|
||||
|
||||
SAFE_FREE(ctx->target);
|
||||
|
||||
while( res ) {
|
||||
SAFE_FREE(res->uri);
|
||||
SAFE_FREE(res->name);
|
||||
SAFE_FREE(res->md5);
|
||||
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
|
||||
|
||||
newres = res->next;
|
||||
SAFE_FREE(res);
|
||||
res = newres;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* local variables.
|
||||
*/
|
||||
|
||||
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
|
||||
int _connected = 0; /* flag to indicate if a connection exists, ie.
|
||||
the dav_session is valid */
|
||||
|
||||
|
||||
void *_userdata;
|
||||
long long chunked_total_size = 0;
|
||||
long long chunked_done = 0;
|
||||
|
||||
struct listdir_context *propfind_cache = 0;
|
||||
|
||||
bool is_first_propfind = true;
|
||||
|
||||
|
||||
csync_vio_file_stat_t _stat_cache;
|
||||
/* id cache, cache the ETag: header of a GET request */
|
||||
struct { char *uri; char *id; } _id_cache = { NULL, NULL };
|
||||
|
||||
static void clean_caches() {
|
||||
clear_propfind_recursive_cache();
|
||||
|
||||
free_fetchCtx(propfind_cache);
|
||||
propfind_cache = NULL;
|
||||
|
||||
SAFE_FREE(_stat_cache.name);
|
||||
SAFE_FREE(_stat_cache.etag );
|
||||
memset( _stat_cache.file_id, 0, FILE_ID_BUF_SIZE+1 );
|
||||
|
||||
SAFE_FREE(_id_cache.uri);
|
||||
SAFE_FREE(_id_cache.id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define PUT_BUFFER_SIZE 1024*5
|
||||
|
||||
char _buffer[PUT_BUFFER_SIZE];
|
||||
|
||||
/*
|
||||
* helper method to build up a user text for SSL problems, called from the
|
||||
@@ -116,7 +47,7 @@ static void addSSLWarning( char *ptr, const char *warn, int len )
|
||||
* it to the csync callback to ask the user.
|
||||
*/
|
||||
#define LEN 4096
|
||||
static int verify_sslcert(void *userdata, int failures,
|
||||
static int ssl_callback_by_neon(void *userdata, int failures,
|
||||
const ne_ssl_certificate *certificate)
|
||||
{
|
||||
char problem[LEN];
|
||||
@@ -124,8 +55,8 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
int ret = -1;
|
||||
const ne_ssl_certificate *cert = certificate;
|
||||
csync_auth_callback authcb = NULL;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
(void) userdata;
|
||||
memset( problem, 0, LEN );
|
||||
|
||||
while( cert ) {
|
||||
@@ -161,14 +92,14 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
}
|
||||
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
|
||||
|
||||
if( dav_session.csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
||||
if( ctx->csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
||||
}
|
||||
if( authcb ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for SSL problems");
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||
if( buf[0] == 'y' || buf[0] == 'Y') {
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -184,41 +115,39 @@ static int verify_sslcert(void *userdata, int failures,
|
||||
* Authentication callback. Is set by ne_set_server_auth to be called
|
||||
* from the neon lib to authenticate a request.
|
||||
*/
|
||||
static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
||||
char *username, char *password)
|
||||
{
|
||||
char buf[NE_ABUFSIZ];
|
||||
csync_auth_callback authcb = NULL;
|
||||
int re = attempt;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
(void) userdata;
|
||||
(void) realm;
|
||||
|
||||
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
|
||||
if( username && password ) {
|
||||
DEBUG_WEBDAV( "Authentication required %s", username );
|
||||
if( dav_session.user ) {
|
||||
if( ctx->dav_session.user ) {
|
||||
/* allow user without password */
|
||||
if( strlen( dav_session.user ) < NE_ABUFSIZ ) {
|
||||
strcpy( username, dav_session.user );
|
||||
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
|
||||
strcpy( username, ctx->dav_session.user );
|
||||
}
|
||||
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
|
||||
strcpy( password, dav_session.pwd );
|
||||
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
|
||||
strcpy( password, ctx->dav_session.pwd );
|
||||
}
|
||||
} else {
|
||||
if( dav_session.csync_ctx ) {
|
||||
authcb = csync_get_auth_callback( dav_session.csync_ctx );
|
||||
}
|
||||
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
||||
if( authcb != NULL ){
|
||||
/* call the csync callback */
|
||||
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
|
||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||
if( strlen(buf) < NE_ABUFSIZ ) {
|
||||
strcpy( username, buf );
|
||||
}
|
||||
memset( buf, 0, NE_ABUFSIZ );
|
||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
|
||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
|
||||
if( strlen(buf) < NE_ABUFSIZ) {
|
||||
strcpy( password, buf );
|
||||
}
|
||||
@@ -235,15 +164,15 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
|
||||
* from the neon lib to authenticate against a proxy. The data to authenticate
|
||||
* against comes from mirall throught vio_module_init function.
|
||||
*/
|
||||
static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
|
||||
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
||||
char *username, char *password)
|
||||
{
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
(void) realm;
|
||||
if( dav_session.proxy_user && strlen( dav_session.proxy_user ) < NE_ABUFSIZ) {
|
||||
strcpy( username, dav_session.proxy_user );
|
||||
if( dav_session.proxy_pwd && strlen( dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
||||
strcpy( password, dav_session.proxy_pwd );
|
||||
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
|
||||
strcpy( username, ctx->dav_session.proxy_user );
|
||||
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
||||
strcpy( password, ctx->dav_session.proxy_pwd );
|
||||
}
|
||||
}
|
||||
/* NTLM needs several attempts */
|
||||
@@ -251,42 +180,42 @@ static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
|
||||
}
|
||||
|
||||
/* Configure the proxy depending on the variables */
|
||||
static int configureProxy( ne_session *session )
|
||||
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
|
||||
{
|
||||
int port = 8080;
|
||||
int re = -1;
|
||||
|
||||
if( ! session ) return -1;
|
||||
if( ! dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
||||
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
||||
|
||||
if( dav_session.proxy_port > 0 ) {
|
||||
port = dav_session.proxy_port;
|
||||
if( ctx->dav_session.proxy_port > 0 ) {
|
||||
port = ctx->dav_session.proxy_port;
|
||||
}
|
||||
|
||||
if( c_streq(dav_session.proxy_type, "NoProxy" )) {
|
||||
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
|
||||
DEBUG_WEBDAV("No proxy configured.");
|
||||
re = 0;
|
||||
} else if( c_streq(dav_session.proxy_type, "DefaultProxy") ||
|
||||
c_streq(dav_session.proxy_type, "HttpProxy") ||
|
||||
c_streq(dav_session.proxy_type, "HttpCachingProxy") ||
|
||||
c_streq(dav_session.proxy_type, "Socks5Proxy")) {
|
||||
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
|
||||
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
|
||||
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
|
||||
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
||||
|
||||
if( dav_session.proxy_host ) {
|
||||
DEBUG_WEBDAV("%s at %s:%d", dav_session.proxy_type, dav_session.proxy_host, port );
|
||||
if (c_streq(dav_session.proxy_type, "Socks5Proxy")) {
|
||||
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, dav_session.proxy_host, port,
|
||||
dav_session.proxy_user, dav_session.proxy_pwd);
|
||||
if( ctx->dav_session.proxy_host ) {
|
||||
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
|
||||
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
||||
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
|
||||
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
|
||||
} else {
|
||||
ne_session_proxy(session, dav_session.proxy_host, port );
|
||||
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
|
||||
}
|
||||
re = 2;
|
||||
} else {
|
||||
DEBUG_WEBDAV("%s requested but no proxy host defined.", dav_session.proxy_type );
|
||||
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
|
||||
/* we used to try ne_system_session_proxy here, but we should rather err out
|
||||
to behave exactly like the caller. */
|
||||
}
|
||||
} else {
|
||||
DEBUG_WEBDAV( "Unsupported Proxy: %s", dav_session.proxy_type );
|
||||
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
|
||||
}
|
||||
|
||||
return re;
|
||||
@@ -303,9 +232,9 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||
const char *sc = NULL;
|
||||
char *key = NULL;
|
||||
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||
|
||||
if (dav_session.session_key)
|
||||
if (ctx->dav_session.session_key)
|
||||
return; /* We already have a session cookie, and we should ignore other ones */
|
||||
|
||||
if(!(status && req)) return;
|
||||
@@ -373,8 +302,8 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||
}
|
||||
if( key ) {
|
||||
DEBUG_WEBDAV("----> Session-key: %s", key);
|
||||
SAFE_FREE(dav_session.session_key);
|
||||
dav_session.session_key = key;
|
||||
SAFE_FREE(ctx->dav_session.session_key);
|
||||
ctx->dav_session.session_key = key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,13 +314,14 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
|
||||
static void request_created_hook(ne_request *req, void *userdata,
|
||||
const char *method, const char *requri)
|
||||
{
|
||||
(void) userdata;
|
||||
// FIXME Can possibly be merged with pre_send_hook
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||
(void) method;
|
||||
(void) requri;
|
||||
|
||||
if( !req ) return;
|
||||
|
||||
if(dav_session.proxy_type) {
|
||||
if(ctx->dav_session.proxy_type) {
|
||||
/* required for NTLM */
|
||||
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
|
||||
}
|
||||
@@ -404,12 +334,12 @@ static void request_created_hook(ne_request *req, void *userdata,
|
||||
static void pre_send_hook(ne_request *req, void *userdata,
|
||||
ne_buffer *header)
|
||||
{
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||
|
||||
if( !req ) return;
|
||||
|
||||
if(dav_session.session_key) {
|
||||
ne_buffer_concat(header, "Cookie: ", dav_session.session_key, "\r\n", NULL);
|
||||
if(ctx->dav_session.session_key) {
|
||||
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
|
||||
} else {
|
||||
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
|
||||
}
|
||||
@@ -419,16 +349,15 @@ static int post_send_hook(ne_request *req, void *userdata,
|
||||
const ne_status *status)
|
||||
{
|
||||
const char *location;
|
||||
|
||||
(void) userdata;
|
||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
||||
(void) status;
|
||||
|
||||
location = ne_get_response_header(req, "Location");
|
||||
|
||||
if( !location ) return NE_OK;
|
||||
|
||||
if( dav_session.redir_callback ) {
|
||||
if( dav_session.redir_callback( dav_session.csync_ctx, location ) ) {
|
||||
if( ctx->dav_session.redir_callback ) {
|
||||
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
|
||||
return NE_REDIRECT;
|
||||
} else {
|
||||
return NE_RETRY;
|
||||
@@ -438,37 +367,12 @@ static int post_send_hook(ne_request *req, void *userdata,
|
||||
return NE_REDIRECT;
|
||||
}
|
||||
|
||||
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
|
||||
// extend as required
|
||||
static const char* get_platform() {
|
||||
#if defined (_WIN32)
|
||||
return "Windows";
|
||||
#elif defined(__APPLE__)
|
||||
return "Macintosh";
|
||||
#elif defined(__gnu_linux__)
|
||||
return "Linux";
|
||||
#elif defined(__DragonFly__)
|
||||
/* might also define __FreeBSD__ */
|
||||
return "DragonFlyBSD";
|
||||
#elif defined(__FreeBSD__)
|
||||
return "FreeBSD";
|
||||
#elif defined(__NetBSD__)
|
||||
return "NetBSD";
|
||||
#elif defined(__OpenBSD__)
|
||||
return "OpenBSD";
|
||||
#elif defined(sun) || defined(__sun)
|
||||
return "Solaris";
|
||||
#else
|
||||
return "Unknown OS";
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to a DAV server
|
||||
* This function sets the flag _connected if the connection is established
|
||||
* and returns if the flag is set, so calling it frequently is save.
|
||||
*/
|
||||
static int dav_connect(const char *base_url) {
|
||||
static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
|
||||
int useSSL = 0;
|
||||
int rc;
|
||||
char protocol[6] = {'\0'};
|
||||
@@ -479,11 +383,14 @@ static int dav_connect(const char *base_url) {
|
||||
unsigned int port = 0;
|
||||
int proxystate = -1;
|
||||
|
||||
if (_connected) {
|
||||
if (ctx->_connected) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = c_parse_uri( base_url, &scheme, &dav_session.user, &dav_session.pwd, &host, &port, &path );
|
||||
rc = c_parse_uri( base_url, &scheme,
|
||||
&ctx->dav_session.user,
|
||||
&ctx->dav_session.pwd,
|
||||
&host, &port, &path );
|
||||
if( rc < 0 ) {
|
||||
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
|
||||
goto out;
|
||||
@@ -505,29 +412,29 @@ static int dav_connect(const char *base_url) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUG_WEBDAV("* user %s", dav_session.user ? dav_session.user : "");
|
||||
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
|
||||
|
||||
if (port == 0) {
|
||||
port = ne_uri_defaultport(protocol);
|
||||
}
|
||||
|
||||
dav_session.ctx = ne_session_create( protocol, host, port);
|
||||
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
|
||||
|
||||
if (dav_session.ctx == NULL) {
|
||||
if (ctx->dav_session.ctx == NULL) {
|
||||
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dav_session.read_timeout != 0) {
|
||||
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
|
||||
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
|
||||
if (ctx->dav_session.read_timeout != 0) {
|
||||
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
|
||||
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
|
||||
}
|
||||
|
||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
||||
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
||||
ne_set_useragent( dav_session.ctx, uaBuf);
|
||||
ne_set_server_auth(dav_session.ctx, ne_auth, 0 );
|
||||
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
||||
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
||||
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
||||
|
||||
if( useSSL ) {
|
||||
if (!ne_has_support(NE_FEATURE_SSL)) {
|
||||
@@ -536,28 +443,28 @@ static int dav_connect(const char *base_url) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ne_ssl_trust_default_ca( dav_session.ctx );
|
||||
ne_ssl_set_verify( dav_session.ctx, verify_sslcert, 0 );
|
||||
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
|
||||
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
|
||||
}
|
||||
|
||||
/* Hook called when a request is created. It sets the proxy connection header. */
|
||||
ne_hook_create_request( dav_session.ctx, request_created_hook, NULL );
|
||||
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
|
||||
/* Hook called after response headers are read. It gets the Session ID. */
|
||||
ne_hook_post_headers( dav_session.ctx, post_request_hook, NULL );
|
||||
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
|
||||
/* Hook called before a request is sent. It sets the cookies. */
|
||||
ne_hook_pre_send( dav_session.ctx, pre_send_hook, NULL );
|
||||
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
|
||||
/* Hook called after request is dispatched. Used for handling possible redirections. */
|
||||
ne_hook_post_send( dav_session.ctx, post_send_hook, NULL );
|
||||
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
|
||||
|
||||
/* Proxy support */
|
||||
proxystate = configureProxy( dav_session.ctx );
|
||||
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
|
||||
if( proxystate < 0 ) {
|
||||
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
|
||||
} else if( proxystate > 0 ) {
|
||||
ne_set_proxy_auth( dav_session.ctx, ne_proxy_auth, 0 );
|
||||
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, ctx );
|
||||
}
|
||||
|
||||
_connected = 1;
|
||||
ctx->_connected = 1;
|
||||
rc = 0;
|
||||
out:
|
||||
SAFE_FREE(path);
|
||||
@@ -573,24 +480,16 @@ out:
|
||||
* and fills a resource struct and stores it to the result list which
|
||||
* is stored in the listdir_context.
|
||||
*/
|
||||
static void results(void *userdata,
|
||||
static void propfind_results_callback(void *userdata,
|
||||
const ne_uri *uri,
|
||||
const ne_prop_result_set *set)
|
||||
{
|
||||
struct listdir_context *fetchCtx = userdata;
|
||||
struct resource *newres = 0;
|
||||
const char *clength, *modtime = NULL;
|
||||
const char *resourcetype = NULL;
|
||||
const char *md5sum = NULL;
|
||||
const char *file_id = NULL;
|
||||
const ne_status *status = NULL;
|
||||
char *path = ne_path_unescape( uri->path );
|
||||
|
||||
(void) status;
|
||||
if( ! fetchCtx ) {
|
||||
DEBUG_WEBDAV("No valid fetchContext");
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! fetchCtx->target ) {
|
||||
DEBUG_WEBDAV("error: target must not be zero!" );
|
||||
@@ -599,37 +498,9 @@ static void results(void *userdata,
|
||||
|
||||
/* Fill the resource structure with the data about the file */
|
||||
newres = c_malloc(sizeof(struct resource));
|
||||
ZERO_STRUCTP(newres);
|
||||
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
|
||||
newres->name = c_basename( path );
|
||||
|
||||
modtime = ne_propset_value( set, &ls_props[0] );
|
||||
clength = ne_propset_value( set, &ls_props[1] );
|
||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||
file_id = ne_propset_value( set, &ls_props[4] );
|
||||
|
||||
newres->type = resr_normal;
|
||||
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||
newres->type = resr_collection;
|
||||
}
|
||||
|
||||
if (modtime) {
|
||||
newres->modtime = oc_httpdate_parse(modtime);
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
|
||||
newres->size = 0;
|
||||
if (clength) {
|
||||
newres->size = atoll(clength);
|
||||
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
|
||||
}
|
||||
|
||||
if( md5sum ) {
|
||||
newres->md5 = csync_normalize_etag(md5sum);
|
||||
}
|
||||
|
||||
csync_vio_set_file_id(newres->file_id, file_id);
|
||||
fill_webdav_properties_into_resource(newres, set);
|
||||
|
||||
/* prepend the new resource to the result list */
|
||||
newres->next = fetchCtx->list;
|
||||
@@ -643,7 +514,7 @@ static void results(void *userdata,
|
||||
/*
|
||||
* fetches a resource list from the WebDAV server. This is equivalent to list dir.
|
||||
*/
|
||||
static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
|
||||
{
|
||||
struct listdir_context *fetchCtx;
|
||||
int ret = 0;
|
||||
@@ -657,12 +528,12 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
|
||||
/* The old legacy one-level PROPFIND cache. Also gets filled
|
||||
by the recursive cache if 'infinity' did not suceed. */
|
||||
if (propfind_cache) {
|
||||
if (c_streq(curi, propfind_cache->target)) {
|
||||
if (ctx->propfind_cache) {
|
||||
if (c_streq(curi, ctx->propfind_cache->target)) {
|
||||
DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
|
||||
propfind_cache->ref++;
|
||||
ctx->propfind_cache->ref++;
|
||||
SAFE_FREE(curi);
|
||||
return propfind_cache;
|
||||
return ctx->propfind_cache;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,10 +549,10 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
fetchCtx->ref = 1;
|
||||
|
||||
/* do a propfind request and parse the results in the results function, set as callback */
|
||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
||||
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||
|
||||
if(hdl) {
|
||||
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
|
||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_callback, fetchCtx);
|
||||
request = ne_propfind_get_request( hdl );
|
||||
req_status = ne_get_status( request );
|
||||
}
|
||||
@@ -694,14 +565,14 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
||||
req_status->reason_phrase);
|
||||
ret = NE_CONNECT;
|
||||
set_error_message(req_status->reason_phrase);
|
||||
set_error_message(ctx, req_status->reason_phrase);
|
||||
}
|
||||
DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
|
||||
} else {
|
||||
if( ret == NE_ERROR && req_status->code == 404) {
|
||||
errno = ENOENT;
|
||||
} else {
|
||||
set_errno_from_neon_errcode(ret);
|
||||
set_errno_from_neon_errcode(ctx, ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,18 +587,18 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
||||
content_type ? content_type: "<empty>");
|
||||
errno = ERRNO_WRONG_CONTENT;
|
||||
set_error_message("Server error: PROPFIND reply is not XML formatted!");
|
||||
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
|
||||
ret = NE_CONNECT;
|
||||
}
|
||||
}
|
||||
|
||||
if( ret != NE_OK ) {
|
||||
const char *err = NULL;
|
||||
set_errno_from_neon_errcode(ret);
|
||||
set_errno_from_neon_errcode(ctx, ret);
|
||||
|
||||
err = ne_get_error( dav_session.ctx );
|
||||
err = ne_get_error( ctx->dav_session.ctx );
|
||||
if(err) {
|
||||
set_error_message(err);
|
||||
set_error_message(ctx, err);
|
||||
}
|
||||
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
||||
}
|
||||
@@ -740,19 +611,19 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free_fetchCtx(propfind_cache);
|
||||
propfind_cache = fetchCtx;
|
||||
propfind_cache->ref++;
|
||||
free_fetchCtx(ctx->propfind_cache);
|
||||
ctx->propfind_cache = fetchCtx;
|
||||
ctx->propfind_cache->ref++;
|
||||
return fetchCtx;
|
||||
}
|
||||
|
||||
static struct listdir_context *fetch_resource_list_attempts(const char *uri, int depth)
|
||||
static struct listdir_context *fetch_resource_list_attempts(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
for(i = 0; i < 10; ++i) {
|
||||
fetchCtx = fetch_resource_list(uri, depth);
|
||||
fetchCtx = fetch_resource_list(ctx, uri, depth);
|
||||
if(fetchCtx) break;
|
||||
/* only loop in case the content is not XML formatted. Otherwise for every
|
||||
* non successful stat (for non existing directories) its tried 10 times. */
|
||||
@@ -764,165 +635,39 @@ static struct listdir_context *fetch_resource_list_attempts(const char *uri, int
|
||||
return fetchCtx;
|
||||
}
|
||||
|
||||
static void fill_stat_cache( csync_vio_file_stat_t *lfs ) {
|
||||
|
||||
if( _stat_cache.name ) SAFE_FREE(_stat_cache.name);
|
||||
if( _stat_cache.etag ) SAFE_FREE(_stat_cache.etag );
|
||||
|
||||
if( !lfs) return;
|
||||
|
||||
_stat_cache.name = c_strdup(lfs->name);
|
||||
_stat_cache.mtime = lfs->mtime;
|
||||
_stat_cache.fields = lfs->fields;
|
||||
_stat_cache.type = lfs->type;
|
||||
_stat_cache.size = lfs->size;
|
||||
csync_vio_file_stat_set_file_id(&_stat_cache, lfs->file_id);
|
||||
|
||||
if( lfs->etag ) {
|
||||
_stat_cache.etag = c_strdup(lfs->etag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* file functions
|
||||
*/
|
||||
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
/* get props:
|
||||
* modtime
|
||||
* creattime
|
||||
* size
|
||||
*/
|
||||
csync_vio_file_stat_t *lfs = NULL;
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
char *decodedUri = NULL;
|
||||
int len = 0;
|
||||
errno = 0;
|
||||
|
||||
buf->name = c_basename(uri);
|
||||
|
||||
if (buf->name == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( _stat_cache.name && strcmp( buf->name, _stat_cache.name ) == 0 ) {
|
||||
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
buf->fields = _stat_cache.fields;
|
||||
buf->type = _stat_cache.type;
|
||||
buf->mtime = _stat_cache.mtime;
|
||||
buf->size = _stat_cache.size;
|
||||
buf->mode = _stat_perms( _stat_cache.type );
|
||||
buf->etag = NULL;
|
||||
if( _stat_cache.etag ) {
|
||||
buf->etag = c_strdup( _stat_cache.etag );
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
||||
}
|
||||
csync_vio_file_stat_set_file_id( buf, _stat_cache.file_id );
|
||||
return 0;
|
||||
}
|
||||
DEBUG_WEBDAV("owncloud_stat => Could not find in stat cache %s", uri);
|
||||
|
||||
/* fetch data via a propfind call. */
|
||||
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE); */
|
||||
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
|
||||
DEBUG_WEBDAV("=> Errno after fetch resource list for %s: %d", uri, errno);
|
||||
if (!fetchCtx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( fetchCtx ) {
|
||||
struct resource *res = fetchCtx->list;
|
||||
while( res ) {
|
||||
/* remove trailing slashes */
|
||||
len = strlen(res->uri);
|
||||
while( len > 0 && res->uri[len-1] == '/' ) --len;
|
||||
decodedUri = ne_path_unescape( fetchCtx->target ); /* allocates memory */
|
||||
|
||||
/* Only do the comparaison of the part of the string without the trailing
|
||||
slashes, and make sure decodedUri is not too large */
|
||||
if( strncmp(res->uri, decodedUri, len ) == 0 && decodedUri[len] == '\0') {
|
||||
SAFE_FREE( decodedUri );
|
||||
break;
|
||||
}
|
||||
res = res->next;
|
||||
SAFE_FREE( decodedUri );
|
||||
}
|
||||
if( res ) {
|
||||
DEBUG_WEBDAV("Working on file %s", res->name );
|
||||
} else {
|
||||
DEBUG_WEBDAV("ERROR: Result struct not valid!");
|
||||
}
|
||||
|
||||
lfs = resourceToFileStat( res );
|
||||
if( lfs ) {
|
||||
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
|
||||
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
||||
|
||||
buf->fields = lfs->fields;
|
||||
buf->type = lfs->type;
|
||||
buf->mtime = lfs->mtime;
|
||||
buf->size = lfs->size;
|
||||
buf->mode = _stat_perms( lfs->type );
|
||||
buf->etag = NULL;
|
||||
if( lfs->etag ) {
|
||||
buf->etag = c_strdup( lfs->etag );
|
||||
}
|
||||
csync_vio_file_stat_set_file_id( buf, lfs->file_id );
|
||||
|
||||
/* fill the static stat buf as input for the stat function */
|
||||
csync_vio_file_stat_destroy( lfs );
|
||||
}
|
||||
|
||||
free_fetchCtx( fetchCtx );
|
||||
}
|
||||
DEBUG_WEBDAV("STAT result from propfind: %s, mtime: %llu", buf->name ? buf->name:"NULL",
|
||||
(unsigned long long) buf->mtime );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* directory functions
|
||||
*/
|
||||
csync_vio_handle_t *owncloud_opendir(const char *uri) {
|
||||
csync_vio_handle_t *owncloud_opendir(CSYNC *ctx, const char *uri) {
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
char *curi = NULL;
|
||||
|
||||
DEBUG_WEBDAV("opendir method called on %s", uri );
|
||||
|
||||
if (dav_connect( uri ) < 0) {
|
||||
if (dav_connect( ctx->owncloud_context, uri ) < 0) {
|
||||
DEBUG_WEBDAV("connection failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curi = _cleanPath( uri );
|
||||
if (is_first_propfind && !dav_session.no_recursive_propfind) {
|
||||
is_first_propfind = false;
|
||||
if (ctx->owncloud_context->is_first_propfind && !ctx->owncloud_context->dav_session.no_recursive_propfind) {
|
||||
ctx->owncloud_context->is_first_propfind = false;
|
||||
// Try to fill it
|
||||
fill_recursive_propfind_cache(uri, curi);
|
||||
fill_recursive_propfind_cache(ctx->owncloud_context, uri, curi);
|
||||
}
|
||||
if (propfind_recursive_cache) {
|
||||
if (ctx->owncloud_context->propfind_recursive_cache) {
|
||||
// Try to fetch from recursive cache (if we have one)
|
||||
fetchCtx = get_listdir_context_from_recursive_cache(curi);
|
||||
fetchCtx = get_listdir_context_from_recursive_cache(ctx->owncloud_context, curi);
|
||||
}
|
||||
SAFE_FREE(curi);
|
||||
is_first_propfind = false;
|
||||
ctx->owncloud_context->is_first_propfind = false;
|
||||
if (fetchCtx) {
|
||||
return fetchCtx;
|
||||
}
|
||||
|
||||
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE ); */
|
||||
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
|
||||
fetchCtx = fetch_resource_list_attempts( ctx->owncloud_context, uri, NE_DEPTH_ONE);
|
||||
if( !fetchCtx ) {
|
||||
/* errno is set properly in fetch_resource_list */
|
||||
DEBUG_WEBDAV("Errno set to %d", errno);
|
||||
@@ -935,17 +680,16 @@ csync_vio_handle_t *owncloud_opendir(const char *uri) {
|
||||
/* no freeing of curi because its part of the fetchCtx and gets freed later */
|
||||
}
|
||||
|
||||
int owncloud_closedir(csync_vio_handle_t *dhandle) {
|
||||
|
||||
int owncloud_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||
struct listdir_context *fetchCtx = dhandle;
|
||||
|
||||
free_fetchCtx(fetchCtx);
|
||||
|
||||
(void)ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
|
||||
csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||
struct listdir_context *fetchCtx = dhandle;
|
||||
(void)ctx;
|
||||
|
||||
// DEBUG_WEBDAV("owncloud_readdir" );
|
||||
// DEBUG_WEBDAV("owncloud_readdir %s ", fetchCtx->target);
|
||||
@@ -971,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,9 +165,9 @@ static void propfind_results_recursive(void *userdata,
|
||||
depth++;
|
||||
pElement = pElement->parent;
|
||||
}
|
||||
if (depth > propfind_recursive_cache_depth) {
|
||||
if (depth > ctx->propfind_recursive_cache_depth) {
|
||||
DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth);
|
||||
propfind_recursive_cache_depth = depth;
|
||||
ctx->propfind_recursive_cache_depth = depth;
|
||||
}
|
||||
|
||||
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
|
||||
@@ -244,7 +179,7 @@ static void propfind_results_recursive(void *userdata,
|
||||
newres = NULL;
|
||||
}
|
||||
|
||||
void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi)
|
||||
{
|
||||
int ret = 0;
|
||||
ne_propfind_handler *hdl = NULL;
|
||||
@@ -256,10 +191,10 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);
|
||||
|
||||
/* do a propfind request and parse the results in the results function, set as callback */
|
||||
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
|
||||
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||
|
||||
if(hdl) {
|
||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
|
||||
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive_callback, ctx);
|
||||
request = ne_propfind_get_request( hdl );
|
||||
req_status = ne_get_status( request );
|
||||
}
|
||||
@@ -271,14 +206,14 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
|
||||
req_status->reason_phrase);
|
||||
ret = NE_CONNECT;
|
||||
set_error_message(req_status->reason_phrase);
|
||||
set_error_message(ctx, req_status->reason_phrase);
|
||||
}
|
||||
DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
|
||||
} else {
|
||||
if( ret == NE_ERROR && req_status->code == 404) {
|
||||
errno = ENOENT;
|
||||
} else {
|
||||
set_errno_from_neon_errcode(ret);
|
||||
set_errno_from_neon_errcode(ctx, ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +228,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
|
||||
content_type ? content_type: "<empty>");
|
||||
errno = ERRNO_WRONG_CONTENT;
|
||||
set_error_message("Server error: PROPFIND reply is not XML formatted!");
|
||||
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
|
||||
ret = NE_CONNECT;
|
||||
}
|
||||
}
|
||||
@@ -301,7 +236,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
if( ret != NE_OK ) {
|
||||
const char *err = NULL;
|
||||
|
||||
err = ne_get_error( dav_session.ctx );
|
||||
err = ne_get_error( ctx->dav_session.ctx );
|
||||
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
|
||||
}
|
||||
|
||||
@@ -316,22 +251,21 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
|
||||
}
|
||||
|
||||
/* Called by owncloud_opendir()->fetch_resource_list() to fill the cache */
|
||||
extern struct listdir_context *propfind_cache;
|
||||
void fill_recursive_propfind_cache(const char *uri, const char *curi) {
|
||||
fetch_resource_list_recursive(uri, curi);
|
||||
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi) {
|
||||
fetch_resource_list_recursive(ctx, uri, curi);
|
||||
|
||||
if (propfind_recursive_cache_depth <= 2) {
|
||||
if (ctx->propfind_recursive_cache_depth <= 2) {
|
||||
DEBUG_WEBDAV("fill_recursive_propfind_cache %s Server maybe did not give us an 'infinity' depth result", curi);
|
||||
/* transform the cache to the normal cache in propfind_cache */
|
||||
propfind_cache = get_listdir_context_from_recursive_cache(curi);
|
||||
ctx->propfind_cache = get_listdir_context_from_recursive_cache(ctx, curi);
|
||||
/* clear the cache, it is bogus since the server returned only results for Depth 1 */
|
||||
clear_propfind_recursive_cache();
|
||||
clear_propfind_recursive_cache(ctx);
|
||||
} else {
|
||||
DEBUG_WEBDAV("fill_recursive_propfind_cache %s We received %d elements deep for 'infinity' depth (%d folders, %d files)",
|
||||
curi,
|
||||
propfind_recursive_cache_depth,
|
||||
propfind_recursive_cache_folder_count,
|
||||
propfind_recursive_cache_file_count);
|
||||
ctx->propfind_recursive_cache_depth,
|
||||
ctx->propfind_recursive_cache_folder_count,
|
||||
ctx->propfind_recursive_cache_file_count);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
*/
|
||||
|
||||
#include "csync_owncloud.h"
|
||||
#include "csync_owncloud_private.h"
|
||||
|
||||
#include "csync_misc.h"
|
||||
|
||||
void set_error_message( const char *msg )
|
||||
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg )
|
||||
{
|
||||
SAFE_FREE(dav_session.error_string);
|
||||
SAFE_FREE(ctx->dav_session.error_string);
|
||||
if( msg )
|
||||
dav_session.error_string = c_strdup(msg);
|
||||
ctx->dav_session.error_string = c_strdup(msg);
|
||||
}
|
||||
|
||||
void set_errno_from_http_errcode( int err ) {
|
||||
@@ -104,12 +106,12 @@ void set_errno_from_http_errcode( int err ) {
|
||||
errno = new_errno;
|
||||
}
|
||||
|
||||
int http_result_code_from_session() {
|
||||
const char *p = ne_get_error( dav_session.ctx );
|
||||
int http_result_code_from_session(csync_owncloud_ctx_t *ctx) {
|
||||
const char *p = ne_get_error( ctx->dav_session.ctx );
|
||||
char *q;
|
||||
int err;
|
||||
|
||||
set_error_message(p); /* remember the error message */
|
||||
set_error_message(ctx, p); /* remember the error message */
|
||||
|
||||
err = strtol(p, &q, 10);
|
||||
if (p == q) {
|
||||
@@ -118,8 +120,8 @@ int http_result_code_from_session() {
|
||||
return err;
|
||||
}
|
||||
|
||||
void set_errno_from_session() {
|
||||
int err = http_result_code_from_session();
|
||||
void set_errno_from_session(csync_owncloud_ctx_t *ctx) {
|
||||
int err = http_result_code_from_session(ctx);
|
||||
|
||||
if( err == EIO || err == ERRNO_ERROR_STRING) {
|
||||
errno = err;
|
||||
@@ -128,7 +130,7 @@ void set_errno_from_session() {
|
||||
}
|
||||
}
|
||||
|
||||
void set_errno_from_neon_errcode( int neon_code ) {
|
||||
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code ) {
|
||||
|
||||
if( neon_code != NE_OK ) {
|
||||
DEBUG_WEBDAV("Neon error code was %d", neon_code);
|
||||
@@ -137,7 +139,7 @@ void set_errno_from_neon_errcode( int neon_code ) {
|
||||
switch(neon_code) {
|
||||
case NE_OK: /* Success, but still the possiblity of problems */
|
||||
case NE_ERROR: /* Generic error; use ne_get_error(session) for message */
|
||||
set_errno_from_session(); /* Something wrong with http communication */
|
||||
set_errno_from_session(ctx); /* Something wrong with http communication */
|
||||
break;
|
||||
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
|
||||
errno = ERRNO_LOOKUP_ERROR;
|
||||
@@ -279,19 +281,9 @@ time_t oc_httpdate_parse( const char *date ) {
|
||||
/*
|
||||
* helper: convert a resource struct to file_stat struct.
|
||||
*/
|
||||
csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
|
||||
void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
|
||||
{
|
||||
csync_vio_file_stat_t *lfs = NULL;
|
||||
|
||||
if( ! res ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lfs = c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
if (lfs == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(lfs);
|
||||
|
||||
lfs->name = c_strdup( res->name );
|
||||
|
||||
@@ -312,30 +304,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
|
||||
}
|
||||
|
||||
+13
-27
@@ -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!");
|
||||
|
||||
@@ -58,28 +58,6 @@ int csync_get_statedb_exists(CSYNC *ctx) {
|
||||
return ctx->statedb.exists;
|
||||
}
|
||||
|
||||
/* Set the hide attribute in win32. That makes it invisible in normal explorers */
|
||||
static void _csync_win32_hide_file( const char *file ) {
|
||||
#ifdef _WIN32
|
||||
mbchar_t *fileName;
|
||||
DWORD dwAttrs;
|
||||
|
||||
if( !file ) return;
|
||||
|
||||
fileName = c_utf8_to_locale( file );
|
||||
dwAttrs = GetFileAttributesW(fileName);
|
||||
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
||||
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
||||
}
|
||||
}
|
||||
c_free_locale_string(fileName);
|
||||
#else
|
||||
(void) file;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _csync_check_db_integrity(sqlite3 *db) {
|
||||
c_strlist_t *result = NULL;
|
||||
int rc = -1;
|
||||
@@ -168,7 +146,7 @@ static int _csync_statedb_check(const char *statedb) {
|
||||
rc = sqlite3_open(statedb, &db);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_close(db);
|
||||
_csync_win32_hide_file(statedb);
|
||||
csync_win32_set_file_hidden(statedb, true);
|
||||
return 1;
|
||||
}
|
||||
sqlite3_close(db);
|
||||
@@ -322,8 +300,6 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
|
||||
name = (const char*) sqlite3_column_text(stmt, 2);
|
||||
memcpy((*st)->path, (len ? name : ""), len + 1);
|
||||
(*st)->inode = sqlite3_column_int64(stmt,3);
|
||||
(*st)->uid = sqlite3_column_int(stmt, 4);
|
||||
(*st)->gid = sqlite3_column_int(stmt, 5);
|
||||
(*st)->mode = sqlite3_column_int(stmt, 6);
|
||||
(*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
|
||||
|
||||
@@ -337,6 +313,11 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
|
||||
if(column_count > 10 && sqlite3_column_text(stmt,10)) {
|
||||
csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
|
||||
}
|
||||
if(column_count > 11 && sqlite3_column_text(stmt,11)) {
|
||||
strncpy((*st)->remotePerm,
|
||||
(char*) sqlite3_column_text(stmt, 11),
|
||||
REMOTE_PERM_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -476,7 +457,7 @@ char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid FROM metadata WHERE path LIKE(?)"
|
||||
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM metadata WHERE path LIKE(?)"
|
||||
|
||||
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
int rc;
|
||||
|
||||
+41
-15
@@ -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,20 +262,22 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||
goto out;
|
||||
}
|
||||
bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
|
||||
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|
||||
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
|
||||
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
|
||||
&& c_streq(fs->file_id, tmp->file_id) && !ctx->read_from_db_disabled) {
|
||||
&& !metadata_differ && !ctx->read_from_db_disabled) {
|
||||
/* If both etag and file id are equal for a directory, read all contents from
|
||||
* the database.
|
||||
* The comparison of file id ensure that we fetch all the file id when upgrading from
|
||||
* owncloud 5 to owncloud 6.
|
||||
* The metadata comparison ensure that we fetch all the file id or permission when
|
||||
* upgrading owncloud
|
||||
*/
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
|
||||
ctx->remote.read_from_db = true;
|
||||
}
|
||||
|
||||
if (!c_streq(fs->file_id, tmp->file_id) && ctx->current == REMOTE_REPLICA) {
|
||||
/* file id has changed. Which means we need to update the DB.
|
||||
* (upgrade from owncloud 5 to owncloud 6 for instence) */
|
||||
if (metadata_differ) {
|
||||
/* file id or permissions has changed. Which means we need to update them in the DB. */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
|
||||
st->should_update_etag = true;
|
||||
}
|
||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
@@ -364,8 +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;
|
||||
@@ -374,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;
|
||||
@@ -589,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) {
|
||||
@@ -646,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)) {
|
||||
@@ -674,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,59 +128,6 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
|
||||
csync_vio_file_stat_t *vfs = NULL;
|
||||
|
||||
if (st == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vfs = csync_vio_file_stat_new();
|
||||
if (vfs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
vfs->acl = NULL;
|
||||
if (st->pathlen > 0) {
|
||||
vfs->name = c_strdup(st->path);
|
||||
}
|
||||
vfs->uid = st->uid;
|
||||
vfs->gid = st->gid;
|
||||
|
||||
vfs->atime = 0;
|
||||
vfs->mtime = st->modtime;
|
||||
vfs->ctime = 0;
|
||||
|
||||
vfs->size = st->size;
|
||||
vfs->blksize = 0; /* Depricated. */
|
||||
vfs->blkcount = 0;
|
||||
|
||||
vfs->mode = st->mode;
|
||||
vfs->device = 0;
|
||||
vfs->inode = st->inode;
|
||||
vfs->nlink = st->nlink;
|
||||
|
||||
/* fields. */
|
||||
vfs->fields = CSYNC_VIO_FILE_STAT_FIELDS_TYPE
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_INODE
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_SIZE
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_MTIME
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_UID
|
||||
+ CSYNC_VIO_FILE_STAT_FIELDS_GID;
|
||||
|
||||
if (st->type == CSYNC_FTW_TYPE_DIR)
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
|
||||
else if (st->type == CSYNC_FTW_TYPE_FILE)
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||
else if (st->type == CSYNC_FTW_TYPE_SLINK)
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
|
||||
else
|
||||
vfs->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||
|
||||
return vfs;
|
||||
}
|
||||
|
||||
bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
|
||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
|
||||
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
|
||||
|
||||
@@ -32,8 +32,5 @@ void csync_memstat_check(void);
|
||||
|
||||
void csync_win32_set_file_hidden( const char *file, bool hidden );
|
||||
|
||||
/* Convert a csync_file_stat_t to csync_vio_file_stat_t */
|
||||
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st);
|
||||
|
||||
bool csync_file_locked_or_open( const char *dir, const char *fname);
|
||||
#endif /* _CSYNC_UTIL_H */
|
||||
|
||||
@@ -20,8 +20,6 @@ set(CSTDLIB_LINK_LIBRARIES
|
||||
|
||||
set(cstdlib_SRCS
|
||||
c_alloc.c
|
||||
c_dir.c
|
||||
c_file.c
|
||||
c_list.c
|
||||
c_path.c
|
||||
c_rbtree.c
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_private.h"
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_dir.h"
|
||||
#include "c_string.h"
|
||||
|
||||
int c_mkdirs(const char *path, mode_t mode) {
|
||||
int tmp;
|
||||
csync_stat_t sb;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
mbchar_t *swpath = NULL;
|
||||
|
||||
if (path == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_tstat(wpath, &sb) == 0) {
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = strlen(path);
|
||||
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
|
||||
while(tmp > 0 && path[tmp - 1] != '/') --tmp;
|
||||
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
|
||||
|
||||
if (tmp > 0) {
|
||||
char subpath[tmp + 1];
|
||||
memcpy(subpath, path, tmp);
|
||||
subpath[tmp] = '\0';
|
||||
swpath = c_utf8_to_locale(subpath);
|
||||
if (_tstat(swpath, &sb) == 0) {
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
c_free_locale_string(swpath);
|
||||
c_free_locale_string(wpath);
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
} else if (errno != ENOENT) {
|
||||
c_free_locale_string(wpath);
|
||||
c_free_locale_string(swpath);
|
||||
return -1;
|
||||
} else if (c_mkdirs(subpath, mode) < 0) {
|
||||
c_free_locale_string(swpath);
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
tmp = _tmkdir(wpath, mode);
|
||||
|
||||
c_free_locale_string(swpath);
|
||||
c_free_locale_string(wpath);
|
||||
|
||||
if ((tmp < 0) && (errno == EEXIST)) {
|
||||
return 0;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int c_rmdirs(const char *path) {
|
||||
_TDIR *d;
|
||||
struct _tdirent *dp;
|
||||
csync_stat_t sb;
|
||||
char *fname = NULL;
|
||||
mbchar_t *wfname = NULL;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
char *rd_name = NULL;
|
||||
|
||||
if ((d = _topendir(wpath)) != NULL) {
|
||||
while( _tstat(wpath, &sb) == 0) {
|
||||
/* if we can remove the directory we're done */
|
||||
if (_trmdir(wpath) == 0) {
|
||||
break;
|
||||
}
|
||||
switch (errno) {
|
||||
case ENOTEMPTY:
|
||||
case EEXIST:
|
||||
case EBADF:
|
||||
break; /* continue */
|
||||
default:
|
||||
_tclosedir(d);
|
||||
c_free_locale_string(wpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((dp = _treaddir(d)) != NULL) {
|
||||
size_t len;
|
||||
rd_name = c_utf8_from_locale(dp->d_name);
|
||||
/* skip '.' and '..' */
|
||||
if( c_streq( rd_name, "." ) || c_streq( rd_name, ".." ) ) {
|
||||
c_free_locale_string(rd_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
len = strlen(path) + strlen(rd_name) + 2;
|
||||
fname = c_malloc(len);
|
||||
if (fname == NULL) {
|
||||
_tclosedir(d);
|
||||
c_free_locale_string(rd_name);
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
snprintf(fname, len, "%s/%s", path, rd_name);
|
||||
wfname = c_utf8_to_locale(fname);
|
||||
|
||||
/* stat the file */
|
||||
if (_tstat(wfname, &sb) != -1) {
|
||||
#ifdef __unix__
|
||||
if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
|
||||
#else
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
#endif
|
||||
if (_trmdir(wfname) < 0) { /* can't be deleted */
|
||||
if (errno == EACCES) {
|
||||
_tclosedir(d);
|
||||
SAFE_FREE(fname);
|
||||
c_free_locale_string(wfname);
|
||||
c_free_locale_string(rd_name);
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
c_rmdirs(fname);
|
||||
}
|
||||
} else {
|
||||
_tunlink(wfname);
|
||||
}
|
||||
} /* lstat */
|
||||
SAFE_FREE(fname);
|
||||
c_free_locale_string(wfname);
|
||||
c_free_locale_string(rd_name);
|
||||
} /* readdir */
|
||||
|
||||
_trewinddir(d);
|
||||
}
|
||||
} else {
|
||||
c_free_locale_string(wpath);
|
||||
return -1;
|
||||
}
|
||||
c_free_locale_string(wpath);
|
||||
_tclosedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_isdir(const char *path) {
|
||||
csync_stat_t sb;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
int re = 0;
|
||||
|
||||
if (path != NULL) {
|
||||
if (_tstat (wpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
re = 1;
|
||||
}
|
||||
}
|
||||
c_free_locale_string(wpath);
|
||||
return re;
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_dir.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc directory function
|
||||
*
|
||||
* @defgroup cynDirInternals cynapses libc directory functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_DIR_H
|
||||
#define _C_DIR_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create parent directories as needed.
|
||||
*
|
||||
* The newly created directory will be owned by the effective user ID of the
|
||||
* process.
|
||||
*
|
||||
* @param path The path to the directory to create.
|
||||
*
|
||||
* @param mode Specifies the permissions to use. It is modified
|
||||
* by the process's umask in the usual way: the
|
||||
* permissions of the created file are (mode & ~umask).
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set:
|
||||
* - EACCES The parent directory does not allow write
|
||||
* permission to the process, or one of the directories
|
||||
* - ENOTDIR if durl is not a directory
|
||||
* - EINVAL NULL durl passed or smbc_init not called.
|
||||
* - ENOMEM Insufficient memory was available.
|
||||
*
|
||||
* @see mkdir()
|
||||
*/
|
||||
int c_mkdirs(const char *path, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Remove the directory and subdirectories including the content.
|
||||
*
|
||||
* This removes all directories and files recursivly.
|
||||
*
|
||||
* @param dir The directory to remove recusively.
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set.
|
||||
*/
|
||||
int c_rmdirs(const char *dir);
|
||||
|
||||
/**
|
||||
* @brief Check if a path is a directory.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a directory, 0 if the path doesn't exist, is a
|
||||
* file or can't be accessed.
|
||||
*/
|
||||
int c_isdir(const char *path);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CDIR_H */
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "c_file.h"
|
||||
#include "c_string.h"
|
||||
|
||||
#include "c_private.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
/* check if path is a symlink */
|
||||
int c_islink(const char *path) {
|
||||
int re = 0;
|
||||
|
||||
mbchar_t *wpath = 0;
|
||||
DWORD dwAttrs;
|
||||
WIN32_FIND_DATAW FindFileData;
|
||||
HANDLE hFind;
|
||||
|
||||
wpath = c_utf8_to_locale(path);
|
||||
|
||||
dwAttrs = GetFileAttributesW(wpath);
|
||||
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
|
||||
|
||||
if ((dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
hFind = FindFirstFileW(wpath, &FindFileData );
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
if( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
(FindFileData.dwReserved0 & IO_REPARSE_TAG_SYMLINK) ) {
|
||||
re = 1;
|
||||
}
|
||||
}
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
c_free_locale_string(wpath);
|
||||
return re;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if path is a file */
|
||||
int c_isfile(const char *path) {
|
||||
csync_stat_t sb;
|
||||
mbchar_t *wpath = c_utf8_to_locale(path);
|
||||
|
||||
int re = _tstat(wpath, &sb);
|
||||
c_free_locale_string(wpath);
|
||||
|
||||
if (re< 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __unix__
|
||||
if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
|
||||
#else
|
||||
if (S_ISREG(sb.st_mode)) {
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy file from src to dst, overwrites dst */
|
||||
#ifdef _WIN32
|
||||
int c_copy(const char* src, const char *dst, mode_t mode) {
|
||||
int rc = -1;
|
||||
mbchar_t *wsrc = 0;
|
||||
mbchar_t *wdst = 0;
|
||||
(void) mode; /* unused on win32 */
|
||||
if(src && dst) {
|
||||
wsrc = c_utf8_to_locale(src);
|
||||
wdst = c_utf8_to_locale(dst);
|
||||
if (CopyFileW(wsrc, wdst, FALSE)) {
|
||||
rc = 0;
|
||||
}
|
||||
c_free_locale_string(wsrc);
|
||||
c_free_locale_string(wdst);
|
||||
if( rc < 0 ) {
|
||||
errno = GetLastError();
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
int c_copy(const char* src, const char *dst, mode_t mode) {
|
||||
int srcfd = -1;
|
||||
int dstfd = -1;
|
||||
int rc = -1;
|
||||
ssize_t bread, bwritten;
|
||||
csync_stat_t sb;
|
||||
char buf[4096];
|
||||
|
||||
if (c_streq(src, dst)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
srcfd = open(src, O_RDONLY, 0);
|
||||
if (srcfd < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _tfstat(srcfd, &sb);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
errno = EISDIR;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
mode = sb.st_mode;
|
||||
}
|
||||
|
||||
dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
|
||||
if (dstfd < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _tfstat(dstfd, &sb);
|
||||
if (rc == 0) {
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
errno = EISDIR;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bread = read(srcfd, buf, sizeof(buf));
|
||||
if (bread == 0) {
|
||||
/* done */
|
||||
break;
|
||||
} else if (bread < 0) {
|
||||
errno = ENODATA;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bwritten = write(dstfd, buf, bread);
|
||||
if (bwritten < 0) {
|
||||
errno = ENODATA;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bread != bwritten) {
|
||||
errno = EFAULT;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __unix__
|
||||
fsync(dstfd);
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (srcfd >= 0) {
|
||||
close(srcfd);
|
||||
}
|
||||
if (dstfd >= 0) {
|
||||
close(dstfd);
|
||||
}
|
||||
if (rc < 0 && c_isfile(dst)) {
|
||||
unlink(dst);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int c_rename( const char *src, const char *dst ) {
|
||||
mbchar_t *nuri = NULL;
|
||||
mbchar_t *ouri = NULL;
|
||||
int rc = 0;
|
||||
|
||||
nuri = c_utf8_to_locale(dst);
|
||||
if (nuri == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ouri = c_utf8_to_locale(src);
|
||||
if (ouri == NULL) {
|
||||
c_free_locale_string(nuri);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
#define MAX_TRIES_RENAME 3
|
||||
int err = 0;
|
||||
int cnt = 0;
|
||||
|
||||
do {
|
||||
BOOL ok;
|
||||
ok = MoveFileExW(ouri,
|
||||
nuri,
|
||||
MOVEFILE_COPY_ALLOWED +
|
||||
MOVEFILE_REPLACE_EXISTING +
|
||||
MOVEFILE_WRITE_THROUGH);
|
||||
if (!ok) {
|
||||
/* error */
|
||||
err = GetLastError();
|
||||
if( (err == ERROR_ACCESS_DENIED ||
|
||||
err == ERROR_LOCK_VIOLATION ||
|
||||
err == ERROR_SHARING_VIOLATION) && cnt < MAX_TRIES_RENAME ) {
|
||||
cnt++;
|
||||
Sleep(cnt*100);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} while( 1 );
|
||||
if( err != 0 ) {
|
||||
errno = err;
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
rc = rename(ouri, nuri);
|
||||
#endif
|
||||
|
||||
c_free_locale_string(nuri);
|
||||
c_free_locale_string(ouri);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int c_compare_file( const char *f1, const char *f2 ) {
|
||||
mbchar_t *wf1, *wf2;
|
||||
int fd1 = -1, fd2 = -1;
|
||||
size_t size1, size2;
|
||||
char buffer1[BUFFER_SIZE];
|
||||
char buffer2[BUFFER_SIZE];
|
||||
csync_stat_t stat1;
|
||||
csync_stat_t stat2;
|
||||
|
||||
int rc = -1;
|
||||
|
||||
if(f1 == NULL || f2 == NULL) return -1;
|
||||
|
||||
wf1 = c_utf8_to_locale(f1);
|
||||
if(wf1 == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
wf2 = c_utf8_to_locale(f2);
|
||||
if(wf2 == NULL) {
|
||||
c_free_locale_string(wf1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_fmode = _O_BINARY;
|
||||
#endif
|
||||
|
||||
fd1 = _topen(wf1, O_RDONLY);
|
||||
if(fd1 < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd2 = _topen(wf2, O_RDONLY);
|
||||
if(fd2 < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* compare size first. */
|
||||
rc = _tfstat(fd1, &stat1);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _tfstat(fd2, &stat2);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if sizes are different, the files can not be equal. */
|
||||
if (stat1.st_size != stat2.st_size) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while( (size1 = read(fd1, buffer1, BUFFER_SIZE)) > 0 ) {
|
||||
size2 = read( fd2, buffer2, BUFFER_SIZE );
|
||||
|
||||
if( size1 != size2 ) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
if(memcmp(buffer1, buffer2, size1) != 0) {
|
||||
/* buffers are different */
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
|
||||
out:
|
||||
|
||||
if(fd1 > -1) close(fd1);
|
||||
if(fd2 > -1) close(fd2);
|
||||
|
||||
c_free_locale_string( wf1 );
|
||||
c_free_locale_string( wf2 );
|
||||
return rc;
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_file.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc file function
|
||||
*
|
||||
* @defgroup cynFileInternals cynapses libc file functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_FILE_H
|
||||
#define _C_FILE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef BUFFER_SIZE
|
||||
#define BUFFER_SIZE (16 * 1024)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief Check if a path is a link.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a symbolic link, 0 if the path doesn't
|
||||
* exist or is something else.
|
||||
*/
|
||||
int c_islink(const char *path);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Check if a path is a regular file or a link.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a file, 0 if the path doesn't exist, is
|
||||
* something else or can't be accessed.
|
||||
*/
|
||||
int c_isfile(const char *path);
|
||||
|
||||
/**
|
||||
* @brief copy a file from source to destination.
|
||||
*
|
||||
* @param src Path to the source file
|
||||
* @param dst Path to the destination file
|
||||
* @param mode File creation mode of the destination. If mode is 0 then the
|
||||
* mode from the source will be used.
|
||||
*
|
||||
* @return 0 on success, less than 0 on error with errno set.
|
||||
* EISDIR if src or dst is a file.
|
||||
*/
|
||||
int c_copy(const char *src, const char *dst, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Compare the content of two files byte by byte.
|
||||
* @param f1 Path of file 1
|
||||
* @param f2 Path of file 2
|
||||
*
|
||||
* @return 0 if the files differ, 1 if the files are equal or -1 on
|
||||
* error with errno set.
|
||||
*/
|
||||
int c_compare_file( const char *f1, const char *f2 );
|
||||
|
||||
/**
|
||||
* @brief move a file from source to destination.
|
||||
*
|
||||
* @param src Path to the source file
|
||||
* @param dst Path to the destination file
|
||||
*
|
||||
* @return 0 on success, less than 0 on error with errno set.
|
||||
*/
|
||||
int c_rename( const char *src, const char *dst );
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_FILE_H */
|
||||
|
||||
@@ -23,45 +23,9 @@
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_dir.h"
|
||||
#include "c_file.h"
|
||||
#include "c_list.h"
|
||||
#include "c_path.h"
|
||||
#include "c_rbtree.h"
|
||||
#include "c_string.h"
|
||||
#include "c_time.h"
|
||||
#include "c_private.h"
|
||||
|
||||
#ifndef UNIT_TESTING
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#endif
|
||||
#define malloc(x) DO_NOT_CALL_MALLOC__USE_C_MALLOC_INSTEAD
|
||||
|
||||
#ifdef calloc
|
||||
#undef calloc
|
||||
#endif
|
||||
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_C_CALLOC_INSTEAD
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef realloc
|
||||
#undef realloc
|
||||
#endif
|
||||
#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_C_REALLOC_INSTEAD
|
||||
|
||||
#ifdef dirname
|
||||
#undef dirname
|
||||
#endif
|
||||
#define dirname(x) DO_NOT_CALL_MALLOC__USE_C_DIRNAME_INSTEAD
|
||||
|
||||
#ifdef basename
|
||||
#undef basename
|
||||
#endif
|
||||
#define basename(x) DO_NOT_CALL_MALLOC__USE_C_BASENAME_INSTEAD
|
||||
|
||||
#ifdef strdup
|
||||
#undef strdup
|
||||
#endif
|
||||
#define strdup(x) DO_NOT_CALL_STRDUP__USE_C_STRDUP_INSTEAD
|
||||
|
||||
|
||||
@@ -117,81 +117,6 @@ char *c_basename (const char *path) {
|
||||
return newbuf;
|
||||
}
|
||||
|
||||
|
||||
char *c_tmpname(const char *templ) {
|
||||
char *tmp = NULL;
|
||||
char *target = NULL;
|
||||
int rc;
|
||||
int i = 0;
|
||||
|
||||
if (!templ) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If the template does not contain the XXXXXX it will be appended. */
|
||||
if( !strstr( templ, "XXXXXX" )) {
|
||||
/* split up the path */
|
||||
char *path = c_dirname(templ);
|
||||
char *base = c_basename(templ);
|
||||
|
||||
if (!base) {
|
||||
if (path) {
|
||||
SAFE_FREE(path);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
/* Create real hidden files for unixoide. */
|
||||
if( path ) {
|
||||
#ifdef _WIN32
|
||||
rc = asprintf(&target, "%s/%s.~XXXXXX", path, base);
|
||||
#else
|
||||
rc = asprintf(&target, "%s/.%s.~XXXXXX", path, base);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
rc = asprintf(&target, "%s.~XXXXXX", base);
|
||||
#else
|
||||
rc = asprintf(&target, ".%s.~XXXXXX", base);
|
||||
#endif
|
||||
|
||||
}
|
||||
SAFE_FREE(path);
|
||||
SAFE_FREE(base);
|
||||
|
||||
if (rc < 0) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
target = c_strdup(templ);
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
goto err;
|
||||
}
|
||||
tmp = strstr( target, "XXXXXX" );
|
||||
if (!tmp) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
#ifdef _WIN32
|
||||
/* in win32 MAX_RAND is 32767, thus we can not shift that far,
|
||||
* otherwise the last three chars are 0
|
||||
*/
|
||||
int hexdigit = (rand() >> (i * 2)) & 0x1f;
|
||||
#else
|
||||
int hexdigit = (rand() >> (i * 5)) & 0x1f;
|
||||
#endif
|
||||
tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
|
||||
}
|
||||
|
||||
return target;
|
||||
|
||||
err:
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int c_parse_uri(const char *uri,
|
||||
char **scheme,
|
||||
char **user, char **passwd,
|
||||
@@ -470,84 +395,3 @@ int c_parse_uri(const char *uri,
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* http://refactormycode.com/codes/1345-extracting-directory-filename-and-extension-from-a-path
|
||||
* Allocate a block of memory that holds the PATHINFO at the beginning
|
||||
* followed by the actual path. Two extra bytes are allocated (+3 instead
|
||||
* of just +1) to deal with shifting the filename and extension to protect the trailing '/'
|
||||
* and the leading '.'. These extra bytes also double as the empty string, as
|
||||
* well as a pad to keep from reading past the memory block.
|
||||
*
|
||||
*/
|
||||
C_PATHINFO * c_split_path(const char* pathSrc)
|
||||
{
|
||||
size_t length = strlen(pathSrc);
|
||||
size_t len=0;
|
||||
C_PATHINFO * pathinfo = (C_PATHINFO *) c_malloc(sizeof(C_PATHINFO) + length + 3);
|
||||
|
||||
if (pathinfo)
|
||||
{
|
||||
char * path = (char *) &pathinfo[1]; // copy of the path
|
||||
char * theEnd = &path[length + 1]; // second null terminator
|
||||
char * extension;
|
||||
char * lastSep;
|
||||
|
||||
// Copy the original string and double null terminate it.
|
||||
strcpy(path, pathSrc);
|
||||
*theEnd = '\0';
|
||||
pathinfo->directory = theEnd; // Assume no path
|
||||
pathinfo->extension = theEnd; // Assume no extension
|
||||
pathinfo->filename = path; // Assume filename only
|
||||
|
||||
lastSep = strrchr(path, '/');
|
||||
if (lastSep)
|
||||
{
|
||||
pathinfo->directory = path; // Pick up the path
|
||||
|
||||
memmove(lastSep + 1, lastSep, strlen(lastSep));
|
||||
*lastSep++ ='/';
|
||||
*lastSep++ ='\0'; // Truncate directory
|
||||
|
||||
pathinfo->filename = lastSep; // Pick up name after path
|
||||
}
|
||||
|
||||
// Start at the second character of the filename to handle
|
||||
// filenames that start with '.' like ".login".
|
||||
// We don't overrun the buffer in the cases of an empty path
|
||||
// or a path that looks like "/usr/bin/" because of the extra
|
||||
// byte.
|
||||
|
||||
|
||||
extension = strrchr(&pathinfo->filename[1], '.');
|
||||
if (extension)
|
||||
{
|
||||
// Shift the extension over to protect the leading '.' since
|
||||
// we need to truncate the filename.
|
||||
memmove(extension + 1, extension, strlen(extension));
|
||||
pathinfo->extension = extension + 1;
|
||||
|
||||
*extension = '\0'; // Truncate filename
|
||||
}
|
||||
else
|
||||
{
|
||||
len=strlen(pathinfo->filename);
|
||||
if(len>1)
|
||||
{
|
||||
//tmp files from kate/kwrite "somefile~": '~' should be the extension
|
||||
if(pathinfo->filename[len-1]=='~')
|
||||
{
|
||||
extension = &pathinfo->filename[len-1];
|
||||
memmove(extension + 1, extension, strlen(extension));
|
||||
pathinfo->extension = extension + 1;
|
||||
*extension = '\0'; // Truncate filename
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pathinfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,19 +66,6 @@ char *c_dirname(const char *path);
|
||||
*/
|
||||
char *c_basename (const char *path);
|
||||
|
||||
/**
|
||||
* @brief Make a temporary filename.
|
||||
*
|
||||
* @param templ The template to replace. If the template contains six X like
|
||||
* 'XXXXXX', these are replaced by a random string. If not, the
|
||||
* templ is interpreted as a path, and a name to a hidden file
|
||||
* with six random is returned.
|
||||
* The caller has to free the memory.
|
||||
*
|
||||
* @return a poitner to the random hidden filename or NULL.
|
||||
*/
|
||||
char *c_tmpname(const char *templ);
|
||||
|
||||
/**
|
||||
* @brief parse a uri and split it into components.
|
||||
*
|
||||
@@ -120,15 +107,6 @@ typedef struct
|
||||
char * extension;
|
||||
} C_PATHINFO;
|
||||
|
||||
/**
|
||||
* @brief Extracting directory, filename and extension from a path.
|
||||
*
|
||||
* @param pathSrc The path to parse.
|
||||
*
|
||||
* @return Returns a C_PATHINFO structure that should be freed using SAFE_FREE().
|
||||
*/
|
||||
C_PATHINFO * c_split_path(const char* pathSrc);
|
||||
|
||||
|
||||
/**
|
||||
* }@
|
||||
|
||||
@@ -239,69 +239,6 @@ void c_strlist_destroy(c_strlist_t *strlist) {
|
||||
SAFE_FREE(strlist);
|
||||
}
|
||||
|
||||
char *c_strreplace(char *src, const char *pattern, const char *repl) {
|
||||
char *p = NULL;
|
||||
|
||||
while ((p = strstr(src, pattern)) != NULL) {
|
||||
size_t of = p - src;
|
||||
size_t l = strlen(src);
|
||||
size_t pl = strlen(pattern);
|
||||
size_t rl = strlen(repl);
|
||||
|
||||
if (rl > pl) {
|
||||
src = (char *) c_realloc(src, strlen(src) + rl - pl + 1);
|
||||
}
|
||||
|
||||
if (rl != pl) {
|
||||
memmove(src + of + rl, src + of + pl, l - of - pl + 1);
|
||||
}
|
||||
|
||||
strncpy(src + of, repl, rl);
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
char *c_uppercase(const char* str) {
|
||||
char *new;
|
||||
char *p;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = c_strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = new; *p; p++) {
|
||||
*p = toupper(*p);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
char *c_lowercase(const char* str) {
|
||||
char *new;
|
||||
char *p;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = c_strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = new; *p; p++) {
|
||||
*p = tolower(*p);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Convert a wide multibyte String to UTF8 */
|
||||
char* c_utf8_from_locale(const mbchar_t *wstr)
|
||||
{
|
||||
|
||||
@@ -119,37 +119,6 @@ void c_strlist_clear(c_strlist_t *strlist);
|
||||
*/
|
||||
void c_strlist_destroy(c_strlist_t *strlist);
|
||||
|
||||
/**
|
||||
* @breif Replace a string with another string in a source string.
|
||||
*
|
||||
* @param src String to search for pattern.
|
||||
*
|
||||
* @param pattern Pattern to search for in the source string.
|
||||
*
|
||||
* @param repl The string which which should replace pattern if found.
|
||||
*
|
||||
* @return Return a pointer to the source string.
|
||||
*/
|
||||
char *c_strreplace(char *src, const char *pattern, const char *repl);
|
||||
|
||||
/**
|
||||
* @brief Uppercase a string.
|
||||
*
|
||||
* @param str The String to uppercase.
|
||||
*
|
||||
* @return The malloced uppered string or NULL on error.
|
||||
*/
|
||||
char *c_uppercase(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Lowercase a string.
|
||||
*
|
||||
* @param str The String to lowercase.
|
||||
*
|
||||
* @return The malloced lowered string or NULL on error.
|
||||
*/
|
||||
char *c_lowercase(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Convert a platform locale string to utf8.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_util.h"
|
||||
@@ -44,7 +45,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
|
||||
if(ctx->remote.read_from_db) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
|
||||
}
|
||||
return owncloud_opendir(name);
|
||||
return owncloud_opendir(ctx, name);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
return csync_vio_local_opendir(name);
|
||||
@@ -69,7 +70,7 @@ int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
|
||||
if( ctx->remote.read_from_db ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
|
||||
}
|
||||
rc = owncloud_closedir(dhandle);
|
||||
rc = owncloud_closedir(ctx, dhandle);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
rc = csync_vio_local_closedir(dhandle);
|
||||
@@ -87,7 +88,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
|
||||
if( ctx->remote.read_from_db ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
|
||||
}
|
||||
return owncloud_readdir(dhandle);
|
||||
return owncloud_readdir(ctx, dhandle);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
return csync_vio_local_readdir(dhandle);
|
||||
@@ -106,7 +107,8 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||
|
||||
switch(ctx->replica) {
|
||||
case REMOTE_REPLICA:
|
||||
rc = owncloud_stat(uri, buf);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
|
||||
assert(ctx->replica != REMOTE_REPLICA);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
rc = csync_vio_local_stat(uri, buf);
|
||||
@@ -121,21 +123,9 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *csync_vio_get_status_string(CSYNC *ctx) {
|
||||
if(ctx->error_string) {
|
||||
return ctx->error_string;
|
||||
}
|
||||
return owncloud_error_string();
|
||||
}
|
||||
|
||||
int csync_vio_set_property(CSYNC* ctx, const char* key, void* data) {
|
||||
(void) ctx;
|
||||
return owncloud_set_property(key, data);
|
||||
}
|
||||
|
||||
int csync_vio_commit(CSYNC *ctx) {
|
||||
(void) ctx;
|
||||
return owncloud_commit();
|
||||
return owncloud_error_string(ctx);
|
||||
}
|
||||
|
||||
@@ -39,10 +39,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
|
||||
|
||||
int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf);
|
||||
|
||||
int csync_vio_set_property(CSYNC *ctx, const char *key, void *data);
|
||||
|
||||
char *csync_vio_get_status_string(CSYNC *ctx);
|
||||
|
||||
int csync_vio_commit(CSYNC *ctx);
|
||||
|
||||
#endif /* _CSYNC_VIO_H */
|
||||
|
||||
@@ -22,14 +22,8 @@
|
||||
#include "vio/csync_vio_file_stat.h"
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||
csync_vio_file_stat_t *file_stat = NULL;
|
||||
|
||||
file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
if (file_stat == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
file_stat->etag = NULL;
|
||||
memset(file_stat->file_id, 0, FILE_ID_BUF_SIZE+1);
|
||||
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
ZERO_STRUCTP(file_stat);
|
||||
return file_stat;
|
||||
}
|
||||
|
||||
@@ -39,15 +33,11 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME) {
|
||||
SAFE_FREE(file_stat->u.symlink_name);
|
||||
}
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM) {
|
||||
SAFE_FREE(file_stat->u.checksum);
|
||||
}
|
||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||
SAFE_FREE(file_stat->etag);
|
||||
}
|
||||
SAFE_FREE(file_stat->directDownloadUrl);
|
||||
SAFE_FREE(file_stat->directDownloadCookies);
|
||||
SAFE_FREE(file_stat->name);
|
||||
SAFE_FREE(file_stat);
|
||||
}
|
||||
|
||||
@@ -34,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;
|
||||
|
||||
@@ -316,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 */
|
||||
@@ -324,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;
|
||||
@@ -332,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;
|
||||
|
||||
@@ -349,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);
|
||||
|
||||
@@ -34,7 +34,6 @@ use LWP::UserAgent;
|
||||
use LWP::Protocol::https;
|
||||
use HTTP::Request::Common qw( POST GET DELETE );
|
||||
use File::Basename;
|
||||
use POSIX qw/strftime/;
|
||||
|
||||
use Encode qw(from_to);
|
||||
use utf8;
|
||||
@@ -129,9 +128,8 @@ sub initTesting(;$)
|
||||
# $d->DebugLevel(3);
|
||||
$prefix = "t1" unless( defined $prefix );
|
||||
|
||||
my $dirId = sprintf("%02d", rand(100));
|
||||
my $dateTime = strftime('%Y%m%d%H%M%S',localtime);
|
||||
my $dir = sprintf( "%s-%s-%s/", $prefix, $dateTime, $dirId );
|
||||
my $dirId = sprintf("%#.3o", rand(1000));
|
||||
my $dir = sprintf( "%s-%s/", $prefix, $dirId );
|
||||
|
||||
$localDir = $dir;
|
||||
$localDir .= "/" unless( $localDir =~ /\/$/ );
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Arquivo executável
+256
@@ -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);
|
||||
|
||||
externo
+1
-1
Submodule src/3rdparty/qtmacgoodies updated: fa06775714...cf09d34dc7
+6
-11
@@ -45,7 +45,6 @@ if (APPLE)
|
||||
list(APPEND 3rdparty_SRC
|
||||
3rdparty/qtmacgoodies/src/macpreferenceswindow.mm
|
||||
3rdparty/qtmacgoodies/src/macstandardicon.mm
|
||||
3rdparty/qtmacgoodies/src/macwindow.mm
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -83,11 +82,11 @@ set(libsync_SRCS
|
||||
mirall/folderman.cpp
|
||||
mirall/folder.cpp
|
||||
mirall/folderwatcher.cpp
|
||||
mirall/authenticationdialog.cpp
|
||||
mirall/syncresult.cpp
|
||||
mirall/mirallconfigfile.cpp
|
||||
mirall/syncengine.cpp
|
||||
mirall/owncloudpropagator.cpp
|
||||
mirall/bandwidthmanager.cpp
|
||||
mirall/propagatorjobs.cpp
|
||||
mirall/propagator_qnam.cpp
|
||||
mirall/propagator_legacy.cpp
|
||||
@@ -107,7 +106,6 @@ set(libsync_SRCS
|
||||
mirall/clientproxy.cpp
|
||||
mirall/syncrunfilelog.cpp
|
||||
mirall/cookiejar.cpp
|
||||
mirall/accountmigrator.cpp
|
||||
creds/dummycredentials.cpp
|
||||
creds/abstractcredentials.cpp
|
||||
creds/credentialsfactory.cpp
|
||||
@@ -127,6 +125,7 @@ else()
|
||||
creds/shibbolethcredentials.cpp
|
||||
creds/shibboleth/shibbolethwebview.cpp
|
||||
creds/shibboleth/shibbolethrefresher.cpp
|
||||
creds/shibboleth/authenticationdialog.cpp
|
||||
creds/shibboleth/shibbolethuserjob.cpp
|
||||
)
|
||||
endif()
|
||||
@@ -248,7 +247,7 @@ else()
|
||||
install(TARGETS ${synclib_NAME} DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
|
||||
if (SPARKLE_FOUND)
|
||||
install(DIRECTORY "${SPARKLE_LIBRARY}"
|
||||
DESTINATION "${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks" USE_SOURCE_PERMISSIONS)
|
||||
DESTINATION "${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks")
|
||||
endif (SPARKLE_FOUND)
|
||||
|
||||
endif()
|
||||
@@ -357,7 +356,9 @@ ENDIF()
|
||||
include_directories(../csync/src ../csync/src/httpbf/src ${CMAKE_CURRENT_BINARY_DIR}/../csync ${CMAKE_CURRENT_BINARY_DIR}/../csync/src )
|
||||
include_directories(${3rdparty_INC})
|
||||
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
qt_add_translation(mirall_I18N ${TRANSLATIONS})
|
||||
endif()
|
||||
|
||||
set( final_src
|
||||
${mirall_HEADERS}
|
||||
@@ -390,6 +391,7 @@ set(ownCloud ${ownCloud_old})
|
||||
if (WITH_DBUS)
|
||||
set(ADDITIONAL_APP_MODULES DBus)
|
||||
endif(WITH_DBUS)
|
||||
|
||||
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
@@ -426,15 +428,8 @@ elseif(NOT BUILD_LIBRARIES_ONLY)
|
||||
|
||||
set (QM_DIR ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/Translations)
|
||||
install(FILES ${mirall_I18N} DESTINATION ${QM_DIR})
|
||||
get_target_property(_qmake Qt5::qmake LOCATION)
|
||||
execute_process(COMMAND ${_qmake} -query QT_INSTALL_TRANSLATIONS
|
||||
OUTPUT_VARIABLE QT_TRANSLATIONS_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
file(GLOB qt_I18N ${QT_TRANSLATIONS_DIR}/qt_??.qm ${QT_TRANSLATIONS_DIR}/qt_??_??.qm)
|
||||
install(FILES ${qt_I18N} DESTINATION ${QM_DIR})
|
||||
file(GLOB qtbase_I18N ${QT_TRANSLATIONS_DIR}/qtbase_??.qm ${QT_TRANSLATIONS_DIR}/qt_??_??.qm)
|
||||
install(FILES ${qtbase_I18N} DESTINATION ${QM_DIR})
|
||||
file(GLOB qtkeychain_I18N ${QT_TRANSLATIONS_DIR}/qtkeychain*.qm)
|
||||
install(FILES ${qtkeychain_I18N} DESTINATION ${QM_DIR})
|
||||
endif()
|
||||
|
||||
@@ -48,8 +48,9 @@ int getauth(const char *prompt,
|
||||
void *userdata)
|
||||
{
|
||||
int re = 0;
|
||||
QMutex mutex;
|
||||
// ### safe?
|
||||
|
||||
// ### safe? Not really. If the wizard is run in the main thread, the caccount could change during the sync.
|
||||
// Ideally, http_credentials could be use userdata, but userdata is the SyncEngine.
|
||||
HttpCredentials* http_credentials = qobject_cast<HttpCredentials*>(AccountManager::instance()->account()->credentials());
|
||||
|
||||
if (!http_credentials) {
|
||||
@@ -63,10 +64,8 @@ int getauth(const char *prompt,
|
||||
|
||||
if( qPrompt == QLatin1String("Enter your username:") ) {
|
||||
// qDebug() << "OOO Username requested!";
|
||||
QMutexLocker locker( &mutex );
|
||||
qstrncpy( buf, user.toUtf8().constData(), len );
|
||||
} else if( qPrompt == QLatin1String("Enter your password:") ) {
|
||||
QMutexLocker locker( &mutex );
|
||||
// qDebug() << "OOO Password requested!";
|
||||
qstrncpy( buf, pwd.toUtf8().constData(), len );
|
||||
} else {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "creds/shibboleth/authenticationdialog.h"
|
||||
#include "creds/shibboleth/shibbolethwebview.h"
|
||||
#include "creds/shibboleth/shibbolethrefresher.h"
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
@@ -172,6 +173,8 @@ QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
|
||||
QNetworkAccessManager* qnam(new MirallAccessManager);
|
||||
connect(qnam, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(slotReplyFinished(QNetworkReply*)));
|
||||
connect(qnam, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
|
||||
SLOT(slotHandleAuthentication(QNetworkReply*,QAuthenticator*)));
|
||||
return qnam;
|
||||
}
|
||||
|
||||
@@ -316,6 +319,23 @@ void ShibbolethCredentials::invalidateAndFetch(Account* account)
|
||||
job->start();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotHandleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
|
||||
{
|
||||
Q_UNUSED(reply)
|
||||
QUrl url = reply->url();
|
||||
// show only scheme, host and port
|
||||
QUrl reducedUrl;
|
||||
reducedUrl.setScheme(url.scheme());
|
||||
reducedUrl.setHost(url.host());
|
||||
reducedUrl.setPort(url.port());
|
||||
|
||||
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString());
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
authenticator->setUser(dialog.user());
|
||||
authenticator->setPassword(dialog.password());
|
||||
}
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job* job)
|
||||
{
|
||||
Account *account = qvariant_cast<Account*>(job->property("account"));
|
||||
@@ -385,7 +405,7 @@ void ShibbolethCredentials::showLoginWindow(Account* account)
|
||||
|
||||
QList<QNetworkCookie> ShibbolethCredentials::accountCookies(Account *account)
|
||||
{
|
||||
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->davUrl());
|
||||
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->url());
|
||||
}
|
||||
|
||||
QNetworkCookie ShibbolethCredentials::findShibCookie(Account *account, QList<QNetworkCookie> cookies)
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
|
||||
public Q_SLOTS:
|
||||
void invalidateAndFetch(Account *account);
|
||||
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onShibbolethCookieReceived(const QNetworkCookie&, Account*);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <QDebug>
|
||||
#include <QNetworkReply>
|
||||
#include <QSettings>
|
||||
#include <QNetworkCookieJar>
|
||||
|
||||
#include "mirall/account.h"
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
@@ -79,11 +80,19 @@ public:
|
||||
: MirallAccessManager(parent), _cred(cred) {}
|
||||
protected:
|
||||
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
|
||||
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
|
||||
if (_cred->user().isEmpty() || _cred->password().isEmpty() || _cred->_token.isEmpty()) {
|
||||
qWarning() << Q_FUNC_INFO << "Empty user/password/token provided!";
|
||||
}
|
||||
|
||||
QNetworkRequest req(request);
|
||||
|
||||
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
|
||||
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
|
||||
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
|
||||
req.setRawHeader(QByteArray("Cookie"), _cred->_token.toLocal8Bit());
|
||||
|
||||
// A pre-authenticated cookie
|
||||
QByteArray token = _cred->_token.toUtf8();
|
||||
setRawCookie(token, request.url());
|
||||
|
||||
return MirallAccessManager::createRequest(op, req, outgoingData);
|
||||
}
|
||||
private:
|
||||
@@ -112,7 +121,7 @@ void TokenCredentials::syncContextPreInit (CSYNC* ctx)
|
||||
|
||||
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
|
||||
{
|
||||
csync_set_module_property(ctx, "session_key", _token.toLocal8Bit().data());
|
||||
csync_set_module_property(ctx, "session_key", _token.toUtf8().data());
|
||||
}
|
||||
|
||||
bool TokenCredentials::changed(AbstractCredentials* credentials) const
|
||||
@@ -156,12 +165,6 @@ bool TokenCredentials::ready() const
|
||||
return _ready;
|
||||
}
|
||||
|
||||
QString TokenCredentials::fetchUser(Account* account)
|
||||
{
|
||||
_user = account->credentialSetting(QLatin1String(userC)).toString();
|
||||
return _user;
|
||||
}
|
||||
|
||||
void TokenCredentials::fetch(Account *account)
|
||||
{
|
||||
if( !account ) {
|
||||
@@ -169,10 +172,11 @@ void TokenCredentials::fetch(Account *account)
|
||||
}
|
||||
Q_EMIT fetched();
|
||||
}
|
||||
|
||||
bool TokenCredentials::stillValid(QNetworkReply *reply)
|
||||
{
|
||||
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
|
||||
// returned if user or password is incorrect
|
||||
// returned if user/password or token are incorrect
|
||||
&& (reply->error() != QNetworkReply::OperationCanceledError
|
||||
|| !reply->property(authenticationFailedC).toBool()));
|
||||
}
|
||||
@@ -184,19 +188,12 @@ QString TokenCredentials::queryPassword(bool *ok)
|
||||
|
||||
void TokenCredentials::invalidateToken(Account *account)
|
||||
{
|
||||
_password = QString();
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
_ready = false;
|
||||
|
||||
// User must be fetched from config file to generate a valid key
|
||||
fetchUser(account);
|
||||
|
||||
const QString kck = keychainKey(account->url().toString(), _user);
|
||||
if( kck.isEmpty() ) {
|
||||
qDebug() << "InvalidateToken: User is empty, bailing out!";
|
||||
return;
|
||||
}
|
||||
|
||||
account->clearCookieJar();
|
||||
_token = QString();
|
||||
_user = QString();
|
||||
_password = QString();
|
||||
}
|
||||
|
||||
void TokenCredentials::persist(Account *account)
|
||||
|
||||
@@ -53,7 +53,6 @@ public:
|
||||
QString password() const;
|
||||
QString queryPassword(bool *ok);
|
||||
void invalidateToken(Account *account);
|
||||
QString fetchUser(Account *account);
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotAuthentication(QNetworkReply*, QAuthenticator*);
|
||||
@@ -61,7 +60,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
QString _user;
|
||||
QString _password;
|
||||
QString _token;
|
||||
QString _token; // the cookies
|
||||
bool _ready;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
#include "mirall/quotainfo.h"
|
||||
#include "mirall/owncloudtheme.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "creds/credentialsfactory.h"
|
||||
|
||||
@@ -28,8 +27,6 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QSslSocket>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
@@ -39,7 +36,6 @@ static const char urlC[] = "url";
|
||||
static const char authTypeC[] = "authType";
|
||||
static const char userC[] = "user";
|
||||
static const char httpUserC[] = "http_user";
|
||||
static const char caCertsKeyC[] = "CaCertificates";
|
||||
|
||||
AccountManager *AccountManager::_instance = 0;
|
||||
|
||||
@@ -75,7 +71,6 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
|
||||
, _treatSslErrorsAsFailure(false)
|
||||
, _state(Account::Disconnected)
|
||||
, _davPath("remote.php/webdav/")
|
||||
, _wasMigrated(false)
|
||||
{
|
||||
qRegisterMetaType<Account*>("Account*");
|
||||
}
|
||||
@@ -103,66 +98,25 @@ void Account::save()
|
||||
}
|
||||
settings->sync();
|
||||
|
||||
// Save accepted certificates.
|
||||
settings->beginGroup(QLatin1String("General"));
|
||||
// ### TODO port away from MirallConfigFile
|
||||
MirallConfigFile cfg;
|
||||
qDebug() << "Saving " << approvedCerts().count() << " unknown certs.";
|
||||
QByteArray certs;
|
||||
Q_FOREACH( const QSslCertificate& cert, approvedCerts() ) {
|
||||
certs += cert.toPem() + '\n';
|
||||
}
|
||||
if (!certs.isEmpty()) {
|
||||
settings->setValue( QLatin1String(caCertsKeyC), certs );
|
||||
cfg.setCaCerts( certs );
|
||||
}
|
||||
}
|
||||
|
||||
Account* Account::restore()
|
||||
{
|
||||
// try to open the correctly themed settings
|
||||
QScopedPointer<QSettings> settings(settingsWithGroup(Theme::instance()->appName()));
|
||||
|
||||
Account *acc = 0;
|
||||
bool migratedCreds = false;
|
||||
|
||||
// if the settings file could not be opened, the childKeys list is empty
|
||||
if( settings->childKeys().isEmpty() ) {
|
||||
// Now try to open the original ownCloud settings to see if they exist.
|
||||
QString oCCfgFile = QDir::fromNativeSeparators( settings->fileName() );
|
||||
// replace the last two segments with ownCloud/owncloud.cfg
|
||||
oCCfgFile = oCCfgFile.left( oCCfgFile.lastIndexOf('/'));
|
||||
oCCfgFile = oCCfgFile.left( oCCfgFile.lastIndexOf('/'));
|
||||
oCCfgFile += QLatin1String("/ownCloud/owncloud.cfg");
|
||||
|
||||
qDebug() << "Migrate: checking old config " << oCCfgFile;
|
||||
|
||||
QFileInfo fi( oCCfgFile );
|
||||
if( fi.isReadable() ) {
|
||||
QSettings *oCSettings = new QSettings(oCCfgFile, QSettings::IniFormat);
|
||||
oCSettings->beginGroup(QLatin1String("ownCloud"));
|
||||
|
||||
// Check the theme url to see if it is the same url that the oC config was for
|
||||
QString overrideUrl = Theme::instance()->overrideServerUrl();
|
||||
if( !overrideUrl.isEmpty() ) {
|
||||
if (overrideUrl.endsWith('/')) { overrideUrl.chop(1); }
|
||||
QString oCUrl = oCSettings->value(QLatin1String(urlC)).toString();
|
||||
if (oCUrl.endsWith('/')) { oCUrl.chop(1); }
|
||||
|
||||
// in case the urls are equal reset the settings object to read from
|
||||
// the ownCloud settings object
|
||||
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
||||
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
||||
if( oCUrl == overrideUrl ) {
|
||||
migratedCreds = true;
|
||||
settings.reset( oCSettings );
|
||||
} else {
|
||||
delete oCSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings->childKeys().isEmpty()) {
|
||||
acc = new Account;
|
||||
|
||||
Account *acc = new Account;
|
||||
MirallConfigFile cfg;
|
||||
acc->setApprovedCerts(QSslCertificate::fromData(cfg.caCerts()));
|
||||
acc->setUrl(settings->value(QLatin1String(urlC)).toUrl());
|
||||
acc->setCredentials(CredentialsFactory::create(settings->value(QLatin1String(authTypeC)).toString()));
|
||||
|
||||
@@ -174,11 +128,6 @@ Account* Account::restore()
|
||||
continue;
|
||||
acc->_settingsMap.insert(key, settings->value(key));
|
||||
}
|
||||
|
||||
// now the cert, it is in the general group
|
||||
settings->beginGroup(QLatin1String("General"));
|
||||
acc->setApprovedCerts(QSslCertificate::fromData(settings->value(caCertsKeyC).toByteArray()));
|
||||
acc->setMigrated(migratedCreds);
|
||||
return acc;
|
||||
}
|
||||
return 0;
|
||||
@@ -415,14 +364,4 @@ void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
|
||||
}
|
||||
}
|
||||
|
||||
bool Account::wasMigrated()
|
||||
{
|
||||
return _wasMigrated;
|
||||
}
|
||||
|
||||
void Account::setMigrated(bool mig)
|
||||
{
|
||||
_wasMigrated = mig;
|
||||
}
|
||||
|
||||
} // namespace Mirall
|
||||
|
||||
@@ -108,13 +108,6 @@ public:
|
||||
/** Returns webdav entry URL, based on url() */
|
||||
QUrl davUrl() const;
|
||||
|
||||
/** set and retrieve the migration flag: if an account of a branded
|
||||
* client was migrated from a former ownCloud Account, this is true
|
||||
*/
|
||||
void setMigrated(bool mig);
|
||||
bool wasMigrated();
|
||||
|
||||
|
||||
QList<QNetworkCookie> lastAuthCookies() const;
|
||||
|
||||
QNetworkReply* headRequest(const QString &relPath);
|
||||
@@ -154,10 +147,8 @@ public:
|
||||
QNetworkAccessManager* networkAccessManager();
|
||||
|
||||
QuotaInfo *quotaInfo();
|
||||
|
||||
signals:
|
||||
void stateChanged(int state);
|
||||
void propagatorNetworkActivity();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotHandleErrors(QNetworkReply*,QList<QSslError>);
|
||||
@@ -175,7 +166,6 @@ private:
|
||||
int _state;
|
||||
static QString _configFileName;
|
||||
QString _davPath; // default "remote.php/webdav/";
|
||||
bool _wasMigrated;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "mirall/accountmigrator.h"
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/folderman.h"
|
||||
#include "mirall/theme.h"
|
||||
|
||||
|
||||
#include <QSettings>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
// The purpose of this class is to migrate an existing account that
|
||||
// was set up with an unbranded client to an branded one.
|
||||
// The usecase is: Usually people try first with the community client,
|
||||
// later they maybe switch to a branded client. When they install the
|
||||
// branded client first, it should automatically pick the information
|
||||
// from the already configured account.
|
||||
|
||||
AccountMigrator::AccountMigrator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// the list of folder definitions which are files in the directory "folders"
|
||||
// underneath the ownCloud configPath (with ownCloud as a last segment)
|
||||
// need to be copied to the themed path and adjusted.
|
||||
|
||||
QStringList AccountMigrator::migrateFolderDefinitons()
|
||||
{
|
||||
MirallConfigFile cfg;
|
||||
QStringList re;
|
||||
|
||||
QString themePath = cfg.configPath();
|
||||
// create the original ownCloud config path out of the theme path
|
||||
// by removing the theme folder and append ownCloud.
|
||||
QString oCPath = themePath;
|
||||
if( oCPath.endsWith(QLatin1Char('/')) ) {
|
||||
oCPath.truncate( oCPath.length()-1 );
|
||||
}
|
||||
oCPath = oCPath.left( oCPath.lastIndexOf('/'));
|
||||
|
||||
themePath += QLatin1String( "folders");
|
||||
oCPath += QLatin1String( "/ownCloud/folders" );
|
||||
|
||||
qDebug() << "Migrator: theme-path: " << themePath;
|
||||
qDebug() << "Migrator: ownCloud path: " << oCPath;
|
||||
|
||||
// get a dir listing of the ownCloud folder definitions and copy
|
||||
// them over to the theme dir
|
||||
QDir oCDir(oCPath);
|
||||
oCDir.setFilter( QDir::Files );
|
||||
QStringList files = oCDir.entryList();
|
||||
|
||||
foreach( const QString& file, files ) {
|
||||
QString escapedAlias = FolderMan::instance()->escapeAlias(file);
|
||||
QString themeFile = themePath + QDir::separator() + file;
|
||||
QString oCFile = oCPath+QDir::separator()+file;
|
||||
if( QFile::copy( oCFile, themeFile ) ) {
|
||||
re.append(file);
|
||||
qDebug() << "Migrator: Folder definition migrated: " << file;
|
||||
|
||||
// fix the connection entry of the folder definition
|
||||
QSettings settings(themeFile, QSettings::IniFormat);
|
||||
settings.beginGroup( escapedAlias );
|
||||
settings.setValue(QLatin1String("connection"), Theme::instance()->appName());
|
||||
settings.sync();
|
||||
}
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTMIGRATOR_H
|
||||
#define ACCOUNTMIGRATOR_H
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
class AccountMigrator {
|
||||
|
||||
public:
|
||||
explicit AccountMigrator();
|
||||
|
||||
/**
|
||||
* @brief migrateFolderDefinitons - migrate the folder definition files
|
||||
* @return the list of migrated folder definitions
|
||||
*/
|
||||
QStringList migrateFolderDefinitons();
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ACCOUNTMIGRATOR_H
|
||||
@@ -713,7 +713,7 @@ void AccountSettings::slotIgnoreFilesEditor()
|
||||
_ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true );
|
||||
_ignoreEditor->open();
|
||||
} else {
|
||||
ownCloudGui::raiseDialog(_ignoreEditor);
|
||||
Utility::raiseDialog(_ignoreEditor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ QString applicationTrPath()
|
||||
#elif defined(Q_OS_MAC)
|
||||
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
|
||||
#elif defined(Q_OS_UNIX)
|
||||
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
|
||||
return QString::fromLatin1(DATADIR "/" APPLICATION_EXECUTABLE "/i18n/");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -532,15 +532,12 @@ void Application::setupTranslations()
|
||||
setProperty("ui_lang", lang);
|
||||
const QString qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
|
||||
const QString qtTrFile = QLatin1String("qt_") + lang;
|
||||
const QString qtBaseTrFile = QLatin1String("qtbase_") + lang;
|
||||
if (!qtTranslator->load(qtTrFile, qtTrPath)) {
|
||||
if (!qtTranslator->load(qtTrFile, trPath)) {
|
||||
qtTranslator->load(qtBaseTrFile, trPath);
|
||||
}
|
||||
if (qtTranslator->load(qtTrFile, qtTrPath)) {
|
||||
qtTranslator->load(qtTrFile, trPath);
|
||||
}
|
||||
const QString qtkeychainTrFile = QLatin1String("qtkeychain_") + lang;
|
||||
if (!qtkeychainTranslator->load(qtkeychainTrFile, qtTrPath)) {
|
||||
qtkeychainTranslator->load(qtkeychainTrFile, trPath);
|
||||
const QString qtkeychainFile = QLatin1String("qt_") + lang;
|
||||
if (!qtkeychainTranslator->load(qtkeychainFile, qtTrPath)) {
|
||||
qtkeychainTranslator->load(qtkeychainFile, trPath);
|
||||
}
|
||||
if (!translator->isEmpty())
|
||||
installTranslator(translator);
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (C) by Markus Goetz <markus@woboq.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "owncloudpropagator.h"
|
||||
#include "propagator_qnam.h"
|
||||
#include "propagatorjobs.h"
|
||||
#include "propagator_legacy.h"
|
||||
#include "mirall/utility.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
// Because of the many layers of buffering inside Qt (and probably the OS and the network)
|
||||
// we cannot lower this value much more. If we do, the estimated bw will be very high
|
||||
// because the buffers fill fast while the actual network algorithms are not relevant yet.
|
||||
static qint64 relativeLimitMeasuringTimerIntervalMsec = 1000*2;
|
||||
// See also WritingState in http://code.woboq.org/qt5/qtbase/src/network/access/qhttpprotocolhandler.cpp.html#_ZN20QHttpProtocolHandler11sendRequestEv
|
||||
|
||||
// FIXME At some point:
|
||||
// * Register device only after the QNR received its metaDataChanged() signal
|
||||
// * Incorporate Qt buffer fill state (it's a negative absolute delta).
|
||||
// * Incorporate SSL overhead (percentage)
|
||||
// * For relative limiting, do less measuring and more delaying+giving quota
|
||||
// * For relative limiting, smoothen measurements
|
||||
|
||||
BandwidthManager::BandwidthManager(OwncloudPropagator *p) : QObject(),
|
||||
_propagator(p),
|
||||
_relativeLimitCurrentMeasuredDevice(0),
|
||||
_relativeUploadLimitProgressAtMeasuringRestart(0),
|
||||
_currentUploadLimit(0),
|
||||
_relativeLimitCurrentMeasuredJob(0),
|
||||
_currentDownloadLimit(0)
|
||||
{
|
||||
_currentUploadLimit = _propagator->_uploadLimit.fetchAndAddAcquire(0);
|
||||
_currentDownloadLimit = _propagator->_downloadLimit.fetchAndAddAcquire(0);
|
||||
|
||||
QObject::connect(&_switchingTimer, SIGNAL(timeout()), this, SLOT(switchingTimerExpired()));
|
||||
_switchingTimer.setInterval(10*1000);
|
||||
_switchingTimer.start();
|
||||
QMetaObject::invokeMethod(this, "switchingTimerExpired", Qt::QueuedConnection);
|
||||
|
||||
// absolute uploads/downloads
|
||||
QObject::connect(&_absoluteLimitTimer, SIGNAL(timeout()), this, SLOT(absoluteLimitTimerExpired()));
|
||||
_absoluteLimitTimer.setInterval(1000);
|
||||
_absoluteLimitTimer.start();
|
||||
|
||||
// Relative uploads
|
||||
QObject::connect(&_relativeUploadMeasuringTimer,SIGNAL(timeout()),
|
||||
this, SLOT(relativeUploadMeasuringTimerExpired()));
|
||||
_relativeUploadMeasuringTimer.setInterval(relativeLimitMeasuringTimerIntervalMsec);
|
||||
_relativeUploadMeasuringTimer.start();
|
||||
_relativeUploadMeasuringTimer.setSingleShot(true); // will be restarted from the delay timer
|
||||
QObject::connect(&_relativeUploadDelayTimer, SIGNAL(timeout()),
|
||||
this, SLOT(relativeUploadDelayTimerExpired()));
|
||||
_relativeUploadDelayTimer.setSingleShot(true); // will be restarted from the measuring timer
|
||||
|
||||
// Relative downloads
|
||||
QObject::connect(&_relativeDownloadMeasuringTimer,SIGNAL(timeout()),
|
||||
this, SLOT(relativeDownloadMeasuringTimerExpired()));
|
||||
_relativeDownloadMeasuringTimer.setInterval(relativeLimitMeasuringTimerIntervalMsec);
|
||||
_relativeDownloadMeasuringTimer.start();
|
||||
_relativeDownloadMeasuringTimer.setSingleShot(true); // will be restarted from the delay timer
|
||||
QObject::connect(&_relativeDownloadDelayTimer, SIGNAL(timeout()),
|
||||
this, SLOT(relativeDownloadDelayTimerExpired()));
|
||||
_relativeDownloadDelayTimer.setSingleShot(true); // will be restarted from the measuring timer
|
||||
}
|
||||
|
||||
void BandwidthManager::registerUploadDevice(UploadDevice *p)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << p;
|
||||
_absoluteUploadDeviceList.append(p);
|
||||
_relativeUploadDeviceList.append(p);
|
||||
QObject::connect(p, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterUploadDevice(QObject*)));
|
||||
|
||||
if (usingAbsoluteUploadLimit()) {
|
||||
p->setBandwidthLimited(true);
|
||||
p->setChoked(false);
|
||||
} else if (usingRelativeUploadLimit()) {
|
||||
p->setBandwidthLimited(true);
|
||||
p->setChoked(true);
|
||||
} else {
|
||||
p->setBandwidthLimited(false);
|
||||
p->setChoked(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::unregisterUploadDevice(QObject *o)
|
||||
{
|
||||
UploadDevice *p = qobject_cast<UploadDevice*>(o);
|
||||
if (p) {
|
||||
unregisterUploadDevice(p);
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << p;
|
||||
_absoluteUploadDeviceList.removeAll(p);
|
||||
_relativeUploadDeviceList.removeAll(p);
|
||||
if (p == _relativeLimitCurrentMeasuredDevice) {
|
||||
_relativeLimitCurrentMeasuredDevice = 0;
|
||||
_relativeUploadLimitProgressAtMeasuringRestart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::registerDownloadJob(GETFileJob* j)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << j;
|
||||
_downloadJobList.append(j);
|
||||
QObject::connect(j, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterDownloadJob(QObject*)));
|
||||
|
||||
if (usingAbsoluteDownloadLimit()) {
|
||||
j->setBandwidthLimited(true);
|
||||
j->setChoked(false);
|
||||
} else if (usingRelativeDownloadLimit()) {
|
||||
j->setBandwidthLimited(true);
|
||||
j->setChoked(true);
|
||||
} else {
|
||||
j->setBandwidthLimited(false);
|
||||
j->setChoked(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::unregisterDownloadJob(GETFileJob* j)
|
||||
{
|
||||
_downloadJobList.removeAll(j);
|
||||
if (_relativeLimitCurrentMeasuredJob == j) {
|
||||
_relativeLimitCurrentMeasuredJob = 0;
|
||||
_relativeDownloadLimitProgressAtMeasuringRestart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::unregisterDownloadJob(QObject* o)
|
||||
{
|
||||
GETFileJob *p = qobject_cast<GETFileJob*>(o);
|
||||
if (p) {
|
||||
unregisterDownloadJob(p);
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::relativeUploadMeasuringTimerExpired()
|
||||
{
|
||||
if (!usingRelativeUploadLimit() || _relativeUploadDeviceList.count() == 0) {
|
||||
// Not in this limiting mode, just wait 1 sec to continue the cycle
|
||||
_relativeUploadDelayTimer.setInterval(1000);
|
||||
_relativeUploadDelayTimer.start();
|
||||
return;
|
||||
}
|
||||
if (_relativeLimitCurrentMeasuredDevice == 0) {
|
||||
qDebug() << Q_FUNC_INFO << "No device set, just waiting 1 sec";
|
||||
_relativeUploadDelayTimer.setInterval(1000);
|
||||
_relativeUploadDelayTimer.start();
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
|
||||
|
||||
qint64 relativeLimitProgressMeasured = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
||||
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
|
||||
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeUploadLimitProgressAtMeasuringRestart;
|
||||
qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
|
||||
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
|
||||
|
||||
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
|
||||
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
|
||||
<< _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
|
||||
<< qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
||||
- _relativeLimitCurrentMeasuredDevice->_read) << ")";
|
||||
|
||||
qint64 uploadLimitPercent = -_currentUploadLimit;
|
||||
// don't use too extreme values
|
||||
uploadLimitPercent = qMin(uploadLimitPercent, qint64(90));
|
||||
uploadLimitPercent = qMax(qint64(10), uploadLimitPercent);
|
||||
qint64 wholeTimeMsec = (100.0 / uploadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
|
||||
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
|
||||
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
|
||||
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
|
||||
" msec for " << uploadLimitPercent << "%";
|
||||
qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
|
||||
|
||||
// We want to wait twice as long since we want to give all
|
||||
// devices the same quota we used now since we don't want
|
||||
// any upload to timeout
|
||||
_relativeUploadDelayTimer.setInterval(realWaitTimeMsec);
|
||||
_relativeUploadDelayTimer.start();
|
||||
|
||||
int deviceCount = _relativeUploadDeviceList.count();
|
||||
qint64 quotaPerDevice = relativeLimitProgressDifference * (uploadLimitPercent / 100.0) / deviceCount + 1.0;
|
||||
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
|
||||
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
|
||||
ud->setBandwidthLimited(true);
|
||||
ud->setChoked(false);
|
||||
ud->giveBandwidthQuota(quotaPerDevice);
|
||||
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
|
||||
}
|
||||
_relativeLimitCurrentMeasuredDevice = 0;
|
||||
}
|
||||
|
||||
void BandwidthManager::relativeUploadDelayTimerExpired()
|
||||
{
|
||||
// Switch to measuring state
|
||||
_relativeUploadMeasuringTimer.start(); // always start to continue the cycle
|
||||
|
||||
if (!usingRelativeUploadLimit()) {
|
||||
return; // oh, not actually needed
|
||||
}
|
||||
|
||||
if (_relativeUploadDeviceList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
|
||||
|
||||
// Take first device and then append it again (= we round robin all devices)
|
||||
_relativeLimitCurrentMeasuredDevice = _relativeUploadDeviceList.takeFirst();
|
||||
_relativeUploadDeviceList.append(_relativeLimitCurrentMeasuredDevice);
|
||||
|
||||
_relativeUploadLimitProgressAtMeasuringRestart = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
||||
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
|
||||
_relativeLimitCurrentMeasuredDevice->setBandwidthLimited(false);
|
||||
_relativeLimitCurrentMeasuredDevice->setChoked(false);
|
||||
|
||||
// choke all other UploadDevices
|
||||
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
|
||||
if (ud != _relativeLimitCurrentMeasuredDevice) {
|
||||
ud->setBandwidthLimited(true);
|
||||
ud->setChoked(true);
|
||||
}
|
||||
}
|
||||
|
||||
// now we're in measuring state
|
||||
}
|
||||
|
||||
// for downloads:
|
||||
void BandwidthManager::relativeDownloadMeasuringTimerExpired()
|
||||
{
|
||||
if (!usingRelativeDownloadLimit() || _downloadJobList.count() == 0) {
|
||||
// Not in this limiting mode, just wait 1 sec to continue the cycle
|
||||
_relativeDownloadDelayTimer.setInterval(1000);
|
||||
_relativeDownloadDelayTimer.start();
|
||||
return;
|
||||
}
|
||||
if (_relativeLimitCurrentMeasuredJob == 0) {
|
||||
qDebug() << Q_FUNC_INFO << "No job set, just waiting 1 sec";
|
||||
_relativeDownloadDelayTimer.setInterval(1000);
|
||||
_relativeDownloadDelayTimer.start();
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
|
||||
|
||||
qint64 relativeLimitProgressMeasured = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
|
||||
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeDownloadLimitProgressAtMeasuringRestart;
|
||||
qDebug() << Q_FUNC_INFO << _relativeDownloadLimitProgressAtMeasuringRestart
|
||||
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
|
||||
|
||||
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
|
||||
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
|
||||
<< _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
|
||||
|
||||
qint64 downloadLimitPercent = -_currentDownloadLimit;
|
||||
// don't use too extreme values
|
||||
downloadLimitPercent = qMin(downloadLimitPercent, qint64(90));
|
||||
downloadLimitPercent = qMax(qint64(10), downloadLimitPercent);
|
||||
qint64 wholeTimeMsec = (100.0 / downloadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
|
||||
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
|
||||
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
|
||||
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
|
||||
" msec for " << downloadLimitPercent << "%";
|
||||
qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
|
||||
|
||||
// We want to wait twice as long since we want to give all
|
||||
// devices the same quota we used now since we don't want
|
||||
// any upload to timeout
|
||||
_relativeDownloadDelayTimer.setInterval(realWaitTimeMsec);
|
||||
_relativeDownloadDelayTimer.start();
|
||||
|
||||
int jobCount = _downloadJobList.count();
|
||||
qint64 quota = relativeLimitProgressDifference * (downloadLimitPercent / 100.0);
|
||||
// if (quota > 20*1024) {
|
||||
// qDebug() << "======== ADJUSTING QUOTA FROM " << quota << " TO " << quota - 20*1024;
|
||||
// quota -= 20*1024;
|
||||
// }
|
||||
qint64 quotaPerJob = quota / jobCount + 1.0;
|
||||
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
|
||||
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
|
||||
gfj->setBandwidthLimited(true);
|
||||
gfj->setChoked(false);
|
||||
gfj->giveBandwidthQuota(quotaPerJob);
|
||||
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
|
||||
}
|
||||
_relativeLimitCurrentMeasuredDevice = 0;
|
||||
}
|
||||
|
||||
void BandwidthManager::relativeDownloadDelayTimerExpired()
|
||||
{
|
||||
// Switch to measuring state
|
||||
_relativeDownloadMeasuringTimer.start(); // always start to continue the cycle
|
||||
|
||||
if (!usingRelativeDownloadLimit()) {
|
||||
return; // oh, not actually needed
|
||||
}
|
||||
|
||||
if (_downloadJobList.isEmpty()) {
|
||||
//qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "No jobs?";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
|
||||
|
||||
// Take first device and then append it again (= we round robin all devices)
|
||||
_relativeLimitCurrentMeasuredJob = _downloadJobList.takeFirst();
|
||||
_downloadJobList.append(_relativeLimitCurrentMeasuredJob);
|
||||
|
||||
_relativeDownloadLimitProgressAtMeasuringRestart = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
|
||||
_relativeLimitCurrentMeasuredJob->setBandwidthLimited(false);
|
||||
_relativeLimitCurrentMeasuredJob->setChoked(false);
|
||||
|
||||
// choke all other UploadDevices
|
||||
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
|
||||
if (gfj != _relativeLimitCurrentMeasuredJob) {
|
||||
gfj->setBandwidthLimited(true);
|
||||
gfj->setChoked(true);
|
||||
}
|
||||
}
|
||||
|
||||
// now we're in measuring state
|
||||
}
|
||||
|
||||
// end downloads
|
||||
|
||||
void BandwidthManager::switchingTimerExpired() {
|
||||
qint64 newUploadLimit = _propagator->_uploadLimit.fetchAndAddAcquire(0);
|
||||
if (newUploadLimit != _currentUploadLimit) {
|
||||
qDebug() << Q_FUNC_INFO << "Upload Bandwidth limit changed" << _currentUploadLimit << newUploadLimit;
|
||||
_currentUploadLimit = newUploadLimit;
|
||||
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
|
||||
if (newUploadLimit == 0) {
|
||||
ud->setBandwidthLimited(false);
|
||||
ud->setChoked(false);
|
||||
} else if (newUploadLimit > 0) {
|
||||
ud->setBandwidthLimited(true);
|
||||
ud->setChoked(false);
|
||||
} else if (newUploadLimit < 0) {
|
||||
ud->setBandwidthLimited(true);
|
||||
ud->setChoked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
qint64 newDownloadLimit = _propagator->_downloadLimit.fetchAndAddAcquire(0);
|
||||
if (newDownloadLimit != _currentDownloadLimit) {
|
||||
qDebug() << Q_FUNC_INFO << "Download Bandwidth limit changed" << _currentDownloadLimit << newDownloadLimit;
|
||||
_currentDownloadLimit = newDownloadLimit;
|
||||
Q_FOREACH(GETFileJob *j, _downloadJobList) {
|
||||
if (usingAbsoluteDownloadLimit()) {
|
||||
j->setBandwidthLimited(true);
|
||||
j->setChoked(false);
|
||||
} else if (usingRelativeDownloadLimit()) {
|
||||
j->setBandwidthLimited(true);
|
||||
j->setChoked(true);
|
||||
} else {
|
||||
j->setBandwidthLimited(false);
|
||||
j->setChoked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthManager::absoluteLimitTimerExpired()
|
||||
{
|
||||
if (usingAbsoluteUploadLimit() && _absoluteUploadDeviceList.count() > 0) {
|
||||
qint64 quotaPerDevice = _currentUploadLimit / qMax(1, _absoluteUploadDeviceList.count());
|
||||
qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
|
||||
Q_FOREACH(UploadDevice *device, _absoluteUploadDeviceList) {
|
||||
device->giveBandwidthQuota(quotaPerDevice);
|
||||
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
|
||||
}
|
||||
}
|
||||
if (usingAbsoluteDownloadLimit() && _downloadJobList.count() > 0) {
|
||||
qint64 quotaPerJob = _currentDownloadLimit / qMax(1, _downloadJobList.count());
|
||||
qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
|
||||
Q_FOREACH(GETFileJob *j, _downloadJobList) {
|
||||
j->giveBandwidthQuota(quotaPerJob);
|
||||
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) by Markus Goetz <markus@woboq.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef BANDWIDTHMANAGER_H
|
||||
#define BANDWIDTHMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLinkedList>
|
||||
#include <QTimer>
|
||||
#include <QIODevice>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
class UploadDevice;
|
||||
class GETFileJob;
|
||||
class OwncloudPropagator;
|
||||
|
||||
class BandwidthManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
BandwidthManager(OwncloudPropagator *p);
|
||||
|
||||
bool usingAbsoluteUploadLimit() { return _currentUploadLimit > 0; }
|
||||
bool usingRelativeUploadLimit() { return _currentUploadLimit < 0; }
|
||||
bool usingAbsoluteDownloadLimit() { return _currentDownloadLimit > 0; }
|
||||
bool usingRelativeDownloadLimit() { return _currentDownloadLimit < 0; }
|
||||
|
||||
|
||||
public slots:
|
||||
void registerUploadDevice(UploadDevice*);
|
||||
void unregisterUploadDevice(UploadDevice*);
|
||||
void unregisterUploadDevice(QObject*);
|
||||
|
||||
void registerDownloadJob(GETFileJob*);
|
||||
void unregisterDownloadJob(GETFileJob*);
|
||||
void unregisterDownloadJob(QObject*);
|
||||
|
||||
void absoluteLimitTimerExpired();
|
||||
void switchingTimerExpired();
|
||||
|
||||
void relativeUploadMeasuringTimerExpired();
|
||||
void relativeUploadDelayTimerExpired();
|
||||
|
||||
void relativeDownloadMeasuringTimerExpired();
|
||||
void relativeDownloadDelayTimerExpired();
|
||||
|
||||
private:
|
||||
QTimer _switchingTimer; // for switching between absolute and relative bw limiting
|
||||
OwncloudPropagator *_propagator; // FIXME this timer and this variable should be replaced
|
||||
// by the propagator emitting the changed limit values to us as signal
|
||||
|
||||
QTimer _absoluteLimitTimer; // for absolute up/down bw limiting
|
||||
|
||||
QLinkedList<UploadDevice*> _absoluteUploadDeviceList;
|
||||
QLinkedList<UploadDevice*> _relativeUploadDeviceList; // FIXME merge with list above ^^
|
||||
QTimer _relativeUploadMeasuringTimer;
|
||||
QTimer _relativeUploadDelayTimer; // for relative bw limiting, we need to wait this amount before measuring again
|
||||
UploadDevice *_relativeLimitCurrentMeasuredDevice; // the device measured
|
||||
qint64 _relativeUploadLimitProgressAtMeasuringRestart; // for measuring how much progress we made at start
|
||||
qint64 _currentUploadLimit;
|
||||
|
||||
QLinkedList<GETFileJob*> _downloadJobList;
|
||||
QTimer _relativeDownloadMeasuringTimer;
|
||||
QTimer _relativeDownloadDelayTimer; // for relative bw limiting, we need to wait this amount before measuring again
|
||||
GETFileJob *_relativeLimitCurrentMeasuredJob; // the device measured
|
||||
qint64 _relativeDownloadLimitProgressAtMeasuringRestart; // for measuring how much progress we made at start
|
||||
qint64 _currentDownloadLimit;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,10 +12,7 @@
|
||||
*/
|
||||
|
||||
#include "filesystem.h"
|
||||
|
||||
#include "utility.h"
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
@@ -27,16 +24,11 @@
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
|
||||
// We use some internals of csync:
|
||||
extern "C" int c_utimes(const char *, const struct timeval *);
|
||||
extern "C" void csync_win32_set_file_hidden( const char *file, bool h );
|
||||
|
||||
extern "C" {
|
||||
#include "vio/csync_vio_handle.h"
|
||||
#include "vio/csync_vio_file_stat.h"
|
||||
#include "vio/csync_vio_local.h"
|
||||
}
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
bool FileSystem::fileEquals(const QString& fn1, const QString& fn2)
|
||||
@@ -77,25 +69,6 @@ void FileSystem::setFileHidden(const QString& filename, bool hidden)
|
||||
return csync_win32_set_file_hidden(filename.toUtf8().constData(), hidden);
|
||||
}
|
||||
|
||||
time_t FileSystem::getModTime(const QString &filename)
|
||||
{
|
||||
csync_vio_file_stat_t* stat = csync_vio_file_stat_new();
|
||||
qint64 result = -1;
|
||||
if (csync_vio_local_stat(filename.toUtf8().data(), stat) != -1
|
||||
&& (stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_MTIME))
|
||||
{
|
||||
result = stat->mtime;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Could not get modification time for" << filename
|
||||
<< "with csync, using QFileInfo";
|
||||
result = Utility::qDateTimeToTime_t(QFileInfo(filename).lastModified());
|
||||
}
|
||||
csync_vio_file_stat_destroy(stat);
|
||||
return result;
|
||||
}
|
||||
|
||||
void FileSystem::setModTime(const QString& filename, time_t modTime)
|
||||
{
|
||||
struct timeval times[2];
|
||||
|
||||
@@ -30,14 +30,6 @@ bool fileEquals(const QString &fn1, const QString &fn2);
|
||||
/** Mark the file as hidden (only has effects on windows) */
|
||||
void setFileHidden(const QString& filename, bool hidden);
|
||||
|
||||
|
||||
/** Get the mtime for a filepath.
|
||||
*
|
||||
* Use this over QFileInfo::lastModified() to avoid timezone related bugs. See
|
||||
* owncloud/core#9781 for details.
|
||||
*/
|
||||
time_t getModTime(const QString &filename);
|
||||
|
||||
void setModTime(const QString &filename, time_t modTime);
|
||||
|
||||
/**
|
||||
|
||||
+88
-22
@@ -27,7 +27,6 @@
|
||||
#include "mirall/clientproxy.h"
|
||||
#include "mirall/syncengine.h"
|
||||
#include "mirall/syncrunfilelog.h"
|
||||
#include "mirall/filesystem.h"
|
||||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
@@ -123,9 +122,7 @@ bool Folder::init()
|
||||
csync_set_log_level( 11 );
|
||||
|
||||
MirallConfigFile cfgFile;
|
||||
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
|
||||
|
||||
setIgnoredFiles();
|
||||
if (Account *account = AccountManager::instance()->account()) {
|
||||
account->credentials()->syncContextPreInit(_csync_ctx);
|
||||
} else {
|
||||
@@ -269,6 +266,7 @@ void Folder::slotPollTimerTimeout()
|
||||
qDebug() << "* Polling" << alias() << "for changes. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
|
||||
|
||||
if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval() ||
|
||||
_lastEtag.isNull() ||
|
||||
!(_syncResult.status() == SyncResult::Success ||_syncResult.status() == SyncResult::Problem)) {
|
||||
qDebug() << "** Force Sync now, state is " << _syncResult.statusString();
|
||||
emit scheduleToSync(alias());
|
||||
@@ -607,6 +605,8 @@ void Folder::startSync(const QStringList &pathList)
|
||||
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)));
|
||||
connect(_engine.data(), SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
|
||||
|
||||
setDirtyNetworkLimits();
|
||||
|
||||
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
||||
|
||||
// disable events until syncing is done
|
||||
@@ -618,7 +618,21 @@ void Folder::startSync(const QStringList &pathList)
|
||||
void Folder::setDirtyNetworkLimits()
|
||||
{
|
||||
if (_engine) {
|
||||
_engine->setNetworkLimits();
|
||||
|
||||
MirallConfigFile cfg;
|
||||
int downloadLimit = 0;
|
||||
if (cfg.useDownloadLimit()) {
|
||||
downloadLimit = cfg.downloadLimit() * 1000;
|
||||
}
|
||||
int uploadLimit = -75; // 75%
|
||||
int useUpLimit = cfg.useUploadLimit();
|
||||
if ( useUpLimit >= 1) {
|
||||
uploadLimit = cfg.uploadLimit() * 1000;
|
||||
} else if (useUpLimit == 0) {
|
||||
uploadLimit = 0;
|
||||
}
|
||||
|
||||
_engine->setNetworkLimits(uploadLimit, downloadLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,10 +660,13 @@ void Folder::slotSyncFinished()
|
||||
|
||||
bubbleUpSyncResult();
|
||||
|
||||
_engine.reset(0);
|
||||
bool anotherSyncNeeded = false;
|
||||
if (_engine) {
|
||||
anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
_engine.reset(0);
|
||||
}
|
||||
// _watcher->setEventsEnabledDelayed(2000);
|
||||
_pollTimer.start();
|
||||
_timeSinceLastSync.restart();
|
||||
|
||||
|
||||
|
||||
if (_csyncError) {
|
||||
@@ -676,6 +693,16 @@ void Folder::slotSyncFinished()
|
||||
// all come in.
|
||||
QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() ));
|
||||
|
||||
if (!anotherSyncNeeded) {
|
||||
_pollTimer.start();
|
||||
_timeSinceLastSync.restart();
|
||||
} else {
|
||||
// Another sync is required. We will make sure that the poll timer occurs soon enough
|
||||
// and we clear the etag to force a sync
|
||||
_lastEtag.clear();
|
||||
QTimer::singleShot(1000, this, SLOT(slotPollTimerTimeout() ));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Folder::slotEmitFinishedDelayed()
|
||||
@@ -728,6 +755,38 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *
|
||||
#endif
|
||||
}
|
||||
|
||||
// compute the file status of a directory recursively. It returns either
|
||||
// "all in sync" or "needs update" or "error", no more details.
|
||||
SyncFileStatus Folder::recursiveFolderStatus( const QString& fileName )
|
||||
{
|
||||
QDir dir(path() + fileName);
|
||||
|
||||
const QStringList dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
|
||||
|
||||
foreach( const QString entry, dirEntries ) {
|
||||
QFileInfo fi(entry);
|
||||
SyncFileStatus sfs;
|
||||
if( fi.isDir() ) {
|
||||
sfs = recursiveFolderStatus( fileName + QLatin1Char('/') + entry );
|
||||
} else {
|
||||
QString fs( fileName + QLatin1Char('/') + entry );
|
||||
if( fileName.isEmpty() ) {
|
||||
// toplevel, no slash etc. needed.
|
||||
fs = entry;
|
||||
}
|
||||
sfs = fileStatus( fs );
|
||||
}
|
||||
|
||||
if( sfs == FILE_STATUS_STAT_ERROR || sfs == FILE_STATUS_ERROR ) {
|
||||
return FILE_STATUS_ERROR;
|
||||
}
|
||||
if( sfs != FILE_STATUS_SYNC) {
|
||||
return FILE_STATUS_EVAL;
|
||||
}
|
||||
}
|
||||
return FILE_STATUS_SYNC;
|
||||
}
|
||||
|
||||
SyncFileStatus Folder::fileStatus( const QString& fileName )
|
||||
{
|
||||
/*
|
||||
@@ -747,7 +806,11 @@ SyncFileStatus Folder::fileStatus( const QString& fileName )
|
||||
// FIXME: Find a way for STATUS_ERROR
|
||||
SyncFileStatus stat = FILE_STATUS_NONE;
|
||||
|
||||
QString file = path() + fileName;
|
||||
QString file = fileName;
|
||||
if( path() != QLatin1String("/") ) {
|
||||
file = path() + fileName;
|
||||
}
|
||||
|
||||
QFileInfo fi(file);
|
||||
|
||||
if( !fi.exists() ) {
|
||||
@@ -771,22 +834,25 @@ SyncFileStatus Folder::fileStatus( const QString& fileName )
|
||||
}
|
||||
}
|
||||
|
||||
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
|
||||
if( stat == FILE_STATUS_NONE && !rec.isValid() ) {
|
||||
stat = FILE_STATUS_NEW;
|
||||
}
|
||||
if( type == CSYNC_FTW_TYPE_DIR ) {
|
||||
// compute recursive status of the directory
|
||||
stat = recursiveFolderStatus( fileName );
|
||||
} else {
|
||||
if( stat == FILE_STATUS_NONE ) {
|
||||
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
|
||||
if( !rec.isValid() ) {
|
||||
stat = FILE_STATUS_NEW;
|
||||
}
|
||||
|
||||
// file was locally modified.
|
||||
if( stat == FILE_STATUS_NONE &&
|
||||
FileSystem::getModTime(fi.absoluteFilePath())
|
||||
!= Utility::qDateTimeToTime_t(rec._modtime) ) {
|
||||
stat = FILE_STATUS_EVAL;
|
||||
// file was locally modified.
|
||||
if( stat == FILE_STATUS_NONE && fi.lastModified() != rec._modtime ) {
|
||||
stat = FILE_STATUS_EVAL;
|
||||
}
|
||||
}
|
||||
if( stat == FILE_STATUS_NONE ) {
|
||||
stat = FILE_STATUS_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
if( stat == FILE_STATUS_NONE ) {
|
||||
stat = FILE_STATUS_SYNC;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -76,6 +76,17 @@ public:
|
||||
*/
|
||||
SyncFileStatus fileStatus( const QString& );
|
||||
|
||||
/**
|
||||
* @brief recursiveFolderStatus
|
||||
* @param fileName - the relative file name to examine
|
||||
* @return the resulting status
|
||||
*
|
||||
* The resulting status can only be either SYNC which means all files
|
||||
* are in sync, ERROR if an error occured, or EVAL if something needs
|
||||
* to be synced underneath this dir.
|
||||
*/
|
||||
SyncFileStatus recursiveFolderStatus( const QString& fileName );
|
||||
|
||||
/**
|
||||
* alias or nickname
|
||||
*/
|
||||
@@ -186,7 +197,6 @@ private slots:
|
||||
private:
|
||||
bool init();
|
||||
|
||||
|
||||
void setIgnoredFiles();
|
||||
|
||||
void bubbleUpSyncResult();
|
||||
|
||||
+13
-39
@@ -13,13 +13,10 @@
|
||||
*/
|
||||
|
||||
#include "mirall/folderman.h"
|
||||
#include "mirall/account.h"
|
||||
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/folder.h"
|
||||
#include "mirall/syncresult.h"
|
||||
#include "mirall/theme.h"
|
||||
#include "mirall/accountmigrator.h"
|
||||
|
||||
#include <neon/ne_socket.h>
|
||||
|
||||
@@ -150,15 +147,6 @@ int FolderMan::setupFolders()
|
||||
dir.setFilter(QDir::Files | QDir::Hidden);
|
||||
QStringList list = dir.entryList();
|
||||
|
||||
if( list.count() == 0 ) {
|
||||
// maybe the account was just migrated.
|
||||
Account *acc = AccountManager::instance()->account();
|
||||
if ( acc && acc->wasMigrated() ) {
|
||||
AccountMigrator accMig;
|
||||
list = accMig.migrateFolderDefinitons();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( const QString& alias, list ) {
|
||||
Folder *f = setupFolderFromConfigFile( alias );
|
||||
if( f ) {
|
||||
@@ -600,41 +588,27 @@ QString FolderMan::getBackupName( const QString& fullPathName ) const
|
||||
|
||||
bool FolderMan::startFromScratch( const QString& localFolder )
|
||||
{
|
||||
if( localFolder.isEmpty() ) {
|
||||
return false;
|
||||
}
|
||||
if( localFolder.isEmpty() ) return false;
|
||||
|
||||
QFileInfo fi( localFolder );
|
||||
QDir parentDir( fi.dir() );
|
||||
QString folderName = fi.fileName();
|
||||
if( fi.exists() && fi.isDir() ) {
|
||||
QDir file = fi.dir();
|
||||
|
||||
// Adjust for case where localFolder ends with a /
|
||||
if ( fi.isDir() ) {
|
||||
folderName = parentDir.dirName();
|
||||
parentDir.cdUp();
|
||||
}
|
||||
|
||||
if( fi.exists() ) {
|
||||
// It exists, but is empty -> just reuse it.
|
||||
if( fi.isDir() && fi.dir().count() == 0 ) {
|
||||
// check if there are files in the directory.
|
||||
if( file.count() == 0 ) {
|
||||
// directory is existing, but its empty. Use it.
|
||||
qDebug() << "startFromScratch: Directory is empty!";
|
||||
return true;
|
||||
}
|
||||
// Make a backup of the folder/file.
|
||||
QString newName = getBackupName( parentDir.absoluteFilePath( folderName ) );
|
||||
if( !parentDir.rename( fi.absoluteFilePath(), newName ) ) {
|
||||
qDebug() << "startFromScratch: Could not rename" << fi.absoluteFilePath()
|
||||
<< "to" << newName;
|
||||
return false;
|
||||
QString newName = getBackupName( fi.absoluteFilePath() );
|
||||
|
||||
if( file.rename( fi.absoluteFilePath(), newName )) {
|
||||
if( file.mkdir( fi.absoluteFilePath() ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !parentDir.mkdir( fi.absoluteFilePath() ) ) {
|
||||
qDebug() << "startFromScratch: Could not mkdir" << fi.absoluteFilePath();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void FolderMan::setDirtyProxy(bool value)
|
||||
|
||||
@@ -83,8 +83,6 @@ public:
|
||||
void removeMonitorPath( const QString& alias, const QString& path );
|
||||
void addMonitorPath( const QString& alias, const QString& path );
|
||||
|
||||
QString escapeAlias( const QString& ) const;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* signal to indicate a folder named by alias has changed its sync state.
|
||||
@@ -132,6 +130,7 @@ private:
|
||||
|
||||
// Escaping of the alias which is used in QSettings AND the file
|
||||
// system, thus need to be escaped.
|
||||
QString escapeAlias( const QString& ) const;
|
||||
QString unescapeAlias( const QString& ) const;
|
||||
|
||||
void removeFolder( const QString& );
|
||||
|
||||
@@ -12,16 +12,15 @@
|
||||
*/
|
||||
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkProxy>
|
||||
#include <QAuthenticator>
|
||||
#include <QSslConfiguration>
|
||||
#include <QNetworkCookie>
|
||||
#include <QNetworkCookieJar>
|
||||
|
||||
#include "mirall/cookiejar.h"
|
||||
#include "mirall/mirallaccessmanager.h"
|
||||
#include "mirall/utility.h"
|
||||
#include "mirall/authenticationdialog.h"
|
||||
|
||||
|
||||
namespace Mirall
|
||||
{
|
||||
@@ -36,16 +35,31 @@ MirallAccessManager::MirallAccessManager(QObject* parent)
|
||||
setProxy(proxy);
|
||||
#endif
|
||||
setCookieJar(new CookieJar);
|
||||
connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
|
||||
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
|
||||
connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
|
||||
this, SLOT(slotAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
|
||||
QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
|
||||
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
|
||||
}
|
||||
|
||||
void MirallAccessManager::setRawCookie(const QByteArray &rawCookie, const QUrl &url)
|
||||
{
|
||||
QNetworkCookie cookie(rawCookie.left(rawCookie.indexOf('=')),
|
||||
rawCookie.mid(rawCookie.indexOf('=')+1));
|
||||
qDebug() << Q_FUNC_INFO << cookie.name() << cookie.value();
|
||||
QList<QNetworkCookie> cookieList;
|
||||
cookieList.append(cookie);
|
||||
|
||||
QNetworkCookieJar *jar = cookieJar();
|
||||
jar->setCookiesFromUrl(cookieList, url);
|
||||
}
|
||||
|
||||
QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
|
||||
{
|
||||
QNetworkRequest newRequest(request);
|
||||
|
||||
if (newRequest.hasRawHeader("cookie")) {
|
||||
// This will set the cookie into the QNetworkCookieJar which will then override the cookie header
|
||||
setRawCookie(request.rawHeader("cookie"), request.url());
|
||||
}
|
||||
|
||||
newRequest.setRawHeader(QByteArray("User-Agent"), Utility::userAgentString());
|
||||
QByteArray verb = newRequest.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
|
||||
// For PROPFIND (assumed to be a WebDAV op), set xml/utf8 as content type/encoding
|
||||
@@ -66,27 +80,5 @@ void MirallAccessManager::slotProxyAuthenticationRequired(const QNetworkProxy &p
|
||||
authenticator->setPassword(proxy.password());
|
||||
}
|
||||
}
|
||||
void MirallAccessManager::slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
|
||||
{
|
||||
// do not handle 401 created by the networkjobs. We may want
|
||||
// to eventually exempt some, but for now we need
|
||||
// it only for other things, e.g. the browser. Would we handle
|
||||
// network jobs, this would break the wizard logic
|
||||
if (reply->property("doNotHandleAuth").toBool()) {
|
||||
return;
|
||||
}
|
||||
QUrl url = reply->url();
|
||||
// show only scheme, host and port
|
||||
QUrl reducedUrl;
|
||||
reducedUrl.setScheme(url.scheme());
|
||||
reducedUrl.setHost(url.host());
|
||||
reducedUrl.setPort(url.port());
|
||||
|
||||
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString());
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
authenticator->setUser(dialog.user());
|
||||
authenticator->setPassword(dialog.password());
|
||||
}
|
||||
}
|
||||
|
||||
} // ns Mirall
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "owncloudlib.h"
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class QByteArray;
|
||||
class QUrl;
|
||||
namespace Mirall
|
||||
{
|
||||
|
||||
@@ -27,12 +29,12 @@ class OWNCLOUDSYNC_EXPORT MirallAccessManager : public QNetworkAccessManager
|
||||
public:
|
||||
MirallAccessManager(QObject* parent = 0);
|
||||
|
||||
void setRawCookie(const QByteArray &rawCookie, const QUrl &url);
|
||||
|
||||
protected:
|
||||
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
|
||||
protected slots:
|
||||
void slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
|
||||
void slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
|
||||
|
||||
};
|
||||
|
||||
} // ns Mirall
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "mirall/networkjobs.h"
|
||||
#include "mirall/account.h"
|
||||
#include "mirall/owncloudpropagator.h"
|
||||
|
||||
#include "creds/credentialsfactory.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
@@ -48,17 +49,8 @@ AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QO
|
||||
, _path(path)
|
||||
{
|
||||
_timer.setSingleShot(true);
|
||||
_timer.setInterval(10*1000); // default to 10 seconds.
|
||||
_timer.setInterval(OwncloudPropagator::httpTimeout() * 1000); // default to 5 minutes.
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
|
||||
|
||||
connect(this, SIGNAL(networkActivity()), SLOT(resetTimeout()));
|
||||
|
||||
// Network activity on the propagator jobs (GET/PUT) keeps all requests alive.
|
||||
// This is a workaround for OC instances which only support one
|
||||
// parallel up and download
|
||||
if (_account) {
|
||||
connect(_account, SIGNAL(propagatorNetworkActivity()), SLOT(resetTimeout()));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
||||
@@ -66,7 +58,6 @@ void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
||||
if (_reply) {
|
||||
_reply->deleteLater();
|
||||
}
|
||||
reply->setProperty("doNotHandleAuth", true);
|
||||
_reply = reply;
|
||||
}
|
||||
|
||||
@@ -89,6 +80,11 @@ void AbstractNetworkJob::setIgnoreCredentialFailure(bool ignore)
|
||||
_ignoreCredentialFailure = ignore;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setAccount(Account *account)
|
||||
{
|
||||
_account = account;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setPath(const QString &path)
|
||||
{
|
||||
_path = path;
|
||||
@@ -97,8 +93,6 @@ void AbstractNetworkJob::setPath(const QString &path)
|
||||
void AbstractNetworkJob::setupConnections(QNetworkReply *reply)
|
||||
{
|
||||
connect(reply, SIGNAL(finished()), SLOT(slotFinished()));
|
||||
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SIGNAL(networkActivity()));
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::addTimer(QNetworkReply *reply)
|
||||
@@ -185,11 +179,8 @@ QString AbstractNetworkJob::responseTimestamp()
|
||||
return _responseTimestamp;
|
||||
}
|
||||
|
||||
AbstractNetworkJob::~AbstractNetworkJob()
|
||||
{
|
||||
if (_reply) {
|
||||
_reply->deleteLater();
|
||||
}
|
||||
AbstractNetworkJob::~AbstractNetworkJob() {
|
||||
_reply->deleteLater();
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::start()
|
||||
|
||||
@@ -55,14 +55,15 @@ public:
|
||||
|
||||
virtual void start();
|
||||
|
||||
void setAccount(Account *account);
|
||||
Account* account() const { return _account; }
|
||||
|
||||
void setPath(const QString &path);
|
||||
QString path() const { return _path; }
|
||||
|
||||
void setReply(QNetworkReply *reply);
|
||||
QNetworkReply* reply() const { return _reply; }
|
||||
|
||||
|
||||
void setIgnoreCredentialFailure(bool ignore);
|
||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
|
||||
@@ -74,7 +75,6 @@ public slots:
|
||||
void resetTimeout();
|
||||
signals:
|
||||
void networkError(QNetworkReply *reply);
|
||||
void networkActivity();
|
||||
protected:
|
||||
void setupConnections(QNetworkReply *reply);
|
||||
QNetworkReply* davRequest(const QByteArray& verb, const QString &relPath,
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "mirall/owncloudsetupwizard.h"
|
||||
#if defined(Q_OS_MAC)
|
||||
# include "mirall/settingsdialogmac.h"
|
||||
# include "macwindow.h" // qtmacgoodies
|
||||
#else
|
||||
# include "mirall/settingsdialog.h"
|
||||
#endif
|
||||
@@ -34,10 +33,6 @@
|
||||
#include <QMessageBox>
|
||||
#include <QSignalMapper>
|
||||
|
||||
#if defined(Q_OS_X11)
|
||||
#include <QX11Info>
|
||||
#endif
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
ownCloudGui::ownCloudGui(Application *parent) :
|
||||
@@ -116,14 +111,6 @@ void ownCloudGui::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
|
||||
if( reason == QSystemTrayIcon::Trigger ) {
|
||||
slotOpenSettingsDialog(true); // start settings if config is existing.
|
||||
}
|
||||
#else
|
||||
// On Mac, if the settings dialog is already visible but hidden
|
||||
// by other applications, this will bring it to the front.
|
||||
if( reason == QSystemTrayIcon::Trigger ) {
|
||||
if (!_settingsDialog.isNull() && _settingsDialog->isVisible()) {
|
||||
slotShowSettings();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -488,7 +475,7 @@ void ownCloudGui::slotShowSettings()
|
||||
_settingsDialog->show();
|
||||
}
|
||||
_settingsDialog->setGeneralErrors( _startupFails );
|
||||
ownCloudGui::raiseDialog(_settingsDialog.data());
|
||||
Utility::raiseDialog(_settingsDialog.data());
|
||||
}
|
||||
|
||||
void ownCloudGui::slotShowSyncProtocol()
|
||||
@@ -516,7 +503,7 @@ void ownCloudGui::slotToggleLogBrowser()
|
||||
if (_logBrowser->isVisible() ) {
|
||||
_logBrowser->hide();
|
||||
} else {
|
||||
ownCloudGui::raiseDialog(_logBrowser);
|
||||
Utility::raiseDialog(_logBrowser);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,42 +519,5 @@ void ownCloudGui::slotHelp()
|
||||
QDesktopServices::openUrl(QUrl(Theme::instance()->helpUrl()));
|
||||
}
|
||||
|
||||
void ownCloudGui::raiseDialog( QWidget *raiseWidget )
|
||||
{
|
||||
if( raiseWidget && raiseWidget->parentWidget() == 0) {
|
||||
// Qt has a bug which causes parent-less dialogs to pop-under.
|
||||
raiseWidget->showNormal();
|
||||
raiseWidget->raise();
|
||||
raiseWidget->activateWindow();
|
||||
}
|
||||
#if defined(Q_OS_MAC)
|
||||
// viel hilft viel ;-)
|
||||
MacWindow::bringToFront(raiseWidget);
|
||||
#endif
|
||||
#if defined(Q_OS_X11)
|
||||
WId wid = widget->winId();
|
||||
NETWM::init();
|
||||
|
||||
XEvent e;
|
||||
e.xclient.type = ClientMessage;
|
||||
e.xclient.message_type = NETWM::NET_ACTIVE_WINDOW;
|
||||
e.xclient.display = QX11Info::display();
|
||||
e.xclient.window = wid;
|
||||
e.xclient.format = 32;
|
||||
e.xclient.data.l[0] = 2;
|
||||
e.xclient.data.l[1] = QX11Info::appTime();
|
||||
e.xclient.data.l[2] = 0;
|
||||
e.xclient.data.l[3] = 0l;
|
||||
e.xclient.data.l[4] = 0l;
|
||||
|
||||
Display *display = QX11Info::display();
|
||||
XSendEvent(display,
|
||||
RootWindow(display, DefaultScreen(display)),
|
||||
False, // propagate
|
||||
SubstructureRedirectMask|SubstructureNotifyMask,
|
||||
&e);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário