Esempio n. 1
0
File: csync.c Progetto: gco/csync
int csync_update(CSYNC *ctx) {
  int rc = -1;
  struct timespec start, finish;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }

  ctx->status_code = CSYNC_STATUS_OK;

  csync_memstat_check();

  /* update detection for local replica */
  csync_gettime(&start);
  ctx->current = LOCAL_REPLICA;
  ctx->replica = ctx->local.type;

  rc = csync_ftw(ctx, ctx->local.uri, csync_walker, MAX_DEPTH);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
            "Update detection for local replica took %.2f seconds walking %zu files.",
            c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
  csync_memstat_check();

  if (rc < 0) {
    ctx->status_code = CSYNC_STATUS_TREE_ERROR;
    return -1;
  }

  /* update detection for remote replica */
  if( ! ctx->options.local_only_mode ) {
    csync_gettime(&start);
    ctx->current = REMOTE_REPLICA;
    ctx->replica = ctx->remote.type;

    rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);

    csync_gettime(&finish);

    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
              "Update detection for remote replica took %.2f seconds "
              "walking %zu files.",
              c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
    csync_memstat_check();

    if (rc < 0) {
      if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
      }

      return -1;
    }
  }
  ctx->status |= CSYNC_STATUS_UPDATE;

  return 0;
}
Esempio n. 2
0
int csync_reconcile(CSYNC *ctx) {
  int rc = -1;
  struct timespec start, finish;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->status_code = CSYNC_STATUS_OK;

  /* Reconciliation for local replica */
  csync_gettime(&start);

  ctx->current = LOCAL_REPLICA;
  ctx->replica = ctx->local.type;

  rc = csync_reconcile_updates(ctx);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "Reconciliation for local replica took %.2f seconds visiting %zu files.",
      c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));

  if (rc < 0) {
      if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR );
      }
      return -1;
  }

  /* Reconciliation for remote replica */
  csync_gettime(&start);

  ctx->current = REMOTE_REPLICA;
  ctx->replica = ctx->remote.type;

  rc = csync_reconcile_updates(ctx);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "Reconciliation for remote replica took %.2f seconds visiting %zu files.",
      c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));

  if (rc < 0) {
      if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = csync_errno_to_status(errno,  CSYNC_STATUS_RECONCILE_ERROR );
      }
      return -1;
  }

  ctx->status |= CSYNC_STATUS_RECONCILE;

  return 0;
}
Esempio n. 3
0
int csync_propagate(CSYNC *ctx) {
  int rc = -1;
  struct timespec start, finish;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->error_code = CSYNC_ERR_NONE;

  /* Reconciliation for local replica */
  csync_gettime(&start);

  ctx->current = LOCAL_REPLICA;
  ctx->replica = ctx->local.type;

  rc = csync_propagate_files(ctx);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "Propagation for local replica took %.2f seconds visiting %zu files.",
      c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));

  if (rc < 0) {
    ctx->error_code = CSYNC_ERR_PROPAGATE;
    return -1;
  }

  /* Reconciliation for local replica */
  csync_gettime(&start);

  ctx->current = REMOTE_REPLCIA;
  ctx->replica = ctx->remote.type;

  rc = csync_propagate_files(ctx);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "Propagation for remote replica took %.2f seconds visiting %zu files.",
      c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));

  if (rc < 0) {
    ctx->error_code = CSYNC_ERR_PROPAGATE;
    return -1;
  }

  ctx->status |= CSYNC_STATUS_PROPAGATE;

  return 0;
}
Esempio n. 4
0
/* reset all the list to empty.
 * used by csync_commit and csync_destroy */
static void _csync_clean_ctx(CSYNC *ctx)
{
    /* destroy the rbtrees */
    if (c_rbtree_size(ctx->local.tree) > 0) {
        c_rbtree_destroy(ctx->local.tree, _tree_destructor);
    }

    if (c_rbtree_size(ctx->remote.tree) > 0) {
        c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
    }

    csync_rename_destroy(ctx);

    /* free memory */
    c_rbtree_free(ctx->local.tree);
    c_rbtree_free(ctx->remote.tree);

    SAFE_FREE(ctx->statedb.file);
    SAFE_FREE(ctx->remote.root_perms);
}
Esempio n. 5
0
/* reset all the list to empty.
 * used by csync_commit and csync_destroy */
