From f18b40f7e7890a659d20f1d3bbd3125a3089b612 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 22 Oct 2015 02:29:27 +0200 Subject: [PATCH] csync_vio: reuse the information from readdir in stat On unix we don't safe much (otherwise csync would have been designed differently). On windows however, the readdir already fetch all the info, so we can as well use it. We still have to query for the file id but we might optimize that later --- csync/src/csync.h | 3 +- csync/src/csync_update.c | 14 +- csync/src/vio/csync_vio_local_unix.c | 10 -- csync/src/vio/csync_vio_local_win.c | 152 ++++++++----------- csync/tests/csync_tests/check_csync_update.c | 1 - csync/tests/vio_tests/check_vio.c | 43 ------ 6 files changed, 68 insertions(+), 155 deletions(-) diff --git a/csync/src/csync.h b/csync/src/csync.h index c2e1afa6b..626c3eeed 100644 --- a/csync/src/csync.h +++ b/csync/src/csync.h @@ -173,7 +173,7 @@ enum csync_vio_file_stat_fields_e { CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0, CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2, - CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3, +// CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3, CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4, // CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5, CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6, @@ -212,7 +212,6 @@ struct csync_vio_file_stat_s { mode_t mode; - dev_t device; uint64_t inode; int fields; // actually enum csync_vio_file_stat_fields_e fields; diff --git a/csync/src/csync_update.c b/csync/src/csync_update.c index 4eb0457f7..779f83b59 100644 --- a/csync/src/csync_update.c +++ b/csync/src/csync_update.c @@ -580,7 +580,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, char *d_name = NULL; csync_vio_handle_t *dh = NULL; csync_vio_file_stat_t *dirent = NULL; - csync_vio_file_stat_t *fs = NULL; csync_file_stat_t *previous_fs = NULL; int read_from_db = 0; int rc = 0; @@ -737,15 +736,13 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, /* Only for the local replica we have to stat(), for the remote one we have all data already */ if (ctx->replica == LOCAL_REPLICA) { - fs = csync_vio_file_stat_new(); - res = csync_vio_stat(ctx, filename, fs); + res = csync_vio_stat(ctx, filename, dirent); } else { - fs = dirent; res = 0; } if( res == 0) { - switch (fs->type) { + switch (dirent->type) { case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK: flag = CSYNC_FTW_FLAG_SLINK; break; @@ -771,14 +768,9 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, previous_fs = ctx->current_fs; /* Call walker function for each file */ - rc = fn(ctx, filename, fs, flag); + rc = fn(ctx, filename, dirent, flag); /* this function may update ctx->current and ctx->read_from_db */ - /* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */ - if (ctx->replica == LOCAL_REPLICA) { - csync_vio_file_stat_destroy(fs); - } - if (rc < 0) { if (CSYNC_STATUS_IS_OK(ctx->status_code)) { ctx->status_code = CSYNC_STATUS_UPDATE_ERROR; diff --git a/csync/src/vio/csync_vio_local_unix.c b/csync/src/vio/csync_vio_local_unix.c index e72eb4fea..667c72e77 100644 --- a/csync/src/vio/csync_vio_local_unix.c +++ b/csync/src/vio/csync_vio_local_unix.c @@ -157,13 +157,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { return -1; } - buf->name = c_basename(uri); - - if (buf->name == NULL) { - csync_vio_file_stat_destroy(buf); - c_free_locale_string(wuri); - return -1; - } buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; switch(sb.st_mode & S_IFMT) { @@ -210,9 +203,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { #endif buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; - buf->device = sb.st_dev; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE; - buf->inode = sb.st_ino; buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; diff --git a/csync/src/vio/csync_vio_local_win.c b/csync/src/vio/csync_vio_local_win.c index 92298279e..80e122851 100644 --- a/csync/src/vio/csync_vio_local_win.c +++ b/csync/src/vio/csync_vio_local_win.c @@ -116,10 +116,31 @@ int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { return rc; } + +static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder) +{ + long long int t = filetime->dwHighDateTime; + t <<= 32; + t += (UINT32)filetime->dwLowDateTime; + t -= 116444736000000000LL; + if (t < 0) + { + if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; + return -1 - ((-t - 1) / 10000000); + } + else + { + if (remainder) *remainder = t % 10000000; + return t / 10000000; + } +} + csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { dhandle_t *handle = NULL; csync_vio_file_stat_t *file_stat = NULL; + ULARGE_INTEGER FileIndex; + DWORD rem; handle = (dhandle_t *) dhandle; @@ -148,13 +169,43 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { file_stat->name = c_utf8_from_locale(handle->ffd.cFileName); file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; - } else { - file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; - } + if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT + && handle->ffd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) { + file_stat->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; + file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; + } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE + || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE + || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) { + file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; + } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; + } else { + file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; + } + + file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE; + /* Check for the hidden flag */ + if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) { + file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; + } + + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - return file_stat; + file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow; + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; + + file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem); + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; + + file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem); + /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; + + file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem); + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; + + return file_stat; err: SAFE_FREE(file_stat); @@ -162,29 +213,16 @@ err: return NULL; } -static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder) -{ - long long int t = filetime->dwHighDateTime; - t <<= 32; - t += (UINT32)filetime->dwLowDateTime; - t -= 116444736000000000LL; - if (t < 0) - { - if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; - return -1 - ((-t - 1) / 10000000); - } - else - { - if (remainder) *remainder = t % 10000000; - return t / 10000000; - } -} + int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { - HANDLE h, hFind; - FILETIME ftCreate, ftAccess, ftWrite; + /* 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) + */ + + HANDLE h; BY_HANDLE_FILE_INFORMATION fileInfo; - WIN32_FIND_DATAW FindFileData; ULARGE_INTEGER FileIndex; mbchar_t *wuri = c_utf8_path_to_locale( uri ); @@ -205,47 +243,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { return -1; } - buf->flags = CSYNC_VIO_FILE_FLAGS_NONE; - do { - // Check first if it is a symlink (code from c_islink) - if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - hFind = FindFirstFileW(wuri, &FindFileData ); - if (hFind != INVALID_HANDLE_VALUE) { - if( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && - (FindFileData.dwReserved0 & IO_REPARSE_TAG_SYMLINK) ) { - buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; - buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; - break; - } - } - FindClose(hFind); - } - if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DEVICE - || fileInfo.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE - || fileInfo.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) { - buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; - break; - } - if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; - break; - } - // fallthrough: - buf->type = CSYNC_VIO_FILE_TYPE_REGULAR; - break; - } while (0); - - /* Check for the hidden flag */ - if( fileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) { - buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; - } - - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - - buf->device = fileInfo.dwVolumeSerialNumber; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE; - /* Get the Windows file id as an inode replacement. */ FileIndex.HighPart = fileInfo.nFileIndexHigh; FileIndex.LowPart = fileInfo.nFileIndexLow; @@ -253,28 +250,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { /* printf("Index: %I64i\n", FileIndex.QuadPart); */ buf->inode = FileIndex.QuadPart; - buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; - - /* Get the file time with a win32 call rather than through stat. See - * http://www.codeproject.com/Articles/1144/Beating-the-Daylight-Savings-Time-bug-and-getting - * for deeper explanation. - */ - if( GetFileTime(h, &ftCreate, &ftAccess, &ftWrite) ) { - DWORD rem; - buf->atime = FileTimeToUnixTime(&ftAccess, &rem); - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; - - buf->mtime = FileTimeToUnixTime(&ftWrite, &rem); - /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; - - buf->ctime = FileTimeToUnixTime(&ftCreate, &rem); - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; - } - c_free_locale_string(wuri); CloseHandle(h); - return 0; } diff --git a/csync/tests/csync_tests/check_csync_update.c b/csync/tests/csync_tests/check_csync_update.c index 0213440f1..ced053e40 100644 --- a/csync/tests/csync_tests/check_csync_update.c +++ b/csync/tests/csync_tests/check_csync_update.c @@ -201,7 +201,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name, } fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; - fs->device = 0; fs->size = 157459; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; diff --git a/csync/tests/vio_tests/check_vio.c b/csync/tests/vio_tests/check_vio.c index bf5e5994d..c8bc64183 100644 --- a/csync/tests/vio_tests/check_vio.c +++ b/csync/tests/vio_tests/check_vio.c @@ -164,46 +164,6 @@ static void check_csync_vio_readdir(void **state) } -/* - * Test for general functions (stat, chmod, chown, ...) - */ - -static void check_csync_vio_stat_dir(void **state) -{ - CSYNC *csync = *state; - csync_vio_file_stat_t *fs; - int rc; - - fs = csync_vio_file_stat_new(); - assert_non_null(fs); - - rc = csync_vio_stat(csync, CSYNC_TEST_DIR, fs); - assert_int_equal(rc, 0); - - assert_string_equal(fs->name, "csync_test"); - assert_int_equal(fs->type, CSYNC_VIO_FILE_TYPE_DIRECTORY); - - csync_vio_file_stat_destroy(fs); -} - -static void check_csync_vio_stat_file(void **state) -{ - CSYNC *csync = *state; - csync_vio_file_stat_t *fs; - int rc; - - fs = csync_vio_file_stat_new(); - assert_non_null(fs); - - rc = csync_vio_stat(csync, CSYNC_TEST_FILE, fs); - assert_int_equal(rc, 0); - - assert_string_equal(fs->name, "file.txt"); - assert_int_equal(fs->type, CSYNC_VIO_FILE_TYPE_REGULAR); - - csync_vio_file_stat_destroy(fs); -} - int torture_run_tests(void) { const UnitTest tests[] = { @@ -211,9 +171,6 @@ int torture_run_tests(void) unit_test_setup_teardown(check_csync_vio_opendir_perm, setup, teardown), unit_test(check_csync_vio_closedir_null), unit_test_setup_teardown(check_csync_vio_readdir, setup_dir, teardown), - - unit_test_setup_teardown(check_csync_vio_stat_dir, setup_dir, teardown), - unit_test_setup_teardown(check_csync_vio_stat_file, setup_file, teardown), }; return run_tests(tests); -- 2.30.2