From 49d2fd685b4c845fb86392b8a2e384ab37e15660 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Fri, 7 Dec 2012 13:02:46 +0100 Subject: [PATCH] iconv support This allows for files on mac to automatically be converted to UNC --- CMakeLists.txt | 1 + DefineOptions.cmake | 1 + client/csync_client.c | 23 +++++- cmake/Modules/FindIconv.cmake | 80 ++++++++++++++++++++ config.h.cmake | 1 + src/CMakeLists.txt | 5 ++ src/csync.c | 23 ++++++ src/csync.h | 15 +++- src/csync_private.h | 7 ++ src/csync_statedb.c | 2 +- src/std/c_dir.c | 10 +-- src/std/c_file.c | 6 +- src/std/c_private.h | 8 +- src/std/c_string.c | 118 +++++++++++++++++++++++------- src/std/c_string.h | 28 ++++--- src/std/c_time.c | 7 +- src/vio/csync_vio.c | 4 +- src/vio/csync_vio_local.c | 35 ++++----- tests/ownCloud/mocka/ocmod_test.c | 3 +- tests/std_tests/check_std_c_str.c | 80 ++++++++++++++++++++ 20 files changed, 377 insertions(+), 80 deletions(-) create mode 100644 cmake/Modules/FindIconv.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dd53b4ce35..8c7d86b034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/DefineOptions.cmake b/DefineOptions.cmake index 485e183221..65b5ae5617 100644 --- a/DefineOptions.cmake +++ b/DefineOptions.cmake @@ -1,2 +1,3 @@ +option(WITH_ICONV "Build csync with iconv support" ON) option(UNIT_TESTING "Build with unit tests" OFF) option(MEM_NULL_TESTS "Enable NULL memory testing" OFF) diff --git a/client/csync_client.c b/client/csync_client.c index 9349bd4abc..d712e38696 100644 --- a/client/csync_client.c +++ b/client/csync_client.c @@ -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= Add an additional exclude file\n\ - --test-statedb Test creation of the statedb. Runs update\n\ + --exclude-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); diff --git a/cmake/Modules/FindIconv.cmake b/cmake/Modules/FindIconv.cmake new file mode 100644 index 0000000000..9ce2fa7fce --- /dev/null +++ b/cmake/Modules/FindIconv.cmake @@ -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 + 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 +) diff --git a/config.h.cmake b/config.h.cmake index 1587d42ffc..02d982a01d 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -11,6 +11,7 @@ #cmakedefine HAVE_CLOCK_GETTIME #cmakedefine WITH_LOG4C 1 +#cmakedefine WITH_ICONV 1 #cmakedefine HAVE_ARGP_H 1 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 180ac61ccd..15eab2d20b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,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 diff --git a/src/csync.c b/src/csync.c index 807efc5d64..c0db9ec037 100644 --- a/src/csync.c +++ b/src/csync.c @@ -32,6 +32,10 @@ #include #include +#ifdef WITH_ICONV +#include +#endif + #include "c_lib.h" #include "csync_private.h" #include "csync_config.h" @@ -42,6 +46,8 @@ #include "csync_util.h" #include "csync_misc.h" #include "c_jhash.h" +#include "std/c_private.h" + #include "csync_update.h" #include "csync_reconcile.h" @@ -717,6 +723,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); @@ -1002,6 +1012,19 @@ int csync_set_module_property(CSYNC* ctx, const char* key, void* value) return csync_vio_set_property(ctx, key, value); } +#ifdef WITH_ICONV +int csync_set_iconv_codec(const char *from) +{ + c_close_iconv(); + + if (from != NULL) { + c_setup_iconv(from); + } + + return 0; +} +#endif + int csync_set_progress_callback(CSYNC* ctx, csync_progress_callback cb) { if (ctx == NULL || cb == NULL) { diff --git a/src/csync.h b/src/csync.h index e2f858e92e..99e219cc6b 100644 --- a/src/csync.h +++ b/src/csync.h @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -462,6 +463,18 @@ 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 + /** * @brief Get the error code from the last operation. * @@ -469,7 +482,6 @@ int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int f */ CSYNC_ERROR_CODE csync_get_error(CSYNC *ctx); - /* dirty stuff from here on - EXPERIMENTAL */ /* read the information if a file is known to csync ie. if it has an entry in the database */ bool csync_file_known( char *statedb_file, const char* url ); @@ -487,7 +499,6 @@ bool csync_file_known( char *statedb_file, const char* url ); */ int csync_set_module_property(CSYNC *ctx, const char *key, void *value); - enum csync_notify_type_e { CSYNC_NOTIFY_START_DOWNLOAD, CSYNC_NOTIFY_START_UPLOAD, CSYNC_NOTIFY_PROGRESS, CSYNC_NOTIFY_FINISHED, CSYNC_NOTFY_ERROR }; diff --git a/src/csync_private.h b/src/csync_private.h index f8851a84eb..75559861be 100644 --- a/src/csync_private.h +++ b/src/csync_private.h @@ -40,6 +40,10 @@ #include "c_private.h" #include "csync.h" +#ifdef WITH_ICONV +#include +#endif + #include "vio/csync_vio_method.h" #include "csync_macros.h" @@ -128,6 +132,9 @@ struct csync_s { bool local_only_mode; bool remote_push_atomar; int log_verbosity; +#ifdef WITH_ICONV + iconv_t iconv_cd; +#endif } options; struct { diff --git a/src/csync_statedb.c b/src/csync_statedb.c index 9112d9f1a7..1b0eece11d 100644 --- a/src/csync_statedb.c +++ b/src/csync_statedb.c @@ -55,7 +55,7 @@ int csync_get_statedb_exists(CSYNC *ctx) { /* Set the hide attribute in win32. That makes it invisible in normal explorers */ static void _csync_win32_hide_file( const char *file ) { #ifdef _WIN32 - const _TCHAR *fileName; + _TCHAR *fileName; if( !file ) return; fileName = c_multibyte( file ); diff --git a/src/std/c_dir.c b/src/std/c_dir.c index a66d1943c9..f7e84b9949 100644 --- a/src/std/c_dir.c +++ b/src/std/c_dir.c @@ -15,8 +15,8 @@ int c_mkdirs(const char *path, mode_t mode) { int tmp; csync_stat_t sb; - const _TCHAR *wpath = c_multibyte(path); - const _TCHAR *swpath = NULL; + _TCHAR *wpath = c_multibyte(path); + _TCHAR *swpath = NULL; if (path == NULL) { errno = EINVAL; @@ -72,8 +72,8 @@ int c_rmdirs(const char *path) { struct _tdirent *dp; csync_stat_t sb; char *fname = NULL; - const _TCHAR *wfname = NULL; - const _TCHAR *wpath = c_multibyte(path); + _TCHAR *wfname = NULL; + _TCHAR *wpath = c_multibyte(path); if ((d = _topendir(wpath)) != NULL) { while( _tstat(wpath, &sb) == 0) { @@ -145,7 +145,7 @@ int c_rmdirs(const char *path) { int c_isdir(const char *path) { csync_stat_t sb; - const _TCHAR *wpath = c_multibyte(path); + _TCHAR *wpath = c_multibyte(path); if (_tstat (wpath, &sb) == 0 && S_ISDIR(sb.st_mode)) { return 1; diff --git a/src/std/c_file.c b/src/std/c_file.c index 99bf605df4..9888f9e5a2 100644 --- a/src/std/c_file.c +++ b/src/std/c_file.c @@ -39,7 +39,7 @@ /* check if path is a file */ int c_isfile(const char *path) { csync_stat_t sb; - const _TCHAR *wpath = c_multibyte(path); + _TCHAR *wpath = c_multibyte(path); int re = _tstat(wpath, &sb); c_free_multibyte(wpath); @@ -69,8 +69,8 @@ int c_copy(const char* src, const char *dst, mode_t mode) { #ifdef _WIN32 if(src && dst) { - const _TCHAR *wsrc = c_multibyte(src); - const _TCHAR *wdst = c_multibyte(dst); + _TCHAR *wsrc = c_multibyte(src); + _TCHAR *wdst = c_multibyte(dst); if (CopyFileW(wsrc, wdst, FALSE)) { rc = 0; } diff --git a/src/std/c_private.h b/src/std/c_private.h index f7a0e00f4c..cd8965d9ed 100644 --- a/src/std/c_private.h +++ b/src/std/c_private.h @@ -31,7 +31,6 @@ #include #endif - #ifdef _WIN32 #define EDQUOT 0 #define ENODATA 0 @@ -114,6 +113,13 @@ typedef char _TCHAR; #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: */ diff --git a/src/std/c_string.c b/src/std/c_string.c index 2c425364ea..7c352257e8 100644 --- a/src/std/c_string.c +++ b/src/std/c_string.c @@ -20,6 +20,7 @@ * vim: ts=2 sw=2 et cindent */ +#include #include #include #include @@ -39,6 +40,78 @@ #include #endif +#ifdef WITH_ICONV +#include + +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 _TCHAR *wstr) +char* c_utf8(const _TCHAR *wstr) { - const char *dst = NULL; + char *dst = NULL; #ifdef _WIN32 char *mdst = NULL; @@ -214,48 +287,37 @@ const char* c_utf8(const _TCHAR *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 _TCHAR* c_multibyte(const char *str) +_TCHAR* c_multibyte(const char *str) { + _TCHAR *dst = NULL; #ifdef _WIN32 - _TCHAR *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) { int size_char = (size_needed+1)*sizeof(_TCHAR); - wstrTo = c_malloc(size_char); - memset( (void*)wstrTo, 0, size_char); - MultiByteToWideChar(CP_UTF8, 0, str, -1, wstrTo, size_needed); + dst = c_malloc(size_char); + memset( (void*)dst, 0, size_char); + MultiByteToWideChar(CP_UTF8, 0, str, -1, dst, size_needed); } - return wstrTo; #else - return str; +#ifdef WITH_ICONV + dst = c_iconv(str, iconv_to_native); +#else + dst = str; +#endif + return dst; #endif } - -void c_free_utf8(char* buf) -{ -#ifdef _WIN32 - SAFE_FREE(buf); -#else - (void)buf; -#endif -} - -void c_free_multibyte(const _TCHAR* buf) -{ -#ifdef _WIN32 - SAFE_FREE(buf); -#else - (void)buf; -#endif -} - diff --git a/src/std/c_string.h b/src/std/c_string.h index 8a8ecdf679..48919dc349 100644 --- a/src/std/c_string.h +++ b/src/std/c_string.h @@ -34,6 +34,9 @@ #define _C_STR_H #include "c_private.h" +#include "c_macro.h" + +#include struct c_strlist_s; typedef struct c_strlist_s c_strlist_t; @@ -146,7 +149,7 @@ char *c_lowercase(const char* str); * * @return The malloced converted string or NULL on error. */ -const char* c_utf8(const _TCHAR *str); + char* c_utf8(const _TCHAR *str); /** * @brief Convert a utf8 encoded string to multibyte (Win32). @@ -155,7 +158,16 @@ const char* c_utf8(const _TCHAR *str); * * @return The malloced converted multibyte string or NULL on error. */ -const _TCHAR* c_multibyte(const char *wstr); +_TCHAR* c_multibyte(const char *wstr); + +#if defined(_WIN32) || defined(WITH_ICONV) +/** + * @brief Free buffer malloced by c_multibyte. + * + * @param buf The buffer to free. + */ + +#define c_free_multibyte(x) SAFE_FREE(x) /** * @brief Free buffer malloced by c_utf8. @@ -163,14 +175,12 @@ const _TCHAR* c_multibyte(const char *wstr); * @param buf The buffer to free. * */ -void c_free_utf8(char* 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 -/** - * @brief Free buffer malloced by c_multibyte. - * - * @param buf The buffer to free. - */ -void c_free_multibyte(const _TCHAR* buf); /** * }@ diff --git a/src/std/c_time.c b/src/std/c_time.c index e40f90d3bd..00e328a1bd 100644 --- a/src/std/c_time.c +++ b/src/std/c_time.c @@ -69,7 +69,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); + _TCHAR *wuri = c_multibyte(uri); + int ret = utimes(wuri, times); + c_free_multibyte(wuri); + return ret; } #else // HAVE_UTIMES @@ -93,7 +96,7 @@ int c_utimes(const char *uri, const struct timeval *times) { FILETIME LastAccessTime; FILETIME LastModificationTime; HANDLE hFile; - const _TCHAR *wuri = c_multibyte( uri ); + _TCHAR *wuri = c_multibyte( uri ); if(times) { UnixTimevalToFileTime(times[0], &LastAccessTime); diff --git a/src/vio/csync_vio.c b/src/vio/csync_vio.c index 155a56afee..ddfc5bde4d 100644 --- a/src/vio/csync_vio.c +++ b/src/vio/csync_vio.c @@ -57,10 +57,10 @@ int csync_vio_init(CSYNC *ctx, const char *module, const char *args) { char *err = NULL; csync_vio_method_t *m = NULL; csync_vio_method_init_fn init_fn; - const _TCHAR *mpath = NULL; + _TCHAR *mpath = NULL; #ifdef _WIN32 _TCHAR tbuf[MAX_PATH]; - const _TCHAR *pathBuf = NULL; + _TCHAR *pathBuf = NULL; char *buf = NULL; char *last_bslash = NULL; #endif diff --git a/src/vio/csync_vio_local.c b/src/vio/csync_vio_local.c index 22d2203954..ca85be8d73 100644 --- a/src/vio/csync_vio_local.c +++ b/src/vio/csync_vio_local.c @@ -47,7 +47,7 @@ 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 _TCHAR *url = c_multibyte(durl); + _TCHAR *url = c_multibyte(durl); if ((fd = _topen(url, flags, mode)) < 0) { return NULL; @@ -69,7 +69,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 _TCHAR *url = c_multibyte(durl); + _TCHAR *url = c_multibyte(durl); if(( fd = _tcreat( url, mode)) < 0) { return NULL; @@ -159,7 +159,7 @@ typedef struct dhandle_s { csync_vio_method_handle_t *csync_vio_local_opendir(const char *name) { dhandle_t *handle = NULL; - const _TCHAR *dirname = c_multibyte(name); + _TCHAR *dirname = c_multibyte(name); handle = c_malloc(sizeof(dhandle_t)); if (handle == NULL) { return NULL; @@ -170,11 +170,7 @@ csync_vio_method_handle_t *csync_vio_local_opendir(const char *name) { SAFE_FREE(handle); return NULL; } -#ifdef _WIN32 handle->path = c_utf8(dirname); -#else - handle->path = c_strdup(dirname); -#endif return (csync_vio_method_handle_t *) handle; } @@ -220,11 +216,7 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_method_handle_t *dhandl goto err; } -#ifdef _WIN32 file_stat->name = c_utf8(dirent->d_name); -#else - file_stat->name = c_strdup(dirent->d_name); -#endif file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; #ifndef _WIN32 @@ -264,7 +256,7 @@ int csync_vio_local_mkdir(const char *uri, mode_t mode) { } int csync_vio_local_rmdir(const char *uri) { - const _TCHAR *dirname = c_multibyte(uri); + _TCHAR *dirname = c_multibyte(uri); int re = -1; re = _trmdir(dirname); @@ -295,7 +287,7 @@ static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder) int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { csync_stat_t sb; - const _TCHAR *wuri = c_multibyte( uri ); + _TCHAR *wuri = c_multibyte( uri ); if( _tstat(wuri, &sb) < 0) { c_free_multibyte(wuri); return -1; @@ -433,10 +425,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 _TCHAR *nuri = c_multibyte(newuri); - const _TCHAR *ouri = c_multibyte(olduri); + _TCHAR *nuri = c_multibyte(newuri); + _TCHAR *ouri = c_multibyte(olduri); +#ifdef _WIN32 if(ouri && nuri) { if (MoveFileExW(ouri, nuri, MOVEFILE_COPY_ALLOWED + MOVEFILE_REPLACE_EXISTING + MOVEFILE_WRITE_THROUGH )) { return 0; @@ -445,24 +437,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 _TCHAR *nuri = c_multibyte(uri); + _TCHAR *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 _TCHAR *nuri = c_multibyte(uri); + _TCHAR *nuri = c_multibyte(uri); int re = -1; re = _tchmod(nuri, mode); diff --git a/tests/ownCloud/mocka/ocmod_test.c b/tests/ownCloud/mocka/ocmod_test.c index 8fb829f7f0..94e45899af 100644 --- a/tests/ownCloud/mocka/ocmod_test.c +++ b/tests/ownCloud/mocka/ocmod_test.c @@ -158,10 +158,11 @@ static void teardown_toplevel_dir( void **state ) { static void stat_local_file( csync_stat_t *sb, const char *file ) { - const _TCHAR *mpath = NULL; + _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 diff --git a/tests/std_tests/check_std_c_str.c b/tests/std_tests/check_std_c_str.c index 1c544b66cb..80c1270fc2 100644 --- a/tests/std_tests/check_std_c_str.c +++ b/tests/std_tests/check_std_c_str.c @@ -1,6 +1,7 @@ #include #include #include +#include #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);