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.
This commit is contained in:
Olivier Goffart 2017-09-22 09:51:22 +02:00 committed by Roeland Jago Douma
parent dc0a0841fa
commit b19677ea97
No known key found for this signature in database
GPG Key ID: F941078878347C0C
5 changed files with 81 additions and 70 deletions

View File

@ -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

View File

@ -24,7 +24,6 @@
#include <errno.h>
#include <stdio.h>
#include <QLoggingCategory>
#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_file_stat_t> 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;

View File

@ -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_file_stat_t> 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);

View File

@ -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_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
dhandle_t *handle = NULL;
@ -93,17 +94,17 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *d
struct _tdirent *dirent = NULL;
std::unique_ptr<csync_file_stat_t> 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<const char *>(handle->path) % '/' % QByteArray() % const_cast<const char *>(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_file_stat_t> 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;
}

View File

@ -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_file_stat_t> 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_file_stat_t> 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;
}