<commit_before>/*
 * libcsync -- a library to sync a directory with another
 *
 * Copyright (c) 2008      by <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "csync_private.h"
#include "csync_reconcile.h"
#include "csync_util.h"

#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler"
#include "csync_log.h"

/*
 * We merge replicas at the file level. The merged replica contains the
 * superset of files that are on the local machine and server copies of
 * the replica. In the case where the same file is in both the local
 * and server copy, the file that was modified most recently is used.
 * This means that new files are not deleted, and updated versions of
 * existing files are not overwritten.
 *
 * When a file is updated, the merge algorithm compares the destination
 * file with the the source file. If the destination file is newer
 * (timestamp is newer), it is not overwritten. If both files, on the
 * source and the destination, have been changed, the newer file wins.
 */
static int _csync_merge_algorithm_visitor(void *obj, void *data) {
  csync_file_stat_t *cur = NULL;
  csync_file_stat_t *other = NULL;
  CSYNC *ctx = NULL;
  c_rbtree_t *tree = NULL;
  c_rbnode_t *node = NULL;

  cur = (csync_file_stat_t *) obj;
  ctx = (CSYNC *) data;

  /* we need the opposite tree! */
  switch (ctx->current) {
    case LOCAL_REPLICA:
      tree = ctx->remote.tree;
      break;
    case REMOTE_REPLCIA:
      tree = ctx->local.tree;
      break;
    default:
      break;
  }

  node = c_rbtree_find(tree, &cur->phash);
  /* file only found on current replica */
  if (node == NULL) {
    switch(cur->instruction) {
      /* file has been modified */
      case CSYNC_INSTRUCTION_EVAL:
        cur->instruction = CSYNC_INSTRUCTION_NEW;
        break;
      /* file has been removed on the opposite replica */
      case CSYNC_INSTRUCTION_NONE:
        cur->instruction = CSYNC_INSTRUCTION_REMOVE;
        break;
      case CSYNC_INSTRUCTION_RENAME:
        cur->instruction = CSYNC_INSTRUCTION_NEW;
        break;
      default:
        break;
    }
  } else {
    /*
     * file found on the other replica
     */
    other = (csync_file_stat_t *) node->data;

    switch (cur->instruction) {
      /* file on current replica is new */
      case CSYNC_INSTRUCTION_NEW:
        switch (other->instruction) {
          /* file on other replica is new too */
          case CSYNC_INSTRUCTION_NEW:
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
              other->instruction = CSYNC_INSTRUCTION_NONE;
            } else if (cur->modtime < other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_NONE;
              other->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              /* file are equal */
              cur->instruction = CSYNC_INSTRUCTION_NONE;
              other->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on other replica has changed too */
          case CSYNC_INSTRUCTION_EVAL:
            /* file on current replica is newer */
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              /* file on opposite replica is newer */
              cur->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on the other replica has not been modified */
          case CSYNC_INSTRUCTION_NONE:
            cur->instruction = CSYNC_INSTRUCTION_SYNC;
            break;
          default:
            break;
        }
        break;
      /* file on current replica has been modified */
      case CSYNC_INSTRUCTION_EVAL:
        switch (other->instruction) {
          /* file on other replica is new too */
          case CSYNC_INSTRUCTION_NEW:
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              cur->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on other replica has changed too */
          case CSYNC_INSTRUCTION_EVAL:
            /* file on current replica is newer */
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              /* file on opposite replica is newer */
              cur->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on the other replica has not been modified */
          case CSYNC_INSTRUCTION_NONE:
            cur->instruction = CSYNC_INSTRUCTION_SYNC;
            break;
          default:
            break;
        }
        break;
      default:
        break;
    }
  }

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: %s", cur->path, csync_instruction_str(cur->instruction));
  return 0;
}

int csync_reconcile_updates(CSYNC *ctx) {
  int rc = -1;
  c_rbtree_t *tree = NULL;

  switch (ctx->current) {
    case LOCAL_REPLICA:
      tree = ctx->local.tree;
      break;
    case REMOTE_REPLCIA:
      tree = ctx->remote.tree;
      break;
    default:
      break;
  }

  rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor);

  return 0;
}