static void _csync_clean_ctx(CSYNC *ctx)
{
    c_list_t * walk;

    /* destroy the rbtrees */
    if (c_rbtree_size(ctx->local.tree) > 0) {
        c_rbtree_destroy(ctx->local.tree, _tree_destructor);
    }

    if (c_rbtree_size(ctx->remote.tree) > 0) {
        c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
    }

    csync_rename_destroy(ctx);

    for (walk = c_list_last(ctx->local.ignored_cleanup); walk != NULL; walk = c_list_prev(walk)) {
        SAFE_FREE(walk->data);
    }
    for (walk = c_list_last(ctx->remote.ignored_cleanup); walk != NULL; walk = c_list_prev(walk)) {
        SAFE_FREE(walk->data);
    }

    /* free memory */
    c_rbtree_free(ctx->local.tree);
    c_list_free(ctx->local.list);
    c_list_free(ctx->local.ignored_cleanup);
    c_rbtree_free(ctx->remote.tree);
    c_list_free(ctx->remote.list);
    c_list_free(ctx->remote.ignored_cleanup);

    ctx->remote.list = 0;
    ctx->local.list = 0;
    ctx->remote.ignored_cleanup = 0;
    ctx->local.ignored_cleanup = 0;

    SAFE_FREE(ctx->statedb.file);
}
Esempio n. 6
0
File: csync.c Progetto: gco/csync
static int  _merge_and_write_statedb(CSYNC *ctx) {
  struct timespec start, finish;
  char errbuf[256] = {0};
  int jwritten = 0;
  int rc = 0;

  /* if we have a statedb */
  if (ctx->statedb.db != NULL) {
    /* and we have successfully synchronized */
    if (ctx->status >= CSYNC_STATUS_DONE) {
      /* merge trees */
      if (csync_merge_file_trees(ctx) < 0) {
        strerror_r(errno, errbuf, sizeof(errbuf));
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to merge trees: %s",
                  errbuf);
        ctx->status_code = CSYNC_STATUS_MERGE_FILETREE_ERROR;
        rc = -1;
      } else {
        csync_gettime(&start);
        /* write the statedb to disk */
        rc = csync_statedb_write(ctx, ctx->statedb.db);
        if (rc == 0) {
          jwritten = 1;
          csync_gettime(&finish);
          CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
              "Writing the statedb of %zu files to disk took %.2f seconds",
              c_rbtree_size(ctx->local.tree), c_secdiff(finish, start));
        } else {
          strerror_r(errno, errbuf, sizeof(errbuf));
          CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to write statedb: %s",
                    errbuf);
          ctx->status_code = CSYNC_STATUS_STATEDB_WRITE_ERROR;
          rc = -1;
        }
      }
    }
    rc = csync_statedb_close(ctx->statedb.file, ctx->statedb.db, jwritten);
    ctx->statedb.db = NULL;
    if (rc < 0) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ERR: closing of statedb failed.");
    }
  }

  return rc;
}
Esempio n. 7
0
int csync_update(CSYNC *ctx) {
  int rc = -1;
  struct timespec start, finish;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->status_code = CSYNC_STATUS_OK;

  /* create/load statedb */
  if (! csync_is_statedb_disabled(ctx)) {
    rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
                  ctx->local.uri);
    if (rc < 0) {
        ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
        return rc;
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Journal: %s", ctx->statedb.file);

    if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
      ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
      rc = -1;
      return rc;
    }
  }

  ctx->status_code = CSYNC_STATUS_OK;

  csync_memstat_check();

  if (!ctx->excludes) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "No exclude file loaded or defined!");
  }

  /* update detection for local replica */
  csync_gettime(&start);
  ctx->current = LOCAL_REPLICA;
  ctx->replica = ctx->local.type;

  rc = csync_ftw(ctx, ctx->local.uri, csync_walker, MAX_DEPTH);
  if (rc < 0) {
    if(ctx->status_code == CSYNC_STATUS_OK)
        ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
    return -1;
  }

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
            "Update detection for local replica took %.2f seconds walking %zu files.",
            c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
  csync_memstat_check();

  if (rc < 0) {
    ctx->status_code = CSYNC_STATUS_TREE_ERROR;
    return -1;
  }

  /* update detection for remote replica */
  if( ! ctx->options.local_only_mode ) {
    csync_gettime(&start);
    ctx->current = REMOTE_REPLICA;
    ctx->replica = ctx->remote.type;

    rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
    if (rc < 0) {
        if(ctx->status_code == CSYNC_STATUS_OK)
            ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
        return -1;
    }


    csync_gettime(&finish);

    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
              "Update detection for remote replica took %.2f seconds "
              "walking %zu files.",
              c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
    csync_memstat_check();
  }
  ctx->status |= CSYNC_STATUS_UPDATE;

  return 0;
}
Esempio n. 8
0
int csync_update(CSYNC *ctx) {
  int rc = -1;
  struct timespec start, finish;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->status_code = CSYNC_STATUS_OK;

  /* create/load statedb */
    rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
                  ctx->local.uri);
    if (rc < 0) {
        ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
        return rc;
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Journal: %s", ctx->statedb.file);

    if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
      rc = -1;
      return rc;
    }

  ctx->status_code = CSYNC_STATUS_OK;

  csync_memstat_check();

  if (!ctx->excludes) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "No exclude file loaded or defined!");
  }

