From: Olivier Goffart Date: Fri, 22 Sep 2017 07:51:22 +0000 (+0200) Subject: csync_vio_local: merge readdir and stat in the same call X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~701^2~57 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=b19677ea97f4d02fbe421fd9045ede065dd0ba46;p=nextcloud-desktop.git csync_vio_local: merge readdir and stat in the same call For the remote this was already done long time ago For windows, this was already partially done The goal is to avoid needless conversion of the path to local encoding. --- diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp index 0c2d9d384..ffe00d59a 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 3f898c63a..611fb111b 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 62522950b..7d3a2e0b4 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 5223878a1..b60fe99ce 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; +} + +static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf) +{ + csync_stat_t sb; - *buf = csync_file_stat_t(); + if (_tstat(wuri, &sb) < 0) { + return -1; + } - switch(sb.st_mode & S_IFMT) { + 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 435ad87d6..588575ed1 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; } } + auto path = c_utf8_from_locale(handle->ffd.cFileName); + if (path == "." || path == "..") + return csync_vio_local_readdir(dhandle); + file_stat.reset(new csync_file_stat_t); - file_stat->path = c_utf8_from_locale(handle->ffd.cFileName); - - 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->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; }