From 183f16c386636fcab18fdc8bc07cf1acd3155dbb Mon Sep 17 00:00:00 2001
From: Andreas Schneider <mail@cynapses.org>
Date: Wed, 18 Jun 2008 13:16:45 +0200
Subject: [PATCH] Add a function to merge the trees.

This is needed to be able to write a complete journal.
---
 src/csync.c      |  26 ++++++----
 src/csync_util.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++
 src/csync_util.h |   2 +
 3 files changed, 141 insertions(+), 10 deletions(-)

diff --git a/src/csync.c b/src/csync.c
index 715def171..c5947ccd1 100644
--- a/src/csync.c
+++ b/src/csync.c
@@ -460,17 +460,23 @@ int csync_destroy(CSYNC *ctx) {
   if (ctx->journal.db != NULL) {
     /* and we have successfully synchronized */
     if (ctx->status >= CSYNC_STATUS_DONE) {
-      clock_gettime(CLOCK_REALTIME, &start);
-      /* write the journal to disk */
-      if (csync_journal_write(ctx) == 0) {
-        jwritten = 1;
-        clock_gettime(CLOCK_REALTIME, &finish);
-        CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
-            "Writing the journal to disk took %.2f seconds",
-            c_secdiff(finish, start));
-      } else {
-        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to write journal: %s",
+      /* merge trees */
+      if (csync_merge_file_trees(ctx) < 0) {
+        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to merge trees: %s",
             strerror(errno));
+      } else {
+        clock_gettime(CLOCK_REALTIME, &start);
+        /* write the journal to disk */
+        if (csync_journal_write(ctx) == 0) {
+          jwritten = 1;
+          clock_gettime(CLOCK_REALTIME, &finish);
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
+              "Writing the journal of %llu files to disk took %.2f seconds",
+              c_rbtree_size(ctx->local.tree), c_secdiff(finish, start));
+        } else {
+          CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to write journal: %s",
+              strerror(errno));
+        }
       }
     }
     csync_journal_close(ctx, ctx->journal.file, jwritten);
diff --git a/src/csync_util.c b/src/csync_util.c
index 841c0bc17..ee71252f6 100644
--- a/src/csync_util.c
+++ b/src/csync_util.c
@@ -20,7 +20,14 @@
  * vim: ts=2 sw=2 et cindent
  */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+
 #include "csync_util.h"
+#include "vio/csync_vio.h"
 
 #define CSYNC_LOG_CATEGORY_NAME "csync.util"
 #include "csync_log.h"
@@ -91,3 +98,119 @@ void csync_memstat_check(void) {
                  m.size * 4, m.resident * 4, m.shared * 4);
 }
 
+static int _merge_file_trees_visitor(void *obj, void *data) {
+  csync_file_stat_t *fs = NULL;
+  csync_vio_file_stat_t *vst = NULL;
+
+  CSYNC *ctx = NULL;
+  c_rbnode_t *node = NULL;
+
+  char *uri = NULL;
+  int rc = -1;
+
+  fs = (csync_file_stat_t *) obj;
+  ctx = (CSYNC *) data;
+
+  /* search for UPDATED file */
+  if (fs->instruction != CSYNC_INSTRUCTION_UPDATED) {
+    rc = 0;
+    goto out;
+  }
+
+  /* check if the file is new or has been synced */
+  node = c_rbtree_find(ctx->local.tree, (void *) fs->phash);
+  if (node == NULL) {
+    csync_file_stat_t *new = NULL;
+
+    new = c_malloc(sizeof(csync_file_stat_t) + fs->pathlen + 1);
+    if (new == NULL) {
+      rc = -1;
+      goto out;
+    }
+    new = memcpy(new, fs, sizeof(csync_file_stat_t) + fs->pathlen + 1);
+
+    if (c_rbtree_insert(ctx->local.tree, new) < 0) {
+      SAFE_FREE(new);
+      rc = -1;
+      goto out;
+    }
+
+    node = c_rbtree_find(ctx->local.tree, (void *) fs->phash);
+    if (node == NULL) {
+      rc = -1;
+      goto out;
+    }
+  }
+  fs = c_rbtree_node_data(node);
+
+  switch (ctx->current) {
+    case LOCAL_REPLICA:
+      if (asprintf(&uri, "%s/%s", ctx->local.uri, fs->path) < 0) {
+        rc =-1;
+        goto out;
+      }
+      break;
+    case REMOTE_REPLCIA:
+      if (asprintf(&uri, "%s/%s", ctx->remote.uri, fs->path) < 0) {
+        rc = -1;
+        goto out;
+      }
+      break;
+    default:
+      break;
+  }
+
+  /* get file stat of the file on local replica */
+  vst = csync_vio_file_stat_new();
+  if (csync_vio_stat(ctx, uri, vst) < 0) {
+    rc = -1;
+    goto out;
+  }
+
+  /* update file stat */
+  fs->inode = vst->inode;
+  fs->modtime = vst->mtime;
+
+  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: UPDATED", uri);
+
+  rc = 0;
+out:
+  csync_vio_file_stat_destroy(vst);
+  SAFE_FREE(uri);
+
+  return rc;
+}
+
+/*
+ * merge the local tree with the new files from remote and update the
+ * inode numbers
+ */
+int csync_merge_file_trees(CSYNC *ctx) {
+  int rc = -1;
+
+  /* walk over remote tree, stat on local system */
+  ctx->current = LOCAL_REPLICA;
+  ctx->replica = ctx->local.type;
+
+  rc = c_rbtree_walk(ctx->remote.tree, ctx, _merge_file_trees_visitor);
+  if (rc < 0) {
+    goto out;
+  }
+
+#if 0
+  /* We don't have to merge the remote tree atm. */
+
+  /* walk over local tree, stat on remote system */
+  ctx->current = REMOTE_REPLICA;
+  ctx->replica = ctx->remote.type;
+
+  rc = c_rbtree_walk(ctx->local.tree, ctx, _merge_file_trees_visitor);
+  if (rc < 0) {
+    goto out;
+  }
+#endif
+
+out:
+  return rc;
+}
+
diff --git a/src/csync_util.h b/src/csync_util.h
index cbbd9a462..cff1ef777 100644
--- a/src/csync_util.h
+++ b/src/csync_util.h
@@ -29,4 +29,6 @@ const char *csync_instruction_str(enum csync_instructions_e instr);
 
 void csync_memstat_check(void);
 
+int csync_merge_file_trees(CSYNC *ctx);
+
 #endif /* _CSYNC_UTIL_H */