/* vim: set ts=8 sw=2 et cindent: */<commit_msg>Fix textwidth.<commit_after>/*
 * libcsync -- a library to sync a directory with another
 *
 * Copyright (c) 2008      by <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "csync_private.h"
#include "csync_reconcile.h"
#include "csync_util.h"

#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler"
#include "csync_log.h"

/*
 * We merge replicas at the file level. The merged replica contains the
 * superset of files that are on the local machine and server copies of
 * the replica. In the case where the same file is in both the local
 * and server copy, the file that was modified most recently is used.
 * This means that new files are not deleted, and updated versions of
 * existing files are not overwritten.
 *
 * When a file is updated, the merge algorithm compares the destination
 * file with the the source file. If the destination file is newer
 * (timestamp is newer), it is not overwritten. If both files, on the
 * source and the destination, have been changed, the newer file wins.
 */
static int _csync_merge_algorithm_visitor(void *obj, void *data) {
  csync_file_stat_t *cur = NULL;
  csync_file_stat_t *other = NULL;
  CSYNC *ctx = NULL;
  c_rbtree_t *tree = NULL;
  c_rbnode_t *node = NULL;

  cur = (csync_file_stat_t *) obj;
  ctx = (CSYNC *) data;

  /* we need the opposite tree! */
  switch (ctx->current) {
    case LOCAL_REPLICA:
      tree = ctx->remote.tree;
      break;
    case REMOTE_REPLCIA:
      tree = ctx->local.tree;
      break;
    default:
      break;
  }

  node = c_rbtree_find(tree, &cur->phash);
  /* file only found on current replica */
  if (node == NULL) {
    switch(cur->instruction) {
      /* file has been modified */
      case CSYNC_INSTRUCTION_EVAL:
        cur->instruction = CSYNC_INSTRUCTION_NEW;
        break;
      /* file has been removed on the opposite replica */
      case CSYNC_INSTRUCTION_NONE:
        cur->instruction = CSYNC_INSTRUCTION_REMOVE;
        break;
      case CSYNC_INSTRUCTION_RENAME:
        cur->instruction = CSYNC_INSTRUCTION_NEW;
        break;
      default:
        break;
    }
  } else {
    /*
     * file found on the other replica
     */
    other = (csync_file_stat_t *) node->data;

    switch (cur->instruction) {
      /* file on current replica is new */
      case CSYNC_INSTRUCTION_NEW:
        switch (other->instruction) {
          /* file on other replica is new too */
          case CSYNC_INSTRUCTION_NEW:
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
              other->instruction = CSYNC_INSTRUCTION_NONE;
            } else if (cur->modtime < other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_NONE;
              other->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              /* file are equal */
              cur->instruction = CSYNC_INSTRUCTION_NONE;
              other->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on other replica has changed too */
          case CSYNC_INSTRUCTION_EVAL:
            /* file on current replica is newer */
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              /* file on opposite replica is newer */
              cur->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on the other replica has not been modified */
          case CSYNC_INSTRUCTION_NONE:
            cur->instruction = CSYNC_INSTRUCTION_SYNC;
            break;
          default:
            break;
        }
        break;
      /* file on current replica has been modified */
      case CSYNC_INSTRUCTION_EVAL:
        switch (other->instruction) {
          /* file on other replica is new too */
          case CSYNC_INSTRUCTION_NEW:
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              cur->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on other replica has changed too */
          case CSYNC_INSTRUCTION_EVAL:
            /* file on current replica is newer */
            if (cur->modtime > other->modtime) {
              cur->instruction = CSYNC_INSTRUCTION_SYNC;
            } else {
              /* file on opposite replica is newer */
              cur->instruction = CSYNC_INSTRUCTION_NONE;
            }
            break;
          /* file on the other replica has not been modified */
          case CSYNC_INSTRUCTION_NONE:
            cur->instruction = CSYNC_INSTRUCTION_SYNC;
            break;
          default:
            break;
        }
        break;
      default:
        break;
    }
  }

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
      "file: %s, instruction: %s",
      cur->path,
      csync_instruction_str(cur->instruction));
  return 0;
}

int csync_reconcile_updates(CSYNC *ctx) {
  int rc = -1;
  c_rbtree_t *tree = NULL;

  switch (ctx->current) {
    case LOCAL_REPLICA:
      tree = ctx->local.tree;
      break;
    case REMOTE_REPLCIA:
      tree = ctx->remote.tree;
      break;
    default:
      break;
  }

  rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor);

  return 0;
}

/* vim: set ts=8 sw=2 et cindent: */
{'fraction_non_alphanumeric': 0.08417452239926587, 'fraction_numerical': 0.0035037957787603237, 'mean_word_length': 2.189146049481245, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '77159', 'n_tokens_mistral': 3587, 'n_tokens_neox': 3516, 'n_words': 1135}