diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp index 0c2d9d384f..ffe00d59ad 100644 --- a/src/csync/csync_update.cpp +++ b/src/csync/csync_update.cpp @@ -565,16 +565,10 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, continue; } - fullpath = uri; - if (!fullpath.isEmpty()) - fullpath += '/'; - fullpath += filename; - /* Only for the local replica we have to stat(), for the remote one we have all data already */ - if (ctx->current == LOCAL_REPLICA) { - if (csync_vio_stat(ctx, fullpath, dirent.get()) != 0) { - // Will get excluded by _csync_detect_update. - dirent->type = CSYNC_FTW_TYPE_SKIP; - } + if (uri[0] == '\0') { + fullpath = filename; + } else { + fullpath = QByteArray() % uri % '/' % filename; } /* if the filename starts with a . we consider it a hidden file diff --git a/src/csync/vio/csync_vio.cpp b/src/csync/vio/csync_vio.cpp index 3f898c63a5..611fb111b0 100644 --- a/src/csync/vio/csync_vio.cpp +++ b/src/csync/vio/csync_vio.cpp @@ -24,7 +24,6 @@ #include #include -#include #include "common/asserts.h" #include "csync_private.h" @@ -34,8 +33,6 @@ #include "csync_statedb.h" #include "common/c_jhash.h" -Q_LOGGING_CATEGORY(lcVio, "sync.csync.vio", QtInfoMsg) - csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) { switch(ctx->current) { case REMOTE_REPLICA: @@ -94,17 +91,6 @@ std::unique_ptr csync_vio_readdir(CSYNC *ctx, csync_vio_handl return NULL; } -int csync_vio_stat(CSYNC *ctx, const char *uri, csync_file_stat_t *buf) { - int rc = -1; - - ASSERT(ctx->current == LOCAL_REPLICA); - rc = csync_vio_local_stat(uri, buf); - if (rc < 0) - qCWarning(lcVio, "Local stat failed, errno %d for %s", errno, uri); - - return rc; -} - char *csync_vio_get_status_string(CSYNC *ctx) { if(ctx->error_string) { return ctx->error_string; diff --git a/src/csync/vio/csync_vio.h b/src/csync/vio/csync_vio.h index 62522950bc..7d3a2e0b4e 100644 --- a/src/csync/vio/csync_vio.h +++ b/src/csync/vio/csync_vio.h @@ -36,8 +36,6 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name); int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle); std::unique_ptr csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle); -int csync_vio_stat(CSYNC *ctx, const char *uri, csync_file_stat_t *buf); - char *csync_vio_get_status_string(CSYNC *ctx); diff --git a/src/csync/vio/csync_vio_local_unix.cpp b/src/csync/vio/csync_vio_local_unix.cpp index 5223878a13..b60fe99cec 100644 --- a/src/csync/vio/csync_vio_local_unix.cpp +++ b/src/csync/vio/csync_vio_local_unix.cpp @@ -45,6 +45,8 @@ typedef struct dhandle_s { char *path; } dhandle_t; +static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf); + csync_vio_handle_t *csync_vio_local_opendir(const char *name) { dhandle_t *handle = NULL; mbchar_t *dirname = NULL; @@ -84,7 +86,6 @@ int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { return rc; } - std::unique_ptr csync_vio_local_readdir(csync_vio_handle_t *dhandle) { dhandle_t *handle = NULL; @@ -93,17 +94,17 @@ std::unique_ptr csync_vio_local_readdir(csync_vio_handle_t *d struct _tdirent *dirent = NULL; std::unique_ptr file_stat; - dirent = _treaddir(handle->dh); - if (dirent == NULL) { - return {}; - } + do { + dirent = _treaddir(handle->dh); + if (dirent == NULL) + return {}; + } while (qstrcmp(dirent->d_name, ".") == 0 || qstrcmp(dirent->d_name, "..") == 0); file_stat.reset(new csync_file_stat_t); file_stat->path = c_utf8_from_locale(dirent->d_name); + QByteArray fullPath = QByteArray() % const_cast(handle->path) % '/' % QByteArray() % const_cast(dirent->d_name); if (file_stat->path.isNull()) { - file_stat->original_path = handle->path; - file_stat->original_path += '/'; - file_stat->original_path += dirent->d_name; + file_stat->original_path = fullPath; CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Invalid characters in file/directory name, please rename: \"%s\" (%s)", dirent->d_name, handle->path); } @@ -129,23 +130,35 @@ std::unique_ptr csync_vio_local_readdir(csync_vio_handle_t *d } #endif + if (file_stat->path.isNull()) + return file_stat; + + if (_csync_vio_local_stat_mb(fullPath.constData(), file_stat.get()) < 0) { + // Will get excluded by _csync_detect_update. + file_stat->type = CSYNC_FTW_TYPE_SKIP; + } return file_stat; } -int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) { - csync_stat_t sb; - - mbchar_t *wuri = c_utf8_path_to_locale( uri ); - - if( _tstat(wuri, &sb) < 0) { +int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) +{ + mbchar_t *wuri = c_utf8_path_to_locale(uri); + *buf = csync_file_stat_t(); + int rc = _csync_vio_local_stat_mb(wuri, buf); c_free_locale_string(wuri); - return -1; - } + return rc; +} - *buf = csync_file_stat_t(); +static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf) +{ + csync_stat_t sb; - switch(sb.st_mode & S_IFMT) { + if (_tstat(wuri, &sb) < 0) { + return -1; + } + + switch (sb.st_mode & S_IFMT) { case S_IFDIR: buf->type = CSYNC_FTW_TYPE_DIR; break; @@ -170,7 +183,5 @@ int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) { buf->inode = sb.st_ino; buf->modtime = sb.st_mtime; buf->size = sb.st_size; - - c_free_locale_string(wuri); return 0; } diff --git a/src/csync/vio/csync_vio_local_win.cpp b/src/csync/vio/csync_vio_local_win.cpp index 435ad87d62..588575ed1b 100644 --- a/src/csync/vio/csync_vio_local_win.cpp +++ b/src/csync/vio/csync_vio_local_win.cpp @@ -45,9 +45,11 @@ typedef struct dhandle_s { WIN32_FIND_DATA ffd; HANDLE hFind; int firstFind; - char *path; + mbchar_t *path; // Always ends with '\' } dhandle_t; +static int _csync_vio_local_stat_mb(const mbchar_t *uri, csync_file_stat_t *buf); + csync_vio_handle_t *csync_vio_local_opendir(const char *name) { dhandle_t *handle = NULL; mbchar_t *dirname = NULL; @@ -73,6 +75,7 @@ csync_vio_handle_t *csync_vio_local_opendir(const char *name) { } if (!dirname || handle->hFind == INVALID_HANDLE_VALUE) { + c_free_locale_string(dirname); int retcode = GetLastError(); if( retcode == ERROR_FILE_NOT_FOUND ) { errno = ENOENT; @@ -85,8 +88,8 @@ csync_vio_handle_t *csync_vio_local_opendir(const char *name) { handle->firstFind = 1; // Set a flag that there first fileinfo is available. - handle->path = c_strdup(name); - c_free_locale_string(dirname); + dirname[std::wcslen(dirname) - 1] = L'\0'; // remove the * + handle->path = dirname; return (csync_vio_handle_t *) handle; } @@ -109,7 +112,7 @@ int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { errno = EBADF; } - SAFE_FREE(handle->path); + c_free_locale_string(handle->path); SAFE_FREE(handle); return rc; @@ -158,20 +161,24 @@ std::unique_ptr csync_vio_local_readdir(csync_vio_handle_t *d return nullptr; } } - file_stat.reset(new csync_file_stat_t); - file_stat->path = c_utf8_from_locale(handle->ffd.cFileName); + auto path = c_utf8_from_locale(handle->ffd.cFileName); + if (path == "." || path == "..") + return csync_vio_local_readdir(dhandle); - if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - // Detect symlinks, and treat junctions as symlinks too. - if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK - || handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) { - file_stat->type = CSYNC_FTW_TYPE_SLINK; - } else { - // The SIS and DEDUP reparse points should be treated as - // regular files. We don't know about the other ones yet, - // but will also treat them normally for now. - file_stat->type = CSYNC_FTW_TYPE_FILE; - } + file_stat.reset(new csync_file_stat_t); + file_stat->path = path; + + if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + // Detect symlinks, and treat junctions as symlinks too. + if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK + || handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) { + file_stat->type = CSYNC_FTW_TYPE_SLINK; + } else { + // The SIS and DEDUP reparse points should be treated as + // regular files. We don't know about the other ones yet, + // but will also treat them normally for now. + file_stat->type = CSYNC_FTW_TYPE_FILE; + } } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) { @@ -189,12 +196,31 @@ std::unique_ptr csync_vio_local_readdir(csync_vio_handle_t *d file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow; file_stat->modtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem); + + std::wstring fullPath; + fullPath.reserve(std::wcslen(handle->path) + std::wcslen(handle->ffd.cFileName)); + fullPath += handle->path; // path always ends with '\', by construction + fullPath += handle->ffd.cFileName; + + if (_csync_vio_local_stat_mb(fullPath.data(), file_stat.get()) < 0) { + // Will get excluded by _csync_detect_update. + file_stat->type = CSYNC_FTW_TYPE_SKIP; + } + return file_stat; } +int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) +{ + mbchar_t *wuri = c_utf8_path_to_locale(uri); + int rc = _csync_vio_local_stat_mb(wuri, buf); + c_free_locale_string(wuri); + return rc; +} -int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) { +static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf) +{ /* Almost nothing to do since csync_vio_local_readdir already filled up most of the information But we still need to fetch the file ID. Possible optimisation: only fetch the file id when we need it (for new files) @@ -203,23 +229,20 @@ int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) { HANDLE h; BY_HANDLE_FILE_INFORMATION fileInfo; ULARGE_INTEGER FileIndex; - mbchar_t *wuri = c_utf8_path_to_locale( uri ); h = CreateFileW( wuri, 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL ); if( h == INVALID_HANDLE_VALUE ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %s", uri ); + CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %ls", wuri); errno = GetLastError(); - c_free_locale_string(wuri); return -1; } if(!GetFileInformationByHandle( h, &fileInfo ) ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "GetFileInformationByHandle failed on %s", uri ); + CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "GetFileInformationByHandle failed on %ls", wuri); errno = GetLastError(); - c_free_locale_string(wuri); CloseHandle(h); return -1; } @@ -235,7 +258,6 @@ int csync_vio_local_stat(const char *uri, csync_file_stat_t *buf) { DWORD rem; buf->modtime = FileTimeToUnixTime(&fileInfo.ftLastWriteTime, &rem); - c_free_locale_string(wuri); CloseHandle(h); return 0; }