csync: Keep the csync_file_stat_t instances created during discovery
authorJocelyn Turcotte <jturcotte@woboq.com>
Thu, 17 Aug 2017 17:06:58 +0000 (19:06 +0200)
committerRoeland Jago Douma <roeland@famdouma.nl>
Thu, 5 Oct 2017 20:01:33 +0000 (22:01 +0200)
Now that they use the same structure, avoid _csync_detect_update
having to recreate another instance and transfer everything manually.
Any instance created during discovery should now be used all the way
up to SyncEngine::treewalkFile.

This also makes sure that the path and types are properly set in that
object instead of having to pass everything as separate parameters.

This gets rid of csync_ftw_flags_e which was now converted from,
and to csync_ftw_type_e, already in the csync_file_stat_t.

Issue #1817

src/csync/csync_update.cpp
src/csync/csync_update.h
test/csync/csync_tests/check_csync_update.cpp

index d3cdfab894dd3b187531617eedd7376daffbeff9..91afc8eb6437df535aa37ef4c3b1b04b7cd12b5e 100644 (file)
 #define __STDC_FORMAT_MACROS
 #include <inttypes.h>
 
-/* calculate the hash of a given uri */
-static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
-  const char *path;
-  int len;
-  uint64_t h = 0;
-
-  if( ctx && file ) {
-    path = file;
-    if (ctx->current == LOCAL_REPLICA) {
-      if (strlen(path) <= strlen(ctx->local.uri)) {
-        return 0;
-      }
-      path += strlen(ctx->local.uri) + 1;
-    }
-    len = strlen(path);
-    h = c_jhash64((uint8_t *) path, len, 0);
-  }
-  return h;
-}
-
 #ifdef NO_RENAME_EXTENSION
 /* Return true if the two path have the same extension. false otherwise. */
 static bool _csync_sameextension(const char *p1, const char *p2) {
@@ -96,6 +76,10 @@ static bool _last_db_return_error(CSYNC* ctx) {
     return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW;
 }
 
+static QByteArray _rel_to_abs(CSYNC* ctx, const QByteArray &relativePath) {
+    return QByteArray() % const_cast<const char *>(ctx->local.uri) % '/' % relativePath;
+}
+
 /* Return true if two mtime are considered equal
  * We consider mtime that are one hour difference to be equal if they are one hour appart
  * because on some system (FAT) the date is changing when the daylight saving is changing */
@@ -124,34 +108,21 @@ static bool _csync_mtime_equal(time_t a, time_t b)
  *
  * See doc/dev/sync-algorithm.md for an overview.
  */
-static int _csync_detect_update(CSYNC *ctx, const char *file,
-    const csync_file_stat_t *fs, enum csync_ftw_type_e type) {
-  uint64_t h = 0;
-  const char *path = NULL;
-  std::unique_ptr<csync_file_stat_t> st;
+static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs) {
   std::unique_ptr<csync_file_stat_t> tmp;
   CSYNC_EXCLUDE_TYPE excluded;
 
-  if ((file == NULL) || (fs == NULL)) {
+  if (fs == NULL) {
     errno = EINVAL;
     ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
     return -1;
   }
 
-  path = file;
-  if (ctx->current == LOCAL_REPLICA) {
-      if (strlen(path) <= strlen(ctx->local.uri)) {
-        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
-        return -1;
-      }
-      path += strlen(ctx->local.uri) + 1;
-  }
-
-  if (type == CSYNC_FTW_TYPE_SKIP) {
+  if (fs->type == CSYNC_FTW_TYPE_SKIP) {
       excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
   } else {
     /* Check if file is excluded */
-    excluded = csync_excluded_traversal(ctx->excludes, path, type);
+    excluded = csync_excluded_traversal(ctx->excludes, fs->path, fs->type);
   }
 
   if( excluded == CSYNC_NOT_EXCLUDED ) {
@@ -160,12 +131,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
        * This code should probably be in csync_exclude, but it does not have the fs parameter.
        * Keep it here for now */
       if (ctx->ignore_hidden_files && (fs->is_hidden)) {
-          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", fs->path.constData());
           excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
       }
   } else {
       /* File is ignored because it's matched by a user- or system exclude pattern. */
-      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded  (%d)", path, excluded);
+      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded  (%d)", fs->path.constData(), excluded);
       if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
           return 1;
       }
@@ -175,26 +146,19 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
   }
 
   if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
-      if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) {
+      if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, fs->path)) {
           return 1;
       }
   }
 
