mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2025-04-09 19:15:43 +02:00
Add iconv support to convert charsets to different platforms.
This commit is contained in:
parent
13bb5ca2c3
commit
9c0c693081
CMakeLists.txtDefineOptions.cmake
client
cmake/Modules
config.h.cmakesrc
tests
@ -39,6 +39,7 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
|
||||
include(MacroAddPlugin)
|
||||
include(MacroCopyFile)
|
||||
|
||||
find_package(Iconv)
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND AND UNIT_TESTING)
|
||||
include(AddCMockaTest)
|
||||
|
@ -1,2 +1,5 @@
|
||||
if ( NOT WIN32 )
|
||||
option(WITH_ICONV "Build csync with iconv support" ON)
|
||||
endif()
|
||||
option(UNIT_TESTING "Build with unit tests" OFF)
|
||||
option(MEM_NULL_TESTS "Enable NULL memory testing" OFF)
|
||||
|
@ -53,8 +53,11 @@ at LOCAL with the ones at REMOTE.\n\
|
||||
--disable-statedb Disable the usage and creation of a statedb.\n\
|
||||
--dry-run This runs only update detection and reconcilation.\n\
|
||||
\n\
|
||||
--exclude-file=<file> Add an additional exclude file\n\
|
||||
--test-statedb Test creation of the statedb. Runs update\n\
|
||||
--exclude-file=<file> Add an additional exclude file\n"
|
||||
#ifdef WITH_ICONV
|
||||
" --iconv=codec Request charset conversion of local filenames\n"
|
||||
#endif
|
||||
" --test-statedb Test creation of the statedb. Runs update\n\
|
||||
detection.\n\
|
||||
--test-update Test the update detection\n\
|
||||
-?, --help Give this help list\n\
|
||||
@ -68,6 +71,9 @@ static const struct option long_options[] =
|
||||
{"exclude-file", required_argument, 0, 0 },
|
||||
{"debug-level", required_argument, 0, 'd' },
|
||||
{"disable-statedb", no_argument, 0, 0 },
|
||||
#ifdef WITH_ICONV
|
||||
{"iconv", required_argument, 0, 0 },
|
||||
#endif
|
||||
{"dry-run", no_argument, 0, 0 },
|
||||
{"test-statedb", no_argument, 0, 0 },
|
||||
{"conflict-copies", no_argument, 0, 'c' },
|
||||
@ -82,6 +88,7 @@ struct argument_s {
|
||||
char *args[2]; /* SOURCE and DESTINATION */
|
||||
char *exclude_file;
|
||||
int debug_level;
|
||||
char *iconv;
|
||||
int disable_statedb;
|
||||
int create_statedb;
|
||||
int update;
|
||||
@ -149,7 +156,9 @@ static int parse_args(struct argument_s *csync_args, int argc, char **argv)
|
||||
csync_args->reconcile = 1;
|
||||
csync_args->propagate = 0;
|
||||
/* printf("Argument: dry-run\n" ); */
|
||||
|
||||
} else if(c_streq(opt->name, "iconv")) {
|
||||
csync_args->iconv = c_strdup(optarg);
|
||||
/* printf("Argument: iconv\n" ); */
|
||||
} else if(c_streq(opt->name, "test-statedb")) {
|
||||
csync_args->create_statedb = 1;
|
||||
csync_args->update = 1;
|
||||
@ -158,7 +167,6 @@ static int parse_args(struct argument_s *csync_args, int argc, char **argv)
|
||||
/* printf("Argument: test-statedb\n"); */
|
||||
} else {
|
||||
fprintf(stderr, "Argument: No idea what!\n");
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -181,6 +189,7 @@ int main(int argc, char **argv) {
|
||||
/* Default values. */
|
||||
arguments.exclude_file = NULL;
|
||||
arguments.debug_level = 4;
|
||||
arguments.iconv = NULL;
|
||||
arguments.disable_statedb = 0;
|
||||
arguments.create_statedb = 0;
|
||||
arguments.update = 1;
|
||||
@ -227,6 +236,12 @@ int main(int argc, char **argv) {
|
||||
csync_disable_statedb(csync);
|
||||
}
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
if (arguments.iconv) {
|
||||
csync_set_iconv_codec(arguments.iconv);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(arguments.with_conflict_copys)
|
||||
{
|
||||
csync_enable_conflictcopys(csync);
|
||||
|
80
cmake/Modules/FindIconv.cmake
Normal file
80
cmake/Modules/FindIconv.cmake
Normal file
@ -0,0 +1,80 @@
|
||||
# - Try to find Iconv
|
||||
# Once done this will define
|
||||
#
|
||||
# ICONV_FOUND - system has Iconv
|
||||
# ICONV_INCLUDE_DIR - the Iconv include directory
|
||||
# ICONV_LIBRARIES - Link these to use Iconv
|
||||
# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
|
||||
#
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
|
||||
# Already in cache, be silent
|
||||
SET(ICONV_FIND_QUIETLY TRUE)
|
||||
ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
|
||||
|
||||
IF(APPLE)
|
||||
FIND_PATH(ICONV_INCLUDE_DIR iconv.h
|
||||
PATHS
|
||||
/opt/local/include/
|
||||
NO_CMAKE_SYSTEM_PATH
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c
|
||||
PATHS
|
||||
/opt/local/lib/
|
||||
NO_CMAKE_SYSTEM_PATH
|
||||
)
|
||||
ENDIF(APPLE)
|
||||
|
||||
FIND_PATH(ICONV_INCLUDE_DIR iconv.h PATHS /opt/local/include /sw/include)
|
||||
|
||||
string(REGEX REPLACE "(.*)/include/?" "\\1" ICONV_INCLUDE_BASE_DIR "${ICONV_INCLUDE_DIR}")
|
||||
|
||||
FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c HINTS "${ICONV_INCLUDE_BASE_DIR}/lib" PATHS /opt/local/lib)
|
||||
|
||||
IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
|
||||
SET(ICONV_FOUND TRUE)
|
||||
ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
|
||||
IF(ICONV_FOUND)
|
||||
check_c_compiler_flag("-Werror" ICONV_HAVE_WERROR)
|
||||
set (CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}")
|
||||
if(ICONV_HAVE_WERROR)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
endif(ICONV_HAVE_WERROR)
|
||||
check_c_source_compiles("
|
||||
#include <iconv.h>
|
||||
int main(){
|
||||
iconv_t conv = 0;
|
||||
const char* in = 0;
|
||||
size_t ilen = 0;
|
||||
char* out = 0;
|
||||
size_t olen = 0;
|
||||
iconv(conv, &in, &ilen, &out, &olen);
|
||||
return 0;
|
||||
}
|
||||
" ICONV_SECOND_ARGUMENT_IS_CONST )
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}")
|
||||
ENDIF(ICONV_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES)
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
IF(ICONV_FOUND)
|
||||
IF(NOT ICONV_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
|
||||
ENDIF(NOT ICONV_FIND_QUIETLY)
|
||||
ELSE(ICONV_FOUND)
|
||||
IF(Iconv_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find Iconv")
|
||||
ENDIF(Iconv_FIND_REQUIRED)
|
||||
ENDIF(ICONV_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ICONV_INCLUDE_DIR
|
||||
ICONV_LIBRARIES
|
||||
ICONV_SECOND_ARGUMENT_IS_CONST
|
||||
)
|
@ -11,6 +11,7 @@
|
||||
#cmakedefine HAVE_CLOCK_GETTIME
|
||||
|
||||
#cmakedefine WITH_LOG4C 1
|
||||
#cmakedefine WITH_ICONV 1
|
||||
|
||||
#cmakedefine HAVE_ARGP_H 1
|
||||
|
||||
|
@ -32,6 +32,11 @@ set(CSYNC_LINK_LIBRARIES
|
||||
${SQLITE3_LIBRARIES}
|
||||
)
|
||||
|
||||
if(ICONV_FOUND AND WITH_ICONV)
|
||||
list(APPEND CSYNC_PRIVATE_INCLUDE_DIRS ${ICONV_INCLUDE_DIRS})
|
||||
list(APPEND CSYNC_LINK_LIBRARIES ${ICONV_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set(csync_SRCS
|
||||
csync.c
|
||||
csync_config.c
|
||||
|
24
src/csync.c
24
src/csync.c
@ -32,6 +32,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
#include "csync_config.h"
|
||||
@ -41,6 +45,7 @@
|
||||
#include "csync_time.h"
|
||||
#include "csync_util.h"
|
||||
#include "csync_misc.h"
|
||||
#include "std/c_private.h"
|
||||
|
||||
#include "csync_update.h"
|
||||
#include "csync_reconcile.h"
|
||||
@ -215,7 +220,7 @@ int csync_init(CSYNC *ctx) {
|
||||
|
||||
if (csync_exclude_load(ctx, exclude) < 0) {
|
||||
strerror_r(errno, errbuf, sizeof(errbuf));
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Could not load %s - %s", exclude,
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Could not load %s - %s", exclude,
|
||||
errbuf);
|
||||
}
|
||||
#endif
|
||||
@ -644,6 +649,10 @@ int csync_destroy(CSYNC *ctx) {
|
||||
SAFE_FREE(ctx->options.config_dir);
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
c_close_iconv();
|
||||
#endif
|
||||
|
||||
SAFE_FREE(ctx);
|
||||
|
||||
SAFE_FREE(lock);
|
||||
@ -833,4 +842,17 @@ bool csync_get_local_only( CSYNC *ctx ) {
|
||||
return ctx->options.local_only_mode;
|
||||
}
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
int csync_set_iconv_codec(const char *from)
|
||||
{
|
||||
c_close_iconv();
|
||||
|
||||
if (from != NULL) {
|
||||
c_setup_iconv(from);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* vim: set ts=8 sw=2 et cindent: */
|
||||
|
12
src/csync.h
12
src/csync.h
@ -35,6 +35,7 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <config.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -421,6 +422,17 @@ int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int fi
|
||||
*/
|
||||
int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
/**
|
||||
* @brief Set iconv source codec for filenames.
|
||||
*
|
||||
* @param from Source codec.
|
||||
*
|
||||
* @return 0 on success, or an iconv error number.
|
||||
*/
|
||||
int csync_set_iconv_codec(const char *from);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -40,6 +40,10 @@
|
||||
#include "c_private.h"
|
||||
#include "csync.h"
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#include "vio/csync_vio_method.h"
|
||||
#include "csync_macros.h"
|
||||
|
||||
@ -128,6 +132,9 @@ struct csync_s {
|
||||
char *config_dir;
|
||||
bool with_conflict_copys;
|
||||
bool local_only_mode;
|
||||
#ifdef WITH_ICONV
|
||||
iconv_t iconv_cd;
|
||||
#endif
|
||||
} options;
|
||||
|
||||
struct {
|
||||
|
@ -39,7 +39,8 @@
|
||||
/* check if path is a file */
|
||||
int c_isfile(const char *path) {
|
||||
csync_stat_t sb;
|
||||
const mbchar_t *wpath = c_multibyte(path);
|
||||
mbchar_t *wpath = c_multibyte(path);
|
||||
|
||||
int re = _tstat(wpath, &sb);
|
||||
c_free_multibyte(wpath);
|
||||
|
||||
@ -69,8 +70,10 @@ int c_copy(const char* src, const char *dst, mode_t mode) {
|
||||
|
||||
#ifdef _WIN32
|
||||
if(src && dst) {
|
||||
if (CopyFile(src, dst, FALSE)) {
|
||||
return 0;
|
||||
mbchar_t *wsrc = c_multibyte(src);
|
||||
mbchar_t *wdst = c_multibyte(dst);
|
||||
if (CopyFileW(wsrc, wdst, FALSE)) {
|
||||
rc = 0;
|
||||
}
|
||||
errno = GetLastError();
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EDQUOT 0
|
||||
#define ENODATA 0
|
||||
@ -111,6 +110,13 @@ typedef char mbchar_t;
|
||||
#define _trewinddir rewinddir
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
/** @internal */
|
||||
int c_setup_iconv(const char* to);
|
||||
/** @internal */
|
||||
int c_close_iconv(void);
|
||||
#endif
|
||||
|
||||
#endif //_C_PRIVATE_H
|
||||
|
||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||
|
@ -20,6 +20,9 @@
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
@ -29,8 +32,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "c_string.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_macro.h"
|
||||
@ -39,6 +40,78 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
#include <iconv.h>
|
||||
|
||||
typedef struct {
|
||||
iconv_t to;
|
||||
iconv_t from;
|
||||
} iconv_conversions;
|
||||
|
||||
static iconv_conversions _iconvs = { NULL, NULL };
|
||||
|
||||
int c_setup_iconv(const char* to) {
|
||||
_iconvs.to = iconv_open(to, "UTF-8");
|
||||
_iconvs.from = iconv_open("UTF-8", to);
|
||||
|
||||
if (_iconvs.to == (iconv_t)-1 || _iconvs.from == (iconv_t)-1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_close_iconv() {
|
||||
int ret_to = iconv_close(_iconvs.to);
|
||||
int ret_from = iconv_close(_iconvs.from);
|
||||
|
||||
if (ret_to == -1 || ret_from == -1)
|
||||
return -1;
|
||||
|
||||
_iconvs.to = (iconv_t) 0;
|
||||
_iconvs.from = (iconv_t) 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum iconv_direction { iconv_from_native, iconv_to_native };
|
||||
|
||||
static char *c_iconv(const char* str, enum iconv_direction dir)
|
||||
{
|
||||
char *in = (char*)str;
|
||||
size_t size;
|
||||
size_t outsize;
|
||||
char *out;
|
||||
char *out_in;
|
||||
size_t ret;
|
||||
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
if(_iconvs.from == NULL && _iconvs.to == NULL) {
|
||||
#ifdef __APPLE__
|
||||
c_setup_iconv("UTF-8-MAC");
|
||||
#else
|
||||
return c_strdup(str);
|
||||
#endif
|
||||
}
|
||||
|
||||
size = strlen(in);
|
||||
outsize = size*2;
|
||||
out = c_malloc(outsize);
|
||||
out_in = out;
|
||||
|
||||
if (dir == iconv_to_native) {
|
||||
ret = iconv(_iconvs.to, &in, &size, &out, &outsize);
|
||||
} else {
|
||||
ret = iconv(_iconvs.from, &in, &size, &out, &outsize);
|
||||
}
|
||||
|
||||
assert(ret != (size_t)-1);
|
||||
|
||||
return out_in;
|
||||
}
|
||||
#endif
|
||||
|
||||
int c_streq(const char *a, const char *b) {
|
||||
register const char *s1 = a;
|
||||
register const char *s2 = b;
|
||||
@ -197,9 +270,9 @@ char *c_lowercase(const char* str) {
|
||||
}
|
||||
|
||||
/* Convert a wide multibyte String to UTF8 */
|
||||
const char* c_utf8(const mbchar_t *wstr)
|
||||
char* c_utf8(const mbchar_t *wstr)
|
||||
{
|
||||
const char *dst = NULL;
|
||||
char *dst = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
char *mdst = NULL;
|
||||
@ -214,19 +287,22 @@ const char* c_utf8(const mbchar_t *wstr)
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, len, mdst, size_needed, NULL, NULL);
|
||||
dst = mdst;
|
||||
}
|
||||
#else
|
||||
#ifdef WITH_ICONV
|
||||
dst = c_iconv(wstr, iconv_from_native);
|
||||
#else
|
||||
dst = wstr;
|
||||
#endif
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* Convert a an UTF8 string to multibyte */
|
||||
const mbchar_t* c_multibyte(const char *str)
|
||||
mbchar_t* c_multibyte(const char *str)
|
||||
{
|
||||
mbchar_t *dst = NULL;
|
||||
#ifdef _WIN32
|
||||
mbchar_t *wstrTo = NULL;
|
||||
if(!str) return NULL;
|
||||
|
||||
size_t len = strlen( str );
|
||||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
|
||||
if(size_needed > 0) {
|
||||
@ -235,26 +311,12 @@ const mbchar_t* c_multibyte(const char *str)
|
||||
memset( (void*)wstrTo, 0, size_char);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str, -1, wstrTo, size_needed);
|
||||
}
|
||||
return wstrTo;
|
||||
#else
|
||||
return str;
|
||||
#endif
|
||||
}
|
||||
|
||||
void c_free_utf8(char* buf)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SAFE_FREE(buf);
|
||||
#ifdef WITH_ICONV
|
||||
dst = c_iconv(str, iconv_to_native);
|
||||
#else
|
||||
(void)buf;
|
||||
dst = str;
|
||||
#endif
|
||||
}
|
||||
|
||||
void c_free_multibyte(const mbchar_t* buf)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SAFE_FREE(buf);
|
||||
#else
|
||||
(void)buf;
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
@ -34,6 +34,9 @@
|
||||
#define _C_STR_H
|
||||
|
||||
#include "c_private.h"
|
||||
#include "c_macro.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct c_strlist_s; typedef struct c_strlist_s c_strlist_t;
|
||||
|
||||
@ -162,7 +165,7 @@ char *c_lowercase(const char* str);
|
||||
* @see c_multibyte()
|
||||
*
|
||||
*/
|
||||
const char* c_utf8(const mbchar_t *str);
|
||||
char* c_utf8(const mbchar_t *str);
|
||||
|
||||
/**
|
||||
* @brief Convert a utf8 encoded string to multibyte (Win32).
|
||||
@ -187,8 +190,9 @@ const char* c_utf8(const mbchar_t *str);
|
||||
* @see c_utf8()
|
||||
*
|
||||
*/
|
||||
const mbchar_t* c_multibyte(const char *wstr);
|
||||
mbchar_t* c_multibyte(const char *wstr);
|
||||
|
||||
#if defined(_WIN32) || defined(WITH_ICONV)
|
||||
/**
|
||||
* @brief Free buffer malloced by c_utf8().
|
||||
*
|
||||
@ -206,7 +210,8 @@ const mbchar_t* c_multibyte(const char *wstr);
|
||||
* @see c_utf8()
|
||||
*
|
||||
*/
|
||||
void c_free_utf8(char* buf);
|
||||
|
||||
#define c_free_multibyte(x) SAFE_FREE(x)
|
||||
|
||||
/**
|
||||
* @brief Free buffer malloced by c_multibyte().
|
||||
@ -225,7 +230,11 @@ void c_free_utf8(char* buf);
|
||||
* @see c_multibyte()
|
||||
*
|
||||
*/
|
||||
void c_free_multibyte(const mbchar_t* buf);
|
||||
#define c_free_utf8(x) SAFE_FREE(x)
|
||||
#else
|
||||
#define c_free_multibyte(x) (void)x
|
||||
#define c_free_utf8(x) (void)x
|
||||
#endif
|
||||
|
||||
/**
|
||||
* }@
|
||||
|
@ -21,6 +21,8 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "c_private.h"
|
||||
#include "c_string.h"
|
||||
|
||||
#include "c_time.h"
|
||||
|
||||
@ -68,7 +70,10 @@ double c_secdiff(struct timespec clock1, struct timespec clock0) {
|
||||
|
||||
#ifdef HAVE_UTIMES
|
||||
int c_utimes(const char *uri, const struct timeval *times) {
|
||||
return utimes(uri, times);
|
||||
mbchar_t *wuri = c_multibyte(uri);
|
||||
int ret = utimes(wuri, times);
|
||||
c_free_multibyte(wuri);
|
||||
return ret;
|
||||
}
|
||||
#else // HAVE_UTIMES
|
||||
|
||||
@ -92,6 +97,7 @@ int c_utimes(const char *uri, const struct timeval *times) {
|
||||
FILETIME LastAccessTime;
|
||||
FILETIME LastModificationTime;
|
||||
HANDLE hFile;
|
||||
mbchar_t *wuri = c_multibyte( uri );
|
||||
|
||||
if(times) {
|
||||
UnixTimevalToFileTime(times[0], &LastAccessTime);
|
||||
|
@ -51,6 +51,12 @@ int csync_vio_init(CSYNC *ctx, const char *module, const char *args) {
|
||||
csync_vio_method_init_fn init_fn;
|
||||
const mbchar_t *mpath = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
mbchar_t tbuf[MAX_PATH];
|
||||
mbchar_t *pathBuf = NULL;
|
||||
char *buf = NULL;
|
||||
char *last_bslash = NULL;
|
||||
#endif
|
||||
|
||||
if (asprintf(&path, "%s/csync_%s.%s", PLUGINDIR, module, MODULE_EXTENSION) < 0) {
|
||||
return -1;
|
||||
|
@ -47,7 +47,7 @@ typedef struct fhandle_s {
|
||||
csync_vio_method_handle_t *csync_vio_local_open(const char *durl, int flags, mode_t mode) {
|
||||
fhandle_t *handle = NULL;
|
||||
int fd = -1;
|
||||
const mbchar_t *url = c_multibyte(durl);
|
||||
mbchar_t *url = c_multibyte(durl);
|
||||
|
||||
if ((fd = _topen(url, flags, mode)) < 0) {
|
||||
c_free_multibyte(url);
|
||||
@ -71,7 +71,7 @@ csync_vio_method_handle_t *csync_vio_local_open(const char *durl, int flags, mod
|
||||
csync_vio_method_handle_t *csync_vio_local_creat(const char *durl, mode_t mode) {
|
||||
fhandle_t *handle = NULL;
|
||||
int fd = -1;
|
||||
const mbchar_t *url = c_multibyte(durl);
|
||||
mbchar_t *url = c_multibyte(durl);
|
||||
|
||||
if(( fd = _tcreat( url, mode)) < 0) {
|
||||
c_free_multibyte(url);
|
||||
@ -163,7 +163,8 @@ typedef struct dhandle_s {
|
||||
|
||||
csync_vio_method_handle_t *csync_vio_local_opendir(const char *name) {
|
||||
dhandle_t *handle = NULL;
|
||||
const mbchar_t *dirname = c_multibyte(name);
|
||||
mbchar_t *dirname = c_multibyte(name);
|
||||
|
||||
handle = c_malloc(sizeof(dhandle_t));
|
||||
if (handle == NULL) {
|
||||
c_free_multibyte(dirname);
|
||||
@ -176,8 +177,7 @@ csync_vio_method_handle_t *csync_vio_local_opendir(const char *name) {
|
||||
SAFE_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->path = c_strdup(name);
|
||||
c_free_multibyte(dirname);
|
||||
handle->path = c_utf8(dirname);
|
||||
|
||||
return (csync_vio_method_handle_t *) handle;
|
||||
}
|
||||
@ -223,7 +223,7 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_method_handle_t *dhandl
|
||||
goto err;
|
||||
}
|
||||
|
||||
file_stat->name = (char*) c_utf8(dirent->d_name);
|
||||
file_stat->name = c_utf8(dirent->d_name);
|
||||
file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -263,7 +263,7 @@ int csync_vio_local_mkdir(const char *uri, mode_t mode) {
|
||||
}
|
||||
|
||||
int csync_vio_local_rmdir(const char *uri) {
|
||||
const mbchar_t *dirname = c_multibyte(uri);
|
||||
mbchar_t *dirname = c_multibyte(uri);
|
||||
int re = -1;
|
||||
|
||||
re = _trmdir(dirname);
|
||||
@ -274,7 +274,8 @@ int csync_vio_local_rmdir(const char *uri) {
|
||||
|
||||
int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
csync_stat_t sb;
|
||||
const mbchar_t *wuri = c_multibyte( uri );
|
||||
mbchar_t *wuri = c_multibyte( uri );
|
||||
|
||||
if( _tstat(wuri, &sb) < 0) {
|
||||
c_free_multibyte(wuri);
|
||||
return -1;
|
||||
@ -372,10 +373,10 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
}
|
||||
|
||||
int csync_vio_local_rename(const char *olduri, const char *newuri) {
|
||||
#ifdef _WIN32
|
||||
const mbchar_t *nuri = c_multibyte(newuri);
|
||||
const mbchar_t *ouri = c_multibyte(olduri);
|
||||
mbchar_t *nuri = c_multibyte(newuri);
|
||||
mbchar_t *ouri = c_multibyte(olduri);
|
||||
|
||||
#ifdef _WIN32
|
||||
if(ouri && nuri) {
|
||||
if (MoveFileExW(ouri, nuri, MOVEFILE_COPY_ALLOWED + MOVEFILE_REPLACE_EXISTING + MOVEFILE_WRITE_THROUGH )) {
|
||||
return 0;
|
||||
@ -384,24 +385,23 @@ int csync_vio_local_rename(const char *olduri, const char *newuri) {
|
||||
} else {
|
||||
errno = ENOENT;
|
||||
}
|
||||
#else
|
||||
return rename(ouri, nuri);
|
||||
#endif
|
||||
c_free_multibyte(nuri);
|
||||
c_free_multibyte(ouri);
|
||||
return -1;
|
||||
#else
|
||||
return rename(olduri, newuri);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int csync_vio_local_unlink(const char *uri) {
|
||||
const mbchar_t *nuri = c_multibyte(uri);
|
||||
mbchar_t *nuri = c_multibyte(uri);
|
||||
int re = _tunlink( nuri );
|
||||
c_free_multibyte(nuri);
|
||||
return re;
|
||||
}
|
||||
|
||||
int csync_vio_local_chmod(const char *uri, mode_t mode) {
|
||||
const mbchar_t *nuri = c_multibyte(uri);
|
||||
mbchar_t *nuri = c_multibyte(uri);
|
||||
int re = -1;
|
||||
|
||||
re = _tchmod(nuri, mode);
|
||||
|
306
tests/ownCloud/mocka/ocmod_test.c
Normal file
306
tests/ownCloud/mocka/ocmod_test.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright 2012 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; 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 <stdio.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <iniparser.h>
|
||||
#include <std/c_path.h>
|
||||
|
||||
#include "../../modules/csync_owncloud.c"
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "config_test.h"
|
||||
|
||||
struct oc_credentials {
|
||||
const char *url;
|
||||
const char *user;
|
||||
const char *pwd;
|
||||
char *oc_server;
|
||||
|
||||
} _credentials;
|
||||
|
||||
|
||||
static bool load_oc_config( const char *config ) {
|
||||
dictionary *dict;
|
||||
const char* val;
|
||||
bool re = true;
|
||||
char *deflt;
|
||||
char b;
|
||||
deflt = &b;
|
||||
|
||||
|
||||
dict = iniparser_load( config );
|
||||
|
||||
if( ! dict ) {
|
||||
printf("Could not load config %s\n", config);
|
||||
return false;
|
||||
}
|
||||
|
||||
val = iniparser_getstring(dict, "global:host", deflt);
|
||||
if( val ) {
|
||||
_credentials.url = c_strdup( val );
|
||||
} else {
|
||||
re = false;
|
||||
}
|
||||
|
||||
val = iniparser_getstring(dict, "global:user", deflt);
|
||||
if( re && val ) {
|
||||
_credentials.user = c_strdup( val );
|
||||
} else {
|
||||
re = false;
|
||||
}
|
||||
|
||||
val = iniparser_getstring(dict, "global:pwd", deflt);
|
||||
if( re && val ) {
|
||||
_credentials.pwd = c_strdup( val );
|
||||
} else {
|
||||
re = false;
|
||||
}
|
||||
|
||||
if( re ) {
|
||||
asprintf(&(_credentials.oc_server),
|
||||
"owncloud://%s:%s@%s/files/webdav.php",
|
||||
_credentials.user, _credentials.pwd,
|
||||
_credentials.url );
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
|
||||
// A test case that does nothing and succeeds.
|
||||
static void null_test_success(void **state) {
|
||||
(void) state;
|
||||
}
|
||||
|
||||
|
||||
static void connect_test_success(void **state) {
|
||||
|
||||
int re = 0;
|
||||
char buf[255];
|
||||
|
||||
(void) state;
|
||||
strcpy(buf, TEST_CONFIG_DIR);
|
||||
strcat(buf, "mockatest.cfg");
|
||||
|
||||
assert_true( load_oc_config( buf ));
|
||||
|
||||
re = dav_connect( _credentials.oc_server );
|
||||
|
||||
assert_int_equal( re, 0 );
|
||||
assert_int_equal( _connected, 1 );
|
||||
assert_int_equal( dav_session.time_delta_sum, 0);
|
||||
assert_int_equal( dav_session.time_delta_cnt, 0);
|
||||
}
|
||||
|
||||
static void fetch_a_context(void **state) {
|
||||
struct listdir_context *fetchCtx = NULL;
|
||||
char *curi = _cleanPath(_credentials.oc_server);
|
||||
int rc = 0;
|
||||
unsigned int i;
|
||||
|
||||
(void) state;
|
||||
|
||||
fetchCtx = fetch_resource_list( curi, NE_DEPTH_ONE);
|
||||
assert_int_equal( rc, 0 );
|
||||
printf("Results: %d\n", fetchCtx->result_count);
|
||||
|
||||
fetchCtx->currResource = fetchCtx->list;
|
||||
for( i = 0; i < fetchCtx->result_count; i++ ) {
|
||||
assert_true( fetchCtx->currResource != NULL );
|
||||
assert_true( fetchCtx->currResource->uri != NULL );
|
||||
assert_true( fetchCtx->currResource->name != NULL );
|
||||
|
||||
printf( " %s -> %s\n", fetchCtx->currResource->uri, fetchCtx->currResource->name );
|
||||
printf( " MD5: %s\n", fetchCtx->currResource->md5);
|
||||
fetchCtx->currResource = fetchCtx->currResource->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_mkdir(const char *dir) {
|
||||
char path[255];
|
||||
|
||||
strcpy( path, _credentials.oc_server );
|
||||
strcat( path, "/");
|
||||
strcat( path, dir );
|
||||
|
||||
return owncloud_mkdir( path, 775 );
|
||||
}
|
||||
|
||||
static void setup_toplevel_dir( void **state ) {
|
||||
char basepath[255];
|
||||
|
||||
strcpy( basepath, "tXXXXXX");
|
||||
assert_int_equal( c_tmpname(basepath), 0 );
|
||||
printf("Using top testing dir %s\n", basepath);
|
||||
assert_int_equal( test_mkdir( basepath ), 0 );
|
||||
*state = (void*) c_strdup(basepath);
|
||||
}
|
||||
|
||||
static void teardown_toplevel_dir( void **state ) {
|
||||
(void) state;
|
||||
}
|
||||
|
||||
static void stat_local_file( csync_stat_t *sb, const char *file )
|
||||
{
|
||||
_TCHAR *mpath = NULL;
|
||||
mpath = c_multibyte(file);
|
||||
assert_int_not_equal(_tstat(mpath, sb), -1);
|
||||
c_free_multibyte(mpath);
|
||||
assert_null(mpath);
|
||||
}
|
||||
|
||||
#define BUFSIZE 4096
|
||||
static size_t upload_a_file( void **state, const char *src_name, const char *durl ) {
|
||||
|
||||
char buffer[BUFSIZE+1];
|
||||
int size;
|
||||
char path[256];
|
||||
char src_path[256];
|
||||
int fh;
|
||||
csync_vio_method_handle_t *handle;
|
||||
size_t written;
|
||||
size_t overall_size = 0;
|
||||
csync_stat_t sb;
|
||||
|
||||
/* Create the target path */
|
||||
strcpy( path, _credentials.oc_server );
|
||||
strcat( path, "/");
|
||||
strcat( path, (const char*) *state );
|
||||
strcat( path, "/");
|
||||
strcat( path, durl );
|
||||
|
||||
handle = owncloud_creat( path, 0644 );
|
||||
assert_int_not_equal( handle, NULL );
|
||||
|
||||
strcpy(src_path, TESTFILES_DIR);
|
||||
strcat(src_path, src_name);
|
||||
fh = open(src_path, O_RDONLY);
|
||||
assert_int_not_equal( fh, -1 );
|
||||
|
||||
while( (size = read(fh, buffer, BUFSIZE) )>0 ) {
|
||||
buffer[size] = '\0';
|
||||
written = owncloud_write( handle, buffer, size );
|
||||
assert_int_equal( size, written );
|
||||
overall_size += written;
|
||||
}
|
||||
assert_int_equal( owncloud_close(handle), 0);
|
||||
|
||||
/* stat the local file */
|
||||
stat_local_file( &sb, src_path );
|
||||
|
||||
assert_int_equal( overall_size, sb.st_size );
|
||||
|
||||
close(fh);
|
||||
|
||||
return overall_size;
|
||||
}
|
||||
|
||||
static void test_upload_files( void **state ) {
|
||||
const char *bpath = (char*) (*state);
|
||||
|
||||
upload_a_file( state, "test.txt", "t1/test.txt");
|
||||
upload_a_file( state, "red_is_the_rose.jpg", "t1/red is the rose.jpg");
|
||||
|
||||
printf("Base path: %s\n", bpath);
|
||||
|
||||
}
|
||||
|
||||
static void download_a_file( const char* local, void **state, const char *durl)
|
||||
{
|
||||
char buffer[BUFSIZE+1];
|
||||
char path[256];
|
||||
char src_path[256];
|
||||
int did;
|
||||
_TCHAR tlocal[256];
|
||||
|
||||
csync_vio_method_handle_t *handle;
|
||||
ssize_t count;
|
||||
ssize_t overall_size = 0;
|
||||
csync_stat_t sb;
|
||||
|
||||
/* Create the target path */
|
||||
strcpy( path, _credentials.oc_server );
|
||||
strcat( path, "/");
|
||||
strcat( path, (const char*) *state );
|
||||
strcat( path, "/");
|
||||
strcat( path, durl );
|
||||
|
||||
strcpy( tlocal, "/tmp/");
|
||||
strcat( tlocal, local );
|
||||
did = _topen(tlocal, O_RDWR|O_CREAT, 0644);
|
||||
assert_true( did > -1 );
|
||||
|
||||
handle = owncloud_open( path, O_RDONLY, 0644 );
|
||||
assert_int_not_equal( handle, NULL );
|
||||
|
||||
while( (count = owncloud_read(handle, buffer, BUFSIZE)) > 0 ) {
|
||||
write( did, buffer, count );
|
||||
overall_size += count;
|
||||
}
|
||||
assert_int_equal( owncloud_close(handle), 0 );
|
||||
close(did);
|
||||
|
||||
strcpy(src_path, TESTFILES_DIR);
|
||||
strcat(src_path, local);
|
||||
stat_local_file( &sb, src_path );
|
||||
|
||||
/* assert the download size, it has to be the same. */
|
||||
assert_true( overall_size == sb.st_size );
|
||||
|
||||
}
|
||||
|
||||
static void test_download_files( void **state ) {
|
||||
const char *bpath = (char*) (*state);
|
||||
|
||||
printf("Base path: %s\n", bpath);
|
||||
|
||||
download_a_file( "test.txt", state, "t1/test.txt");
|
||||
download_a_file( "red_is_the_rose.jpg", state, "t1/red is the rose.jpg");
|
||||
}
|
||||
|
||||
static void test_setup_dirs(void **state) {
|
||||
const char *basepath = *state;
|
||||
char path[255];
|
||||
|
||||
strcpy( path, basepath );
|
||||
strcat( path, "/t1" );
|
||||
assert_int_equal( test_mkdir( path ), 0 );
|
||||
|
||||
strcpy( path, basepath );
|
||||
strcat( path, "/t2");
|
||||
assert_int_equal( test_mkdir( path ), 0 );
|
||||
strcat( path, "/Übergröße");
|
||||
assert_int_equal( test_mkdir( path ), 0 );
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
const UnitTest tests[] = {
|
||||
unit_test(null_test_success),
|
||||
unit_test(connect_test_success),
|
||||
unit_test_setup_teardown(test_setup_dirs, setup_toplevel_dir, teardown_toplevel_dir),
|
||||
unit_test(test_upload_files),
|
||||
unit_test(fetch_a_context),
|
||||
unit_test(test_download_files),
|
||||
};
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
return run_tests(tests);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
@ -173,6 +174,82 @@ static void check_c_uppercase_null(void **state)
|
||||
assert_null(str);
|
||||
}
|
||||
|
||||
static void check_iconv_setup(void **state)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
#ifdef __APPLE__
|
||||
rc = c_setup_iconv("UTF-8-MAC");
|
||||
assert_int_equal(rc, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void check_iconv_teardown(void **state)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
// this must never crash
|
||||
rc = c_close_iconv();
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void check_iconv_to_native_normalization(void **state)
|
||||
{
|
||||
const char *out = NULL;
|
||||
const char *in= "\x48\xc3\xa4"; // UTF8
|
||||
#ifdef __APPLE__
|
||||
const char *exp_out = "\x48\x61\xcc\x88"; // UTF-8-MAC
|
||||
#else
|
||||
const char *exp_out = "\x48\xc3\xa4"; // UTF8
|
||||
#endif
|
||||
|
||||
out = c_multibyte(in);
|
||||
assert_string_equal(out, exp_out);
|
||||
|
||||
c_free_multibyte(out);
|
||||
assert_null(out);
|
||||
|
||||
(void) state; /* unused */
|
||||
}
|
||||
|
||||
static void check_iconv_from_native_normalization(void **state)
|
||||
{
|
||||
const char *out = NULL;
|
||||
#ifdef __APPLE__
|
||||
const char* in = "\x48\x61\xcc\x88"; // UTF-8-MAC
|
||||
#else
|
||||
const char *in = "\x48\xc3\xa4"; // UTF-8
|
||||
#endif
|
||||
const char *exp_out = "\x48\xc3\xa4"; // UTF-8
|
||||
|
||||
out = c_utf8(in);
|
||||
assert_string_equal(out, exp_out);
|
||||
|
||||
c_free_utf8(out);
|
||||
assert_null(out);
|
||||
|
||||
(void) state; /* unused */
|
||||
}
|
||||
|
||||
static void check_iconv_ascii(void **state)
|
||||
{
|
||||
const char *out = NULL;
|
||||
const char* in = "abc/ABC\\123";
|
||||
const char *exp_out = "abc/ABC\\123";
|
||||
|
||||
out = c_utf8(in);
|
||||
assert_string_equal(out, exp_out);
|
||||
|
||||
c_free_utf8(out);
|
||||
assert_null(out);
|
||||
|
||||
(void) state; /* unused */
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
@ -189,6 +266,9 @@ int torture_run_tests(void)
|
||||
unit_test(check_c_uppercase),
|
||||
unit_test(check_c_uppercase_empty),
|
||||
unit_test(check_c_uppercase_null),
|
||||
unit_test_setup_teardown(check_iconv_ascii, check_iconv_setup, check_iconv_teardown),
|
||||
unit_test_setup_teardown(check_iconv_to_native_normalization, check_iconv_setup, check_iconv_teardown),
|
||||
unit_test_setup_teardown(check_iconv_from_native_normalization, check_iconv_setup, check_iconv_teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
|
Loading…
Reference in New Issue
Block a user