csync_vio: reuse the information from readdir in stat
authorOlivier Goffart <ogoffart@woboq.com>
Thu, 22 Oct 2015 00:29:27 +0000 (02:29 +0200)
committerOlivier Goffart <ogoffart@woboq.com>
Thu, 22 Oct 2015 16:46:41 +0000 (18:46 +0200)
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
csync/src/csync_update.c
csync/src/vio/csync_vio_local_unix.c
csync/src/vio/csync_vio_local_win.c
csync/tests/csync_tests/check_csync_update.c
csync/tests/vio_tests/check_vio.c

index c2e1afa6b3b969319498224849bd45fa2728029e..626c3eeedc389a79d3e05754421249f4107979f5 100644 (file)
@@ -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;
index 4eb0457f726ca3f4e9b52f0a3888686cc94d471d..779f83b5954ba78cd5ad626972700d8540569972 100644 (file)
@@ -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;
index e72eb4feaa869be691fe8ccea3ce8d1d192604c5..667c72e777dbef19744a819448623c4eeabb96a3 100644 (file)
@@ -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;
 
index 92298279eb22e18a7693cd27030ea2feff340d52..80e1228514bcb7e8098f8761b03f9c80eda3b217 100644 (file)
@@ -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;
 }
index 0213440f1c406d99868ad85ac017a4490ffaf785..ced053e4042515771c460441181c4915894d6cef 100644 (file)
@@ -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;
index bf5e5994dbdd4105369f1124c71d5d3d23da27f4..c8bc641836cd8464f6fb9b32a819134fe9457aa1 100644 (file)
@@ -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);