csync_vio_local: merge readdir and stat in the same call
authorOlivier Goffart <ogoffart@woboq.com>
Fri, 22 Sep 2017 07:51:22 +0000 (09:51 +0200)
committerRoeland Jago Douma <roeland@famdouma.nl>
Thu, 5 Oct 2017 20:01:35 +0000 (22:01 +0200)
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.

src/csync/csync_update.cpp
src/csync/vio/csync_vio.cpp
src/csync/vio/csync_vio.h
src/csync/vio/csync_vio_local_unix.cpp
src/csync/vio/csync_vio_local_win.cpp

index 0c2d9d384f81eeb47766494385cc976e8d2137af..ffe00d59adffe4543cef356376b68871118c49b6 100644 (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
index 3f898c63a538a43d5a61b4329271f50072795a2b..611fb111b0dc48c18f6d74bd5e9229eff000e74f 100644 (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;
index 62522950bcbaa70b9273ed9dd3863516f82a328e..7d3a2e0b4eea37b3538eda7e9198d8285b02596c 100644 (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);
 
 
index 5223878a135a060e8bbf25a1738fc3f28ddc1347..b60fe99cecb5a97c497506b55baf771bcf329f7e 100644 (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;
+}
+
+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;
 }
index 435ad87d62195277b19fb0e669a612895b0cfdd8..588575ed1b0cb37f4982aa3c893b8efac09444eb 100644 (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;
       }
   }
+  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_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;
 }