-  h = _hash_of_file(ctx, file );
-  if( h == 0 ) {
-    return -1;
-  }
-
-  st.reset(new csync_file_stat_t);
-
-  if (type == CSYNC_FTW_TYPE_FILE ) {
+  if (fs->type == CSYNC_FTW_TYPE_FILE ) {
     if (fs->modtime == 0) {
-      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
+      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", fs->path.constData());
     }
   }
 
-  if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
-      st->instruction = CSYNC_INSTRUCTION_IGNORE;
+  if (excluded > CSYNC_NOT_EXCLUDED || fs->type == CSYNC_FTW_TYPE_SLINK) {
+      fs->instruction = CSYNC_INSTRUCTION_IGNORE;
       if (ctx->current_fs) {
           ctx->current_fs->has_ignored_files = true;
       }
@@ -208,14 +172,14 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
    * does not change on rename.
    */
   if (csync_get_statedb_exists(ctx)) {
-    tmp = csync_statedb_get_stat_by_hash(ctx, h);
+    tmp = csync_statedb_get_stat_by_hash(ctx, fs->phash);
 
     if(_last_db_return_error(ctx)) {
         ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
         return -1;
     }
 
-    if(tmp && tmp->phash == h ) { /* there is an entry in the database */
+    if(tmp && tmp->phash == fs->phash ) { /* there is an entry in the database */
         /* we have an update! */
         CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Database entry found, compare: %" PRId64 " <-> %" PRId64
                                             ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
@@ -224,11 +188,11 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
                   fs->etag.constData(), tmp->etag.constData(), (uint64_t) fs->inode, (uint64_t) tmp->inode,
                   (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm.constData(), tmp->remotePerm.constData(), tmp->has_ignored_files );
         if (ctx->current == REMOTE_REPLICA && fs->etag != tmp->etag) {
-            st->instruction = CSYNC_INSTRUCTION_EVAL;
+            fs->instruction = CSYNC_INSTRUCTION_EVAL;
 
             // Preserve the EVAL flag later on if the type has changed.
             if (tmp->type != fs->type) {
-                st->child_modified = true;
+                fs->child_modified = true;
             }
 
             goto out;
@@ -240,57 +204,57 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
 
             // Checksum comparison at this stage is only enabled for .eml files,
             // check #4754 #4755
-            bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
+            bool isEmlFile = csync_fnmatch("*.eml", fs->path, FNM_CASEFOLD) == 0;
             if (isEmlFile && fs->size == tmp->size && !tmp->checksumHeader.isEmpty()) {
                 if (ctx->callbacks.checksum_hook) {
-                    st->checksumHeader = ctx->callbacks.checksum_hook(
-                        file, tmp->checksumHeader,
+                    fs->checksumHeader = ctx->callbacks.checksum_hook(
+                        _rel_to_abs(ctx, fs->path), tmp->checksumHeader,
                         ctx->callbacks.checksum_userdata);
                 }
                 bool checksumIdentical = false;
-                if (!st->checksumHeader.isEmpty()) {
-                    checksumIdentical = st->checksumHeader == tmp->checksumHeader;
+                if (!fs->checksumHeader.isEmpty()) {
+                    checksumIdentical = fs->checksumHeader == tmp->checksumHeader;
                 }
                 if (checksumIdentical) {
-                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
-                    st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", fs->path.constData());
+                    fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
                     goto out;
                 }
             }
 
             // Preserve the EVAL flag later on if the type has changed.
             if (tmp->type != fs->type) {
-                st->child_modified = true;
+                fs->child_modified = true;
             }
 
-            st->instruction = CSYNC_INSTRUCTION_EVAL;
+            fs->instruction = CSYNC_INSTRUCTION_EVAL;
             goto out;
         }
         bool metadata_differ = (ctx->current == REMOTE_REPLICA && (fs->file_id != tmp->file_id
                                                             || fs->remotePerm != tmp->remotePerm))
                              || (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
-        if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
+        if (fs->type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
                 && !metadata_differ && ctx->read_remote_from_db) {
             /* If both etag and file id are equal for a directory, read all contents from
              * the database.
              * The metadata comparison ensure that we fetch all the file id or permission when
              * upgrading owncloud
              */
-            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
+            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", fs->path.constData());
             ctx->remote.read_from_db = true;
         }
         /* If it was remembered in the db that the remote dir has ignored files, store
          * that so that the reconciler can make advantage of.
          */
         if( ctx->current == REMOTE_REPLICA ) {
-            st->has_ignored_files = tmp->has_ignored_files;
+            fs->has_ignored_files = tmp->has_ignored_files;
         }
         if (metadata_differ) {
             /* file id or permissions has changed. Which means we need to update them in the DB. */
-            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
-            st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", fs->path.constData());
+            fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
         } else {
-            st->instruction = CSYNC_INSTRUCTION_NONE;
+            fs->instruction = CSYNC_INSTRUCTION_NONE;
         }
     } else {
         /* check if it's a file and has been renamed */
@@ -305,13 +269,13 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
             }
 
             // Default to NEW unless we're sure it's a rename.
-            st->instruction = CSYNC_INSTRUCTION_NEW;
+            fs->instruction = CSYNC_INSTRUCTION_NEW;
 
             bool isRename =
                 tmp && tmp->inode == fs->inode && tmp->type == fs->type
                     && (tmp->modtime == fs->modtime || fs->type == CSYNC_FTW_TYPE_DIR)
 #ifdef NO_RENAME_EXTENSION
-                    && _csync_sameextension(tmp->path, path)
+                    && _csync_sameextension(tmp->path, fs->path)
 #endif
                 ;
 
@@ -319,21 +283,21 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
             // Verify the checksum where possible
             if (isRename && !tmp->checksumHeader.isEmpty() && ctx->callbacks.checksum_hook
                 && fs->type == CSYNC_FTW_TYPE_FILE) {
-                st->checksumHeader = ctx->callbacks.checksum_hook(
-                    file, tmp->checksumHeader,
-                    ctx->callbacks.checksum_userdata);
-                if (!st->checksumHeader.isEmpty()) {
-                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader.constData(), tmp->checksumHeader.constData());
-                    isRename = st->checksumHeader == tmp->checksumHeader;
+                    fs->checksumHeader = ctx->callbacks.checksum_hook(
+                        _rel_to_abs(ctx, fs->path), tmp->checksumHeader,
+                        ctx->callbacks.checksum_userdata);
+                if (!fs->checksumHeader.isEmpty()) {
+                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", fs->path.constData(), fs->checksumHeader.constData(), tmp->checksumHeader.constData());
+                    isRename = fs->checksumHeader == tmp->checksumHeader;
                 }
             }
 
             if (isRename) {
                 CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
                 /* inode found so the file has been renamed */
-                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
+                fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                 if (fs->type == CSYNC_FTW_TYPE_DIR) {
-                    csync_rename_record(ctx, tmp->path, path);
+                    csync_rename_record(ctx, tmp->path, fs->path);
                 }
             }
             goto out;
@@ -349,28 +313,28 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
             if(tmp ) {                           /* tmp existing at all */
                 if (tmp->type != fs->type) {
                     CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "file types different is not!");
-                    st->instruction = CSYNC_INSTRUCTION_NEW;
+                    fs->instruction = CSYNC_INSTRUCTION_NEW;
                     goto out;
                 }
-                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path.constData(), file);
-                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
+                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s --> %s", tmp->path.constData(), fs->path.constData());
+                fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                 if (fs->type == CSYNC_FTW_TYPE_DIR) {
-                    csync_rename_record(ctx, tmp->path, path);
+                    csync_rename_record(ctx, tmp->path, fs->path);
                 } else {
                     if( tmp->etag != fs->etag ) {
                         /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */
                         /* File with different etag, don't do a rename, but download the file again */
-                        st->instruction = CSYNC_INSTRUCTION_NEW;
+                        fs->instruction = CSYNC_INSTRUCTION_NEW;
                     }
                 }
                 goto out;
 
             } else {
                 /* file not found in statedb */
-                st->instruction = CSYNC_INSTRUCTION_NEW;
+                fs->instruction = CSYNC_INSTRUCTION_NEW;
 
                 if (fs->type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
-                    if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
+                    if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, fs->path, fs->remotePerm)) {
                         return 1;
                     }
                 }
@@ -387,66 +351,47 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
 out:
 
   /* Set the ignored error string. */
-  if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
-      if( type == CSYNC_FTW_TYPE_SLINK ) {
-          st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
+  if (fs->instruction == CSYNC_INSTRUCTION_IGNORE) {
+      if( fs->type == CSYNC_FTW_TYPE_SLINK ) {
+          fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
       } else {
           if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
           } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS;  /* File contains invalid characters. */
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS;  /* File contains invalid characters. */
           } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */
           } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
           } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
           } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
           } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) {
-              st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE;
+              fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE;
           }
       }
   }