#ifdef USE_NEON
  /* This is not actually connecting, just setting the info for neon. The legacy propagator can use it.. */
  if (dav_connect( ctx, ctx->remote.uri ) < 0) {
      ctx->status_code = CSYNC_STATUS_CONNECT_ERROR;
      return -1;
  }
#endif

  /* update detection for local replica */
  csync_gettime(&start);
  ctx->current = LOCAL_REPLICA;
  ctx->replica = ctx->local.type;

  rc = csync_ftw(ctx, ctx->local.uri, csync_walker, MAX_DEPTH);
  if (rc < 0) {
    if(ctx->status_code == CSYNC_STATUS_OK) {
        ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
    }
    goto out;
  }

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
            "Update detection for local replica took %.2f seconds walking %zu files.",
            c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
  csync_memstat_check();

  /* update detection for remote replica */
  csync_gettime(&start);
  ctx->current = REMOTE_REPLICA;
  ctx->replica = ctx->remote.type;

  rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
  if (rc < 0) {
      if(ctx->status_code == CSYNC_STATUS_OK) {
          ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
      }
      goto out;
  }

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
            "Update detection for remote replica took %.2f seconds "
            "walking %zu files.",
            c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
  csync_memstat_check();

  ctx->status |= CSYNC_STATUS_UPDATE;

  rc = 0;

out:
  csync_statedb_close(ctx);
  return rc;
}
Esempio n. 9
0
int csync_destroy(CSYNC *ctx) {
  struct timespec start, finish;
  char *lock = NULL;
  char errbuf[256] = {0};
  int jwritten = 0;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->error_code = CSYNC_ERR_NONE;

  csync_vio_shutdown(ctx);

  /* if we have a statedb */
  if (ctx->statedb.db != NULL) {
    /* and we have successfully synchronized */
    if (ctx->status >= CSYNC_STATUS_DONE) {
      /* merge trees */
      if (csync_merge_file_trees(ctx) < 0) {
        strerror_r(errno, errbuf, sizeof(errbuf));
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to merge trees: %s",
                  errbuf);
      } else {
        csync_gettime(&start);
        /* write the statedb to disk */
        if (csync_statedb_write(ctx) == 0) {
          jwritten = 1;
          csync_gettime(&finish);
          CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
              "Writing the statedb of %zu files to disk took %.2f seconds",
              c_rbtree_size(ctx->local.tree), c_secdiff(finish, start));
        } else {
          strerror_r(errno, errbuf, sizeof(errbuf));
          CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to write statedb: %s",
                    errbuf);
        }
      }
    }
    csync_statedb_close(ctx, ctx->statedb.file, jwritten);
  }

  /* clear exclude list */
  csync_exclude_destroy(ctx);

#ifndef _WIN32
  /* remove the lock file */
  if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) > 0) {
    csync_lock_remove(lock);
  }
#endif

  /* stop logging */
  csync_log_fini();

  /* destroy the rbtrees */
  if (c_rbtree_size(ctx->local.tree) > 0) {
    c_rbtree_destroy(ctx->local.tree, _tree_destructor);
  }

  if (c_rbtree_size(ctx->remote.tree) > 0) {
    c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
  }

  /* free memory */
  c_rbtree_free(ctx->local.tree);
  c_list_free(ctx->local.list);
  c_rbtree_free(ctx->remote.tree);
  c_list_free(ctx->remote.list);
  SAFE_FREE(ctx->local.uri);
  SAFE_FREE(ctx->remote.uri);
  SAFE_FREE(ctx->options.config_dir);
  SAFE_FREE(ctx->statedb.file);

  SAFE_FREE(ctx);

  SAFE_FREE(lock);

  return 0;
}
Esempio n. 10
0
File: csync.c Progetto: gco/csync
int csync_destroy(CSYNC *ctx) {
  char *lock = NULL;
  int rc;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->status_code = CSYNC_STATUS_OK;

  csync_vio_shutdown(ctx);

  rc = _merge_and_write_statedb(ctx);
  if (rc < 0) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "destroy: Merge and Write database failed!");
    if (ctx->status_code == CSYNC_STATUS_OK) {
      ctx->status_code = CSYNC_STATUS_STATEDB_WRITE_ERROR;
    }
    /* The other steps happen anyway, what else can we do? */
  }

  /* clear exclude list */
  csync_exclude_destroy(ctx);

#ifndef _WIN32
  /* remove the lock file */
  rc = asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE);
  if (rc > 0) {
    csync_lock_remove(lock);
  }
#endif

  /* destroy the rbtrees */
  rc = c_rbtree_size(ctx->local.tree);
  if (rc > 0) {
    c_rbtree_destroy(ctx->local.tree, _tree_destructor);
  }

  rc = c_rbtree_size(ctx->remote.tree);
  if (rc > 0) {
    c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
  }

  /* free memory */
  c_rbtree_free(ctx->local.tree);
  c_list_free(ctx->local.list);
  c_rbtree_free(ctx->remote.tree);
  c_list_free(ctx->remote.list);
  SAFE_FREE(ctx->local.uri);
  SAFE_FREE(ctx->remote.uri);
  SAFE_FREE(ctx->options.config_dir);
  SAFE_FREE(ctx->statedb.file);
  SAFE_FREE(ctx->error_string);

#ifdef WITH_ICONV
  c_close_iconv();
#endif

  SAFE_FREE(ctx);

  SAFE_FREE(lock);

  return 0;
}
Esempio n. 11
0
File: csync.c Progetto: gco/csync
int csync_commit(CSYNC *ctx) {
  int rc = 0;

  if (ctx == NULL) {
    return -1;
  }

  ctx->status_code = CSYNC_STATUS_OK;

  rc = _merge_and_write_statedb(ctx);
  if (rc < 0) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Merge and Write database failed!");
    if (ctx->status_code == CSYNC_STATUS_OK) {
      ctx->status_code = CSYNC_STATUS_STATEDB_WRITE_ERROR;
    }
    rc = 1;  /* Set to soft error. */
    /* The other steps happen anyway, what else can we do? */
  }

  rc = csync_vio_commit(ctx);
  if (rc < 0) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "commit failed: %s",
              ctx->error_string ? ctx->error_string : "");
    goto out;
  }

  /* destroy the rbtrees */
  rc = c_rbtree_size(ctx->local.tree);
  if (rc > 0) {
    c_rbtree_destroy(ctx->local.tree, _tree_destructor);
  }

  rc = c_rbtree_size(ctx->remote.tree);
  if (rc > 0) {
    c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
  }

  /* free memory */
  c_rbtree_free(ctx->local.tree);
  c_list_free(ctx->local.list);
  c_rbtree_free(ctx->remote.tree);
  c_list_free(ctx->remote.list);

  ctx->local.list = 0;
  ctx->remote.list = 0;

  /* create/load statedb */
  rc = csync_is_statedb_disabled(ctx);
  if (rc == 0) {
    if (ctx->statedb.file == NULL) {
      rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
                    ctx->local.uri);
      if (rc < 0) {
        ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
        CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Failed to assemble statedb file name.");
        goto out;
      }
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Journal: %s", ctx->statedb.file);

    rc = csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db);
    if (rc < 0) {
      ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
      goto out;
    }
  }

  /* Create new trees */
  rc = c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
  if (rc < 0) {
    ctx->status_code = CSYNC_STATUS_TREE_ERROR;
    goto out;
  }

  rc = c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
  if (rc < 0) {
    ctx->status_code = CSYNC_STATUS_TREE_ERROR;
    goto out;
  }

  /* reset the progress */
  ctx->progress.file_count = 0;
  ctx->progress.current_file_no = 0;
  ctx->progress.byte_sum = 0;
  ctx->progress.byte_current = 0;

  ctx->status = CSYNC_STATUS_INIT;
  SAFE_FREE(ctx->error_string);

  rc = 0;

out:
  return rc;
}
Esempio n. 12
0
File: csync.c Progetto: gco/csync
int csync_propagate(CSYNC *ctx) {
  int rc = -1;
  struct timespec start, finish;

  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }

  ctx->status_code = CSYNC_STATUS_OK;

  /* Initialize the database for the overall progress callback. */
  rc = csync_init_overall_progress(ctx);
  if (rc < 0) {
      if (ctx->status_code == CSYNC_STATUS_OK) {
          ctx->status_code = CSYNC_STATUS_PROPAGATE_ERROR;
      }
      return -1;
  }

  /* Reconciliation for local replica */
  csync_gettime(&start);

  ctx->current = LOCAL_REPLICA;
  ctx->replica = ctx->local.type;

  rc = csync_propagate_files(ctx);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "Propagation for local replica took %.2f seconds visiting %zu files.",
      c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));

  if (rc < 0) {
      if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = CSYNC_STATUS_PROPAGATE_ERROR;
      }
      return -1;
  }

  /* Reconciliation for local replica */
  csync_gettime(&start);

  ctx->current = REMOTE_REPLICA;
  ctx->replica = ctx->remote.type;

  rc = csync_propagate_files(ctx);

  csync_gettime(&finish);

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "Propagation for remote replica took %.2f seconds visiting %zu files.",
      c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));

  if (rc < 0) {
      if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
          ctx->status_code = CSYNC_STATUS_PROPAGATE_ERROR;
      }
      return -1;
  }

  ctx->status |= CSYNC_STATUS_PROPAGATE;

  return 0;
}