static int _csync_remove_file(CSYNC *ctx, csync_file_stat_t *st) {
  char errbuf[256] = {0};
  char *uri = NULL;
  int rc = -1;

  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
        ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
        return -1;
      }
      break;
    case REMOTE_REPLICA:
      if (asprintf(&uri, "%s/%s", ctx->remote.uri, st->path) < 0) {
        ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
        return -1;
      }
      break;
    default:
      break;
  }

  if (csync_vio_unlink(ctx, uri) < 0) {
    ctx->status_code = csync_errno_to_status(errno,
                                             CSYNC_STATUS_PROPAGATE_ERROR);
    switch (errno) {
      case ENOMEM:
        rc = -1;
        break;
      default:
        rc = 1;
        break;
    }
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, command: unlink, error: %s",
        uri,
        errbuf);
    goto out;
  }

  /* set instruction for the statedb merger */
  st->instruction = CSYNC_INSTRUCTION_DELETED;

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "REMOVED file: %s", uri);

  rc = 0;
out:
  SAFE_FREE(uri);

  /* set instruction for the statedb merger */
  if (rc != 0) {
    /* Write file to statedb, to try to sync again on the next run. */
    st->instruction = CSYNC_INSTRUCTION_NONE;
  }

  return rc;
}
Exemple #2
0
static void check_csync_vio_unlink(void **state)
{
    CSYNC *csync = *state;
    csync_stat_t sb;
    mbchar_t *file = c_utf8_to_locale(CSYNC_TEST_FILE);
    int rc;

    rc = csync_vio_unlink(csync, CSYNC_TEST_FILE);
    assert_int_equal(rc, 0);

    rc = _tstat(file, &sb);
    assert_int_equal(rc, -1);

    c_free_locale_string(file);
}
Exemple #3
0
/* check time difference between the replicas */
time_t csync_timediff(CSYNC *ctx) {
  time_t timediff = -1;
  char errbuf[256] = {0};
  char *luri = NULL;
  char *ruri = NULL;
  csync_vio_handle_t *fp = NULL;
  csync_vio_file_stat_t *st = NULL;
  csync_vio_handle_t *dp = NULL;

  /* try to open remote dir to get auth */
  ctx->replica = ctx->remote.type;
  dp = csync_vio_opendir(ctx, ctx->remote.uri);
  if (dp == NULL) {
    /*
     * To prevent problems especially with pam_csync we shouldn't try to create the
     * remote directory here. Just fail!
     */
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
        "Access dienied to remote uri: %s - %s",
        ctx->remote.uri,
        errbuf);
    return -1;
  }
  csync_vio_closedir(ctx, dp);

  if (asprintf(&luri, "%s/.csync_timediff.ctmp", ctx->local.uri) < 0) {
    goto out;
  }

  if (asprintf(&ruri, "%s/.csync_timediff.ctmp", ctx->remote.uri) < 0) {
    goto out;
  }

  /* create temporary file on local */
  ctx->replica = ctx->local.type;
  fp = csync_vio_creat(ctx, luri, 0644);
  if (fp == NULL) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
        "Unable to create temporary file: %s - %s",
        luri,
        errbuf);
    goto out;
  }
  csync_vio_close(ctx, fp);

  /* Get the modification time */
  st = csync_vio_file_stat_new();
  if (csync_vio_stat(ctx, luri, st) < 0) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
        "Synchronisation is not possible! %s - %s",
        luri,
        errbuf);
    goto out;
  }
  timediff = st->mtime;
  csync_vio_file_stat_destroy(st);
  st = NULL;

  /* create temporary file on remote replica */
  ctx->replica = ctx->remote.type;

  fp = csync_vio_creat(ctx, ruri, 0644);
  if (fp == NULL) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
        "Unable to create temporary file: %s - %s",
        ruri,
        errbuf);
    goto out;
  }
  csync_vio_close(ctx, fp);

  /* Get the modification time */
  st = csync_vio_file_stat_new();
  if (csync_vio_stat(ctx, ruri, st) < 0) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
        "Synchronisation is not possible! %s - %s",
        ruri,
        errbuf);
    goto out;
  }

  /* calc time difference */
  timediff = llabs(timediff - st->mtime);
  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Time difference: %ld seconds", timediff);

out:
  csync_vio_file_stat_destroy(st);

  ctx->replica = ctx->local.type;
  csync_vio_unlink(ctx, luri);
  SAFE_FREE(luri);

  ctx->replica = ctx->remote.type;
  csync_vio_unlink(ctx, ruri);
  SAFE_FREE(ruri);

  return timediff;
}
Exemple #4
0
static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
  enum csync_replica_e srep = -1;
  enum csync_replica_e drep = -1;
  enum csync_replica_e rep_bak = -1;

  char *suri = NULL;
  char *duri = NULL;
  char *turi = NULL;
  char *tdir = NULL;

  csync_vio_handle_t *sfp = NULL;
  csync_vio_handle_t *dfp = NULL;

  csync_vio_file_stat_t *tstat = NULL;

  char errbuf[256] = {0};
  char buf[MAX_XFER_BUF_SIZE] = {0};
  ssize_t bread = 0;
  ssize_t bwritten = 0;
  struct timeval times[2];

  int rc = -1;
  int count = 0;
  int flags = 0;

  rep_bak = ctx->replica;

  switch (ctx->current) {
    case LOCAL_REPLICA:
      srep = ctx->local.type;
      drep = ctx->remote.type;
      if (asprintf(&suri, "%s/%s", ctx->local.uri, st->path) < 0) {
        rc = -1;
        goto out;
      }
      if (asprintf(&duri, "%s/%s", ctx->remote.uri, st->path) < 0) {
        rc = -1;
        goto out;
      }
      break;
    case REMOTE_REPLCIA:
      srep = ctx->remote.type;
      drep = ctx->local.type;
      if (asprintf(&suri, "%s/%s", ctx->remote.uri, st->path) < 0) {
        rc = -1;
        goto out;
      }
      if (asprintf(&duri, "%s/%s", ctx->local.uri, st->path) < 0) {
        rc = -1;
        goto out;
      }
      break;
    default:
      break;
  }

  /* Open the source file */
  ctx->replica = srep;
  flags = O_RDONLY|O_NOFOLLOW;
  /* O_NOATIME can only be set by the owner of the file or the superuser */
  if (st->uid == ctx->pwd.uid || ctx->pwd.euid == 0) {
    flags |= O_NOATIME;
  }
  sfp = csync_vio_open(ctx, suri, flags, 0);
  if (sfp == NULL) {
    if (errno == ENOMEM) {
      rc = -1;
    } else {
      rc = 1;
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, command: open(O_RDONLY), error: %s",
        suri,
        strerror_r(errno, errbuf, sizeof(errbuf)));
    goto out;
  }

  /* create the temporary file name */
  if (asprintf(&turi, "%s.XXXXXX", duri) < 0) {
    rc = -1;
    goto out;
  }

  /* We just want a random file name here, open checks if the file exists. */
  if (c_tmpname(turi) < 0) {
    rc = -1;
    goto out;
  }

  /* Create the destination file */
  ctx->replica = drep;
  while ((dfp = csync_vio_open(ctx, turi, O_CREAT|O_EXCL|O_WRONLY|O_NOCTTY,
          C_FILE_MODE)) == NULL) {
    switch (errno) {
      case EEXIST:
        if (count++ > 10) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
              "file: %s, command: open(O_CREAT), error: max count exceeded",
              duri);
          rc = 1;
          goto out;
        }
        if (c_tmpname(turi) < 0) {
          rc = -1;
          goto out;
        }
        break;
      case ENOENT:
        /* get the directory name */
        tdir = c_dirname(turi);
        if (tdir == NULL) {
          rc = -1;
          goto out;
        }

        if (csync_vio_mkdirs(ctx, tdir, C_DIR_MODE) < 0) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
              "dir: %s, command: mkdirs, error: %s",
              tdir,
              strerror_r(errno, errbuf, sizeof(errbuf)));
        }
        break;
      case ENOMEM:
        rc = -1;
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
            "file: %s, command: open(O_CREAT), error: %s",
            turi,
            strerror_r(errno, errbuf, sizeof(errbuf)));
        goto out;
        break;
      default:
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
            "file: %s, command: open(O_CREAT), error: %s",
            turi,
            strerror_r(errno, errbuf, sizeof(errbuf)));
        rc = 1;
        goto out;
        break;
    }

  }

  /* copy file */
  for (;;) {
    ctx->replica = srep;
    bread = csync_vio_read(ctx, sfp, buf, MAX_XFER_BUF_SIZE);

    if (bread < 0) {
      /* read error */
      CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
          "file: %s, command: read, error: %s",
          suri,
          strerror_r(errno, errbuf, sizeof(errbuf)));
      rc = 1;
      goto out;
    } else if (bread == 0) {
      /* done */
      break;
    }

    ctx->replica = drep;
    bwritten = csync_vio_write(ctx, dfp, buf, bread);

    if (bwritten < 0 || bread != bwritten) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
          "file: %s, command: write, error: bread = %zu, bwritten = %zu - %s",
          duri,
          bread,
          bwritten,
          strerror_r(errno, errbuf, sizeof(errbuf)));
      rc = 1;
      goto out;
    }
  }

  ctx->replica = srep;
  if (csync_vio_close(ctx, sfp) < 0) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, command: close, error: %s",
        suri,
        strerror_r(errno, errbuf, sizeof(errbuf)));
  }
  sfp = NULL;

  ctx->replica = drep;
  if (csync_vio_close(ctx, dfp) < 0) {
    dfp = NULL;
    switch (errno) {
      /* stop if no space left or quota exceeded */
      case ENOSPC:
      case EDQUOT:
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
            "file: %s, command: close, error: %s",
            turi,
            strerror_r(errno, errbuf, sizeof(errbuf)));
        rc = -1;
        goto out;
        break;
      default:
        CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
            "file: %s, command: close, error: %s",
            turi,
            strerror_r(errno, errbuf, sizeof(errbuf)));
        break;
    }
  }
  dfp = NULL;

  /*
   * Check filesize
   */
  ctx->replica = drep;
  tstat = csync_vio_file_stat_new();
  if (tstat == NULL) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, command: stat, error: %s",
        turi,
        strerror_r(errno, errbuf, sizeof(errbuf)));
    rc = -1;
    goto out;
  }

  if (csync_vio_stat(ctx, turi, tstat) < 0) {
    switch (errno) {
      case ENOMEM:
        rc = -1;
        break;
      default:
        rc = 1;
        break;
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, command: stat, error: %s",
        turi,
        strerror_r(errno, errbuf, sizeof(errbuf)));
    goto out;
  }

  if (st->size != tstat->size) {
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, error: incorrect filesize (size: %jd should be %jd)",
        turi, tstat->size, st->size);
    rc = 1;
    goto out;
  }

  /* override original file */
  ctx->replica = drep;
  if (csync_vio_rename(ctx, turi, duri) < 0) {
    switch (errno) {
      case ENOMEM:
        rc = -1;
        break;
      default:
        rc = 1;
        break;
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
        "file: %s, command: rename, error: %s",
        duri,
        strerror_r(errno, errbuf, sizeof(errbuf)));
    goto out;
  }

  /* set mode only if it is not the default mode */
  if ((st->mode & 07777) != C_FILE_MODE) {
    if (csync_vio_chmod(ctx, duri, st->mode) < 0) {
      switch (errno) {
        case ENOMEM:
          rc = -1;
          break;
        default:
          rc = 1;
          break;
      }
      CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
          "file: %s, command: chmod, error: %s",
          duri,
          strerror_r(errno, errbuf, sizeof(errbuf)));
      goto out;
    }
  }

  /* set owner and group if possible */
  if (ctx->pwd.euid == 0) {
    csync_vio_chown(ctx, duri, st->uid, st->gid);
  }

  /* sync time */
  times[0].tv_sec = times[1].tv_sec = st->modtime;
  times[0].tv_usec = times[1].tv_usec = 0;

  ctx->replica = drep;
  csync_vio_utimes(ctx, duri, times);

  /* set instruction for the statedb merger */
  st->instruction = CSYNC_INSTRUCTION_UPDATED;

  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "PUSHED  file: %s", duri);

  rc = 0;

out:
  ctx->replica = srep;
  csync_vio_close(ctx, sfp);

  ctx->replica = drep;
  csync_vio_close(ctx, dfp);

  csync_vio_file_stat_destroy(tstat);

  /* set instruction for the statedb merger */
  if (rc != 0) {
    st->instruction = CSYNC_INSTRUCTION_ERROR;
    csync_vio_unlink(ctx, turi);
  }

  SAFE_FREE(suri);
  SAFE_FREE(duri);
  SAFE_FREE(turi);
  SAFE_FREE(tdir);

  ctx->replica = rep_bak;

  return rc;
}