-  if (st->instruction != CSYNC_INSTRUCTION_NONE
-      && st->instruction != CSYNC_INSTRUCTION_IGNORE
-      && st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
-      && type != CSYNC_FTW_TYPE_DIR) {
-    st->child_modified = true;
+  if (fs->instruction != CSYNC_INSTRUCTION_NONE
+      && fs->instruction != CSYNC_INSTRUCTION_IGNORE
+      && fs->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
+      && fs->type != CSYNC_FTW_TYPE_DIR) {
+    fs->child_modified = true;
   }
-  ctx->current_fs = st.get();
-
-  st->inode = fs->inode;
-  st->size  = fs->size;
-  st->modtime = fs->modtime;
-  st->type  = type;
-  st->is_hidden = fs->is_hidden;
-  st->etag = fs->etag;
-  st->file_id = fs->file_id;
-  st->directDownloadUrl = fs->directDownloadUrl;
-  st->directDownloadCookies = fs->directDownloadCookies;
-  st->remotePerm = fs->remotePerm;
-
-  // For the remote: propagate the discovered checksum
-  if (ctx->current == REMOTE_REPLICA) {
-      st->checksumHeader = fs->checksumHeader;
-  }
-
-  st->phash = h;
-  st->path = path;
+  ctx->current_fs = fs.get();
 
-  CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", st->path.constData(),
-      csync_instruction_str(st->instruction));
+  CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", fs->path.constData(),
+      csync_instruction_str(fs->instruction));
 
   switch (ctx->current) {
     case LOCAL_REPLICA:
-      if (c_rbtree_insert(ctx->local.tree, (void *) st.release()) < 0) {
+      if (c_rbtree_insert(ctx->local.tree, (void *) fs.release()) < 0) {
         ctx->status_code = CSYNC_STATUS_TREE_ERROR;
         return -1;
       }
       break;
     case REMOTE_REPLICA:
-      if (c_rbtree_insert(ctx->remote.tree, (void *) st.release()) < 0) {
+      if (c_rbtree_insert(ctx->remote.tree, (void *) fs.release()) < 0) {
         ctx->status_code = CSYNC_STATUS_TREE_ERROR;
         return -1;
       }
@@ -458,12 +403,8 @@ out:
   return 0;
 }
 
-int csync_walker(CSYNC *ctx, const char *file, const csync_file_stat_t *fs,
-    int flag) {
+int csync_walker(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs) {
   int rc = -1;
-  enum csync_ftw_type_e type = CSYNC_FTW_TYPE_SKIP;
-  std::unique_ptr<csync_file_stat_t> st;
-  uint64_t h;
 
   if (ctx->abort) {
     CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
@@ -471,51 +412,30 @@ int csync_walker(CSYNC *ctx, const char *file, const csync_file_stat_t *fs,
     return -1;
   }
 
-  switch (flag) {
-    case CSYNC_FTW_FLAG_FILE:
+  switch (fs->type) {
+    case CSYNC_FTW_TYPE_FILE:
       if (ctx->current == REMOTE_REPLICA) {
-          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id.constData(), fs->size);
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", fs->path.constData(), fs->file_id.constData(), fs->size);
       } else {
-          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size);
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", fs->path.constData(), fs->inode, fs->size);
       }
-      type = CSYNC_FTW_TYPE_FILE;
       break;
-  case CSYNC_FTW_FLAG_DIR: /* enter directory */
+  case CSYNC_FTW_TYPE_DIR: /* enter directory */
       if (ctx->current == REMOTE_REPLICA) {
-          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id.constData());
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", fs->path.constData(), fs->file_id.constData());
       } else {
-          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode);
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", fs->path.constData(), fs->inode);
       }
-      type = CSYNC_FTW_TYPE_DIR;
       break;
-  case CSYNC_FTW_FLAG_NSTAT: /* not statable file */
-    /* if file was here before and now is not longer stat-able, still
-     * add it to the db, otherwise not. */
-    h = _hash_of_file( ctx, file );
-    if( h == 0 ) {
-      return 0;
-    }
-    st = csync_statedb_get_stat_by_hash(ctx, h);
-    if( !st ) {
-      return 0;
-    }
-    st.reset();
-
-    type = CSYNC_FTW_TYPE_SKIP;
-    break;
-  case CSYNC_FTW_FLAG_SLINK:
-    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file);
-    type = CSYNC_FTW_TYPE_SLINK;
+  case CSYNC_FTW_TYPE_SLINK:
+    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", fs->path.constData());
     break;
-  case CSYNC_FTW_FLAG_DNR:
-  case CSYNC_FTW_FLAG_DP:
-  case CSYNC_FTW_FLAG_SLN:
   default:
     return 0;
     break;
   }
 
-  rc = _csync_detect_update(ctx, file, fs, type );
+  rc = _csync_detect_update(ctx, std::move(fs));
 
   return rc;
 }
@@ -554,13 +474,12 @@ static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_f
 int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
     unsigned int depth) {
   QByteArray filename;
-  QByteArray d_name;
+  QByteArray fullpath;
   csync_vio_handle_t *dh = NULL;
   std::unique_ptr<csync_file_stat_t> dirent;
   csync_file_stat_t *previous_fs = NULL;
   int read_from_db = 0;
   int rc = 0;
-  int res = 0;
 
   bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
 
@@ -628,8 +547,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
   }
 
   while ((dirent = csync_vio_readdir(ctx, dh))) {
-    int flag;
-
     /* Conversion error */
     if (dirent->path.isEmpty() && !dirent->original_path.isEmpty()) {
         ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
@@ -638,65 +555,58 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
         goto error;
     }
 
-    d_name = dirent->path;
-    if (d_name.isEmpty()) {
+    // At this point dirent->path only contains the file name.
+    filename = dirent->path;
+    if (filename.isEmpty()) {
       ctx->status_code = CSYNC_STATUS_READDIR_ERROR;
       goto error;
     }
 
     /* skip "." and ".." */
-    if ( d_name == "." || d_name == "..") {
-      dirent.reset();
+    if ( filename == "." || filename == "..") {
       continue;
     }
 
-    if (uri[0] == '\0') {
-      filename = d_name;
-    } else {
-      /* For the local replica, dirent->path only contains the file name */
-      filename = uri;
-      filename += '/';
-      filename += d_name;
-    }
-
+    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) {
-        res = csync_vio_stat(ctx, filename, dirent.get());
-    } else {
-        res = 0;
+        if (csync_vio_stat(ctx, fullpath, dirent.get()) != 0) {
+            // Will get excluded by _csync_detect_update.
+            dirent->type = CSYNC_FTW_TYPE_SKIP;
+        }
     }
 
     /* if the filename starts with a . we consider it a hidden file
      * For windows, the hidden state is also discovered within the vio
      * local stat function.
      */
-    if( d_name[0] == '.' ) {
-        if (d_name == ".sys.admin#recall#") { /* recall file shall not be ignored (#4420) */
+    if( filename[0] == '.' ) {
+        if (filename == ".sys.admin#recall#") { /* recall file shall not be ignored (#4420) */
             dirent->is_hidden = true;
         }
     }
 
-    flag = CSYNC_FTW_FLAG_NSTAT;
-    if( res == 0) {
-      switch (dirent->type) {
-        case CSYNC_FTW_TYPE_SLINK:
-          flag = CSYNC_FTW_FLAG_SLINK;
-          break;
-        case CSYNC_FTW_TYPE_DIR:
-          flag = CSYNC_FTW_FLAG_DIR;
-          break;
-        case CSYNC_FTW_TYPE_FILE:
-          flag = CSYNC_FTW_FLAG_FILE;
-          break;
-        default:
-          break;
-      };
+    // Now process to have a relative path to the sync root for the local replica, or to the data root on the remote.
+    dirent->path = fullpath;
+    if (ctx->current == LOCAL_REPLICA) {
+        if (dirent->path.size() <= (int)strlen(ctx->local.uri)) {
+            ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
+            goto error;
+        }
+        // "len + 1" to include the slash in-between.
+        dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1);
     }
+    // We calculate the phash using the relative path.
+    dirent->phash = c_jhash64((const uint8_t*)dirent->path.constData(), dirent->path.size(), 0);
 
     previous_fs = ctx->current_fs;
+    bool recurse = dirent->type == CSYNC_FTW_TYPE_DIR;
 
     /* Call walker function for each file */
-    rc = fn(ctx, filename, dirent.get(), flag);
+    rc = fn(ctx, std::move(dirent));
     /* this function may update ctx->current and ctx->read_from_db */
 
     if (rc < 0) {
@@ -708,9 +618,9 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
       goto error;
     }
 
-    if (flag == CSYNC_FTW_FLAG_DIR && rc == 0
+    if (recurse && rc == 0
         && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) {
-      rc = csync_ftw(ctx, filename, fn, depth - 1);
+      rc = csync_ftw(ctx, fullpath, fn, depth - 1);
       if (rc < 0) {
         ctx->current_fs = previous_fs;
         goto error;
@@ -738,7 +648,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
 
     ctx->current_fs = previous_fs;
     ctx->remote.read_from_db = read_from_db;
-    dirent.reset();
   }
 
   csync_vio_closedir(ctx, dh);
index b1de56dee04d08bf95dcb13de997d3668f23cfd3..1b4c50995cbbbdab8fc34824f30996911a6d7d46 100644 (file)
  * @{
  */
 
-/**
- * Types for files
- */
-enum csync_ftw_flags_e {
-  CSYNC_FTW_FLAG_FILE,         /* Regular file.  */
-  CSYNC_FTW_FLAG_DIR,          /* Directory.  */
-  CSYNC_FTW_FLAG_DNR,          /* Unreadable directory.  */
-  CSYNC_FTW_FLAG_NSTAT,                /* Unstatable file.  */
-  CSYNC_FTW_FLAG_SLINK,                /* Symbolic link.  */
-  /* These flags are only passed from the `nftw' function.  */
-  CSYNC_FTW_FLAG_DP,           /* Directory, all subdirs have been visited. */
-  CSYNC_FTW_FLAG_SLN           /* Symbolic link naming non-existing file.  */
-};
-
-typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file,
-    const csync_file_stat_t *fs, int flag);
+typedef int (*csync_walker_fn) (CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs);
 
 /**
  * @brief The walker function to use in the file tree walker.
@@ -67,7 +52,7 @@ typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file,
  *
  * @return 0 on success, < 0 on error.
  */
-int csync_walker(CSYNC *ctx, const char *file, const csync_file_stat_t *fs, int flag);
+int csync_walker(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs);
 
 /**
  * @brief The file tree walker.
index 184f6877e44a9d6e55ffd0d1761b1b36752f2b1a..f8329465fdbd9b677cc7216363d3f6feabe78137 100644 (file)
@@ -205,14 +205,10 @@ static std::unique_ptr<csync_file_stat_t> create_fstat(const char *name,
 }
 
 static int failing_fn(CSYNC *ctx,
-                      const char *file,
-                      const csync_file_stat_t *fs,
-                      int flag)
+                      std::unique_ptr<csync_file_stat_t> fs)
 {
   (void) ctx;
-  (void) file;
   (void) fs;
-  (void) flag;
 
   return -1;
 }
@@ -227,10 +223,7 @@ static void check_csync_detect_update(void **state)
 
     fs = create_fstat("file.txt", 0, 1217597845);
 
-    rc = _csync_detect_update(csync,
-                              "/tmp/check_csync1/file.txt",
-                              fs.get(),
-                              CSYNC_FTW_TYPE_FILE);
+    rc = _csync_detect_update(csync, std::move(fs));
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
@@ -253,10 +246,7 @@ static void check_csync_detect_update_db_none(void **state)
 
     fs = create_fstat("file.txt", 0, 1217597845);
 
-    rc = _csync_detect_update(csync,
-                              "/tmp/check_csync1/file.txt",
-                              fs.get(),
-                              CSYNC_FTW_TYPE_FILE);
+    rc = _csync_detect_update(csync, std::move(fs));
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
@@ -277,10 +267,7 @@ static void check_csync_detect_update_db_eval(void **state)
 
     fs = create_fstat("file.txt", 0, 42);
 
-    rc = _csync_detect_update(csync,
-                              "/tmp/check_csync1/file.txt",
-                              fs.get(),
-                              CSYNC_FTW_TYPE_FILE);
+    rc = _csync_detect_update(csync, std::move(fs));
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
@@ -303,10 +290,7 @@ static void check_csync_detect_update_db_rename(void **state)
     fs = create_fstat("wurst.txt", 0, 42);
     csync_set_statedb_exists(csync, 1);
 
-    rc = _csync_detect_update(csync,
-                              "/tmp/check_csync1/wurst.txt",
-                              fs.get(),
-                              CSYNC_FTW_TYPE_FILE);
+    rc = _csync_detect_update(csync, std::move(fs));
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to rename */
@@ -330,10 +314,7 @@ static void check_csync_detect_update_db_new(void **state)
 
     fs = create_fstat("file.txt", 42000, 0);
 
-    rc = _csync_detect_update(csync,
-                              "/tmp/check_csync1/file.txt",
-                              fs.get(),
-                              CSYNC_FTW_TYPE_FILE);
+    rc = _csync_detect_update(csync, std::move(fs));
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
@@ -351,18 +332,7 @@ static void check_csync_detect_update_null(void **state)
     std::unique_ptr<csync_file_stat_t> fs;
     int rc;
 
-    fs = create_fstat("file.txt", 0, 0);
-
-    rc = _csync_detect_update(csync,
-                              NULL,
-                              fs.get(),
-                              CSYNC_FTW_TYPE_FILE);
-    assert_int_equal(rc, -1);
-
-    rc = _csync_detect_update(csync,
-                              "/tmp/check_csync1/file.txt",
-                              NULL,
-                              CSYNC_FTW_TYPE_FILE);
+    rc = _csync_detect_update(csync, NULL);
     assert_int_equal(rc, -1);
 }