Esempio n. 1
0
int csync_init(CSYNC *ctx) {
  int rc;
  char *config = NULL;

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

  ctx->status_code = CSYNC_STATUS_OK;

  /* Do not initialize twice */
  if (ctx->status & CSYNC_STATUS_INIT) {
    return 1;
  }

  /* check for uri */
  if (csync_fnmatch("owncloud://*", ctx->remote.uri, 0) == 0 && csync_fnmatch("ownclouds://*", ctx->remote.uri, 0) == 0) {
      ctx->status_code = CSYNC_STATUS_NO_MODULE;
      rc = -1;
      goto out;
  }

  ctx->local.type = LOCAL_REPLICA;

  if ( !ctx->options.local_only_mode) {
      owncloud_init(csync_get_auth_callback(ctx), csync_get_userdata(ctx));
      ctx->remote.type = REMOTE_REPLICA;
  } else {
    ctx->remote.type = LOCAL_REPLICA;
  }

  if (ctx->options.timeout)
    csync_vio_set_property(ctx, "timeout", &ctx->options.timeout);

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

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

  ctx->status = CSYNC_STATUS_INIT;

  csync_set_module_property(ctx, "csync_context", ctx);

  /* initialize random generator */
  srand(time(NULL));

  rc = 0;

out:
  SAFE_FREE(config);
  return rc;
}
Esempio n. 2
0
int csync_init(CSYNC *ctx) {
  int rc;

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

  ctx->status_code = CSYNC_STATUS_OK;

  /* Do not initialize twice */
  if (ctx->status & CSYNC_STATUS_INIT) {
    return 1;
  }

  /* check for uri */
  if (csync_fnmatch("owncloud://*", ctx->remote.uri, 0) == 0 && csync_fnmatch("ownclouds://*", ctx->remote.uri, 0) == 0) {
      ctx->status_code = CSYNC_STATUS_NO_MODULE;
      rc = -1;
      goto out;
  }

  ctx->local.type = LOCAL_REPLICA;

#ifdef USE_NEON
  owncloud_init(ctx);
#endif
  ctx->remote.type = REMOTE_REPLICA;

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

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

  ctx->remote.root_perms = 0;

  ctx->status = CSYNC_STATUS_INIT;

  /* initialize random generator */
  srand(time(NULL));

  rc = 0;

out:
  return rc;
}
Esempio n. 3
0
int csync_excluded(CSYNC *ctx, const char *path) {
  size_t i;
  const char *p;

  if (! ctx->options.unix_extensions) {
    for (p = path; *p; p++) {
      switch (*p) {
        case '\\':
        case ':':
        case '?':
        case '*':
        case '"':
        case '>':
        case '<':
        case '|':
          return 1;
        default:
          break;
      }
    }
  }

  if (ctx->excludes == NULL) {
    return 0;
  }

  if (ctx->excludes->count) {
    for (i = 0; i < ctx->excludes->count; i++) {
      if (csync_fnmatch(ctx->excludes->vector[i], path, 0) == 0) {
        return 1;
      }
    }
  }
  return 0;
}
Esempio n. 4
0
static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
    size_t i = 0;
    const char *bname = NULL;
    size_t blen = 0;
    char *conflict = NULL;
    int rc = -1;
    CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
    CSYNC_EXCLUDE_TYPE type  = CSYNC_NOT_EXCLUDED;

    /* split up the path */
    bname = strrchr(path, '/');
    if (bname) {
        bname += 1; // don't include the /
    } else {
        bname = path;
    }
    blen = strlen(bname);

    rc = csync_fnmatch("._sync_*.db*", bname, 0);
    if (rc == 0) {
        match = CSYNC_FILE_SILENTLY_EXCLUDED;
        goto out;
    }
    rc = csync_fnmatch(".sync_*.db*", bname, 0);
    if (rc == 0) {
        match = CSYNC_FILE_SILENTLY_EXCLUDED;
        goto out;
    }
    rc = csync_fnmatch(".csync_journal.db*", bname, 0);
    if (rc == 0) {
        match = CSYNC_FILE_SILENTLY_EXCLUDED;
        goto out;
    }

    // check the strlen and ignore the file if its name is longer than 254 chars.
    // whenever changing this also check createDownloadTmpFileName
    if (blen > 254) {
        match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
        goto out;
    }

#ifdef _WIN32
    // Windows cannot sync files ending in spaces (#2176). It also cannot
    // distinguish files ending in '.' from files without an ending,
    // as '.' is a separator that is not stored internally, so let's
    // not allow to sync those to avoid file loss/ambiguities (#416)
    if (blen > 1) {
        if (bname[blen-1]== ' ') {
            match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
            goto out;
        } else if (bname[blen-1]== '.' ) {
            match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
            goto out;
        }
    }

    if (csync_is_windows_reserved_word(bname)) {
      match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
      goto out;
    }

    // Filter out characters not allowed in a filename on windows
    const char *p = NULL;
    for (p = path; *p; p++) {
        switch (*p) {
        case '\\':
        case ':':
        case '?':
        case '*':
        case '"':
        case '>':
        case '<':
        case '|':
            match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
            goto out;
        default:
            break;
        }
    }
#endif

    rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
    if (rc == 0) {
        match = CSYNC_FILE_SILENTLY_EXCLUDED;
        goto out;
    }

    /* Always ignore conflict files, not only via the exclude list */
    rc = csync_fnmatch("*_conflict-*", bname, 0);
    if (rc == 0) {
        match = CSYNC_FILE_EXCLUDE_CONFLICT;
        goto out;
    }

    if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
        rc = asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
        if (rc < 0) {
            goto out;
        }
        rc = csync_fnmatch(conflict, path, 0);
        if (rc == 0) {
            match = CSYNC_FILE_EXCLUDE_CONFLICT;
            SAFE_FREE(conflict);
            goto out;
        }
        SAFE_FREE(conflict);
    }

    if( ! excludes ) {
        goto out;
    }

    c_strlist_t *path_components = NULL;
    if (check_leading_dirs) {
        /* Build a list of path components to check. */
        path_components = c_strlist_new(32);
        char *path_split = strdup(path);
        size_t len = strlen(path_split);
        for (i = len; ; --i) {
            // read backwards until a path separator is found
            if (i != 0 && path_split[i-1] != '/') {
                continue;
            }

            // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
            if (path_split[i] != 0) {
                c_strlist_add_grow(&path_components, path_split + i);
            }

            if (i == 0) {
                break;
            }

            // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
            path_split[i-1] = '\0';
            c_strlist_add_grow(&path_components, path_split);
        }
        SAFE_FREE(path_split);
    }

    /* Loop over all exclude patterns and evaluate the given path */
    for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
        bool match_dirs_only = false;
        char *pattern = excludes->vector[i];

        type = CSYNC_FILE_EXCLUDE_LIST;
        if (!pattern[0]) { /* empty pattern */
            continue;
        }
        /* Excludes starting with ']' means it can be cleanup */
        if (pattern[0] == ']') {
            ++pattern;
            if (filetype == CSYNC_FTW_TYPE_FILE) {
                type = CSYNC_FILE_EXCLUDE_AND_REMOVE;
            }
        }
        /* Check if the pattern applies to pathes only. */
        if (pattern[strlen(pattern)-1] == '/') {
            if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) {
                continue;
            }
            match_dirs_only = true;
            pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
        }

        /* check if the pattern contains a / and if, compare to the whole path */
        if (strchr(pattern, '/')) {
            rc = csync_fnmatch(pattern, path, FNM_PATHNAME);
            if( rc == 0 ) {
                match = type;
            }
            /* if the pattern requires a dir, but path is not, its still not excluded. */
            if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) {
                match = CSYNC_NOT_EXCLUDED;
            }
        }

        /* if still not excluded, check each component and leading directory of the path */
        if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) {
            size_t j = 0;
            if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
                j = 1; // skip the first entry, which is bname
            }
            for (; j < path_components->count; ++j) {
                rc = csync_fnmatch(pattern, path_components->vector[j], 0);
                if (rc == 0) {
                    match = type;
                    break;
                }
            }
        } else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) {
            rc = csync_fnmatch(pattern, bname, 0);
            if (rc == 0) {
                match = type;
            }
        }
        if (match_dirs_only) {
            /* restore the '/' */
            pattern[strlen(pattern)] = '/';
        }
    }
    c_strlist_destroy(path_components);

  out:

    return match;
}
Esempio n. 5
0
int csync_excluded(CSYNC *ctx, const char *path) {
  size_t i;
  const char *p;
  char *bname;
  int rc;
  int match = 0;

  if (! ctx->options.unix_extensions) {
    for (p = path; *p; p++) {
      switch (*p) {
        case '\\':
        case ':':
        case '?':
        case '*':
        case '"':
        case '>':
        case '<':
        case '|':
          return 1;
        default:
          break;
      }
    }
  }

  rc = csync_fnmatch(".csync_journal.db*", path, 0);
  if (rc == 0) {
      return 1;
  }

  bname = c_basename(path);
  if (bname == NULL) {
      return 0;
  }

  rc = csync_fnmatch(".csync_journal.db*", bname, 0);
  if (rc == 0) {
      match = 1;
      goto out;
  }

  if (ctx->excludes == NULL) {
      goto out;
  }

  for (i = 0; match == 0 && i < ctx->excludes->count; i++) {
      rc = csync_fnmatch(ctx->excludes->vector[i], path, 0);
      if (rc == 0) {
          match = 1;
      }

      rc = csync_fnmatch(ctx->excludes->vector[i], bname, 0);
      if (rc == 0) {
          match = 1;
      }
  }

out:
  free(bname);
  return match;
}
Esempio n. 6
0
static int _csync_detect_update(CSYNC *ctx, const char *file,
    const csync_vio_file_stat_t *fs, const int type) {
  uint64_t h = 0;
  size_t len = 0;
  size_t size = 0;
  const char *path = NULL;
  csync_file_stat_t *st = NULL;
  csync_file_stat_t *tmp = NULL;
  CSYNC_EXCLUDE_TYPE excluded;

  if ((file == NULL) || (fs == NULL)) {
    errno = EINVAL;
    ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
    return -1;
  }

  path = file;
  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (strlen(path) <= strlen(ctx->local.uri)) {
        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
        return -1;
      }
      path += strlen(ctx->local.uri) + 1;
      break;
    case REMOTE_REPLICA:
      if (strlen(path) <= strlen(ctx->remote.uri)) {
        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
        return -1;
      }
      path += strlen(ctx->remote.uri) + 1;
      break;
    default:
      path = NULL;
      ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
      return -1;
  }

  len = strlen(path);

  if (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);
  }

  if( excluded == CSYNC_NOT_EXCLUDED ) {
      /* Even if it is not excluded by a pattern, maybe it is to be ignored
       * because it's a hidden file that should not be synced.
       * 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->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
          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);
      if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
          return 1;
      }
      if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
          return 1;
      }
  }

  if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
      if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) {
          return 1;
      }
  }

  h = _hash_of_file(ctx, file );
  if( h == 0 ) {
    return -1;
  }
  size = sizeof(csync_file_stat_t) + len + 1;

  st = c_malloc(size);

  /* Set instruction by default to none */
  st->instruction = CSYNC_INSTRUCTION_NONE;
  st->etag = NULL;
  st->child_modified = 0;
  st->has_ignored_files = 0;
  if (type == CSYNC_FTW_TYPE_FILE ) {
    if (fs->mtime == 0) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
    }
  }

  if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
      st->instruction = CSYNC_INSTRUCTION_IGNORE;
      if (ctx->current_fs) {
          ctx->current_fs->has_ignored_files = true;
      }

      goto out;
  }

  /* Update detection: Check if a database entry exists.
   * If not, the file is either new or has been renamed. To see if it is
   * renamed, the db gets queried by the inode of the file as that one
   * does not change on rename.
   */
  if (csync_get_statedb_exists(ctx)) {
    tmp = csync_statedb_get_stat_by_hash(ctx, h);

    if(_last_db_return_error(ctx)) {
        SAFE_FREE(st);
        SAFE_FREE(tmp);
        ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
        return -1;
    }

    if(tmp && tmp->phash == h ) { /* there is an entry in the database */
        /* we have an update! */
        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Database entry found, compare: %" PRId64 " <-> %" PRId64
                                            ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
                                            ", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d",
                  ((int64_t) fs->mtime), ((int64_t) tmp->modtime),
                  fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
                  (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
        if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
            st->instruction = CSYNC_INSTRUCTION_EVAL;

            // Preserve the EVAL flag later on if the type has changed.
            if (_csync_filetype_different(tmp, fs)) {
                st->child_modified = 1;
            }

            goto out;
        }
        if (ctx->current == LOCAL_REPLICA &&
                (!_csync_mtime_equal(fs->mtime, tmp->modtime)
                 // zero size in statedb can happen during migration
                 || (tmp->size != 0 && fs->size != tmp->size))) {

            // Checksum comparison at this stage is only enabled for .eml files,
            // check #4754 #4755
            bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
            if (isEmlFile && fs->size == tmp->size && tmp->checksumTypeId) {
                if (ctx->callbacks.checksum_hook) {
                    st->checksum = ctx->callbacks.checksum_hook(
                                file, tmp->checksumTypeId,
                                ctx->callbacks.checksum_userdata);
                }
                bool checksumIdentical = false;
                if (st->checksum) {
                    st->checksumTypeId = tmp->checksumTypeId;
                    checksumIdentical = strncmp(st->checksum, tmp->checksum, 1000) == 0;
                }
                if (checksumIdentical) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
                    st->instruction = CSYNC_INSTRUCTION_NONE;
                    st->should_update_metadata = true;
                    goto out;
                }
            }

            // Preserve the EVAL flag later on if the type has changed.
            if (_csync_filetype_different(tmp, fs)) {
                st->child_modified = 1;
            }

            st->instruction = CSYNC_INSTRUCTION_EVAL;
            goto out;
        }
        bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
                                                            || !c_streq(fs->remotePerm, tmp->remotePerm)))
                             || (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
        if (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);
            ctx->remote.read_from_db = true;
        }
        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->should_update_metadata = 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;
        }
        st->instruction = CSYNC_INSTRUCTION_NONE;
    } else {
        enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;

        /* tmp might point to malloc mem, so free it here before reusing tmp  */
        SAFE_FREE(tmp);

        /* check if it's a file and has been renamed */
        if (ctx->current == LOCAL_REPLICA) {
            CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);

            tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);

            if(_last_db_return_error(ctx)) {
                SAFE_FREE(st);
                ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
                return -1;
            }

            /* translate the file type between the two stat types csync has. */
            if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
            } else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
            } else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
            } else {
                tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
            }

            // Default to NEW unless we're sure it's a rename.
            st->instruction = CSYNC_INSTRUCTION_NEW;

            bool isRename =
                tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
                    && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
#ifdef NO_RENAME_EXTENSION
                    && _csync_sameextension(tmp->path, path)
#endif
                ;


            // Verify the checksum where possible
            if (isRename && tmp->checksumTypeId && ctx->callbacks.checksum_hook
                    && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) {
                st->checksum = ctx->callbacks.checksum_hook(
                            file, tmp->checksumTypeId,
                            ctx->callbacks.checksum_userdata);
                if (st->checksum) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksum, tmp->checksum);
                    st->checksumTypeId = tmp->checksumTypeId;
                    isRename = strncmp(st->checksum, tmp->checksum, 1000) == 0;
                }
            }

            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;
                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    csync_rename_record(ctx, tmp->path, path);
                }
            }
            goto out;

        } else {
            /* Remote Replica Rename check */
            tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);

            if(_last_db_return_error(ctx)) {
                SAFE_FREE(st);
                ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
                return -1;
            }
            if(tmp ) {                           /* tmp existing at all */
                if ( _csync_filetype_different(tmp, fs)) {
                    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: file types different is not!");
                    st->instruction = CSYNC_INSTRUCTION_NEW;
                    goto out;
                }
                CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file);
                st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
                    csync_rename_record(ctx, tmp->path, path);
                } else {
                    if( !c_streq(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;
                    }
                }
                goto out;

            } else {
                /* file not found in statedb */
                st->instruction = CSYNC_INSTRUCTION_NEW;

                if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
                    if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
                        SAFE_FREE(st);
                        return 1;
                    }
                }
                goto out;
            }
        }
    }
  } else  {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unable to open statedb" );
      SAFE_FREE(st);
      ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
      return -1;
  }

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. */
      } else {
          if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
              st->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. */
          } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
              st->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;
          } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
              st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
          }
      }
  }
  if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE
      && type != CSYNC_FTW_TYPE_DIR) {
    st->child_modified = 1;
  }
  ctx->current_fs = st;

  csync_file_stat_free(tmp);
  st->inode = fs->inode;
  st->mode  = fs->mode;
  st->size  = fs->size;
  st->modtime = fs->mtime;
  st->type  = type;
  st->etag   = NULL;
  if( fs->etag ) {
      SAFE_FREE(st->etag);
      st->etag  = c_strdup(fs->etag);
  }
  csync_vio_set_file_id(st->file_id, fs->file_id);
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
      SAFE_FREE(st->directDownloadUrl);
      st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
  }
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
      SAFE_FREE(st->directDownloadCookies);
      st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
  }
  if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
      strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
  }

  st->phash = h;
  st->pathlen = len;
  memcpy(st->path, (len ? path : ""), len + 1);

  switch (ctx->current) {
    case LOCAL_REPLICA:
      if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
        SAFE_FREE(st);
        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
        return -1;
      }
      break;
    case REMOTE_REPLICA:
      if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
        SAFE_FREE(st);
        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
        return -1;
      }
      break;
    default:
      break;
  }
  CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: %s <<=", st->path,
      csync_instruction_str(st->instruction));

  return 0;
}
Esempio n. 7
0
CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
  size_t i = 0;
  const char *p = NULL;
  char *bname = NULL;
  char *dname = NULL;
  char *prev_dname = NULL;
  char *conflict = NULL;
  int rc = -1;
  CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
  CSYNC_EXCLUDE_TYPE type  = CSYNC_NOT_EXCLUDED;

    for (p = path; *p; p++) {
      switch (*p) {
        case '\\':
        case ':':
        case '?':
        case '*':
        case '"':
        case '>':
        case '<':
        case '|':
          return CSYNC_FILE_EXCLUDE_INVALID_CHAR;
        default:
          break;
      }
    }

  /* split up the path */
  dname = c_dirname(path);
  bname = c_basename(path);

  if (bname == NULL || dname == NULL) {
      match = CSYNC_NOT_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  rc = csync_fnmatch(".csync_journal.db*", bname, 0);
  if (rc == 0) {
      match = CSYNC_FILE_SILENTLY_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
  if (rc == 0) {
      match = CSYNC_FILE_SILENTLY_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  /* Always ignore conflict files, not only via the exclude list */
  rc = csync_fnmatch("*_conflict-*", bname, 0);
  if (rc == 0) {
      match = CSYNC_FILE_SILENTLY_EXCLUDED;
      SAFE_FREE(bname);
      SAFE_FREE(dname);
      goto out;
  }

  if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
      asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
      rc = csync_fnmatch(conflict, path, 0);
      if (rc == 0) {
          match = CSYNC_FILE_SILENTLY_EXCLUDED;
          SAFE_FREE(conflict);
          SAFE_FREE(bname);
          SAFE_FREE(dname);
          goto out;
      }
      SAFE_FREE(conflict);
  }

  SAFE_FREE(bname);
  SAFE_FREE(dname);

  if (ctx->excludes == NULL) {
      goto out;
  }

  /* Loop over all exclude patterns and evaluate the given path */
  for (i = 0; match == CSYNC_NOT_EXCLUDED && i < ctx->excludes->count; i++) {
      bool match_dirs_only = false;
      char *pattern_stored = c_strdup(ctx->excludes->vector[i]);
      char* pattern = pattern_stored;

      type = CSYNC_FILE_EXCLUDE_LIST;
      if (strlen(pattern) < 1) {
          continue;
      }
      /* Ecludes starting with ']' means it can be cleanup */
      if (pattern[0] == ']') {
          ++pattern;
          if (filetype == CSYNC_FTW_TYPE_FILE) {
              type = CSYNC_FILE_EXCLUDE_AND_REMOVE;
          }
      }
      /* Check if the pattern applies to pathes only. */
      if (pattern[strlen(pattern)-1] == '/') {
          match_dirs_only = true;
          pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
      }

      /* check if the pattern contains a / and if, compare to the whole path */
      if (strchr(pattern, '/')) {
          rc = csync_fnmatch(pattern, path, FNM_PATHNAME);
          if( rc == 0 ) {
              match = type;
          }
          /* if the pattern requires a dir, but path is not, its still not excluded. */
          if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) {
              match = CSYNC_NOT_EXCLUDED;
          }
      }

      /* if still not excluded, check each component of the path */
      if (match == CSYNC_NOT_EXCLUDED) {
          int trailing_component = 1;
          dname = c_dirname(path);
          bname = c_basename(path);

          if (bname == NULL || dname == NULL) {
              match = CSYNC_NOT_EXCLUDED;
              goto out;
          }

          /* Check each component of the path */
          do {
              /* Do not check the bname if its a file and the pattern matches dirs only. */
              if ( !(trailing_component == 1 /* it is the trailing component */
                     && match_dirs_only      /* but only directories are matched by the pattern */
                     && filetype == CSYNC_FTW_TYPE_FILE) ) {
                  /* Check the name component against the pattern */
                  rc = csync_fnmatch(pattern, bname, 0);
                  if (rc == 0) {
                      match = type;
                  }
              }
              if (!(c_streq(dname, ".") || c_streq(dname, "/"))) {
                  rc = csync_fnmatch(pattern, dname, 0);
                  if (rc == 0) {
                      match = type;
                  }
              }
              trailing_component = 0;
              prev_dname = dname;
              SAFE_FREE(bname);
              bname = c_basename(prev_dname);
              dname = c_dirname(prev_dname);
              SAFE_FREE(prev_dname);

          } while( match == CSYNC_NOT_EXCLUDED && !c_streq(dname, ".")
                     && !c_streq(dname, "/") );
      }
      SAFE_FREE(pattern_stored);
      SAFE_FREE(bname);
      SAFE_FREE(dname);
  }

out:

  return match;
}
Esempio n. 8
0
int csync_init(CSYNC *ctx) {
  int rc;
  time_t timediff = -1;
  char *log = NULL;
  char *exclude = NULL;
  char *lock = NULL;
  char *config = NULL;
#ifndef _WIN32
  char errbuf[256] = {0};
#endif
  
  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }
  ctx->error_code = CSYNC_ERR_NONE;

  /* Do not initialize twice */
  if (ctx->status & CSYNC_STATUS_INIT) {
    return 1;
  }

  /* load log file */
  if (csync_log_init() < 0) {
    ctx->error_code = CSYNC_ERR_LOG;
    fprintf(stderr, "csync_init: logger init failed\n");
    return -1;
  }

  /* create dir if it doesn't exist */
  if (! c_isdir(ctx->options.config_dir)) {
    c_mkdirs(ctx->options.config_dir, 0700);
  }

  if (asprintf(&log, "%s/%s", ctx->options.config_dir, CSYNC_LOG_FILE) < 0) {
    ctx->error_code = CSYNC_ERR_UNSPEC;
    rc = -1;
    goto out;
  }

  /* load log if it exists */
  if (c_isfile(log)) {
    csync_log_load(log);
  } else {
#ifndef _WIN32
    if (c_copy(SYSCONFDIR "/csync/" CSYNC_LOG_FILE, log, 0644) == 0) {
      csync_log_load(log);
    }
#endif
  }

  /* create lock file */
  if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) < 0) {
    ctx->error_code = CSYNC_ERR_UNSPEC;
    rc = -1;
    goto out;
  }

#ifndef _WIN32
  if (csync_lock(lock) < 0) {
    ctx->error_code = CSYNC_ERR_LOCK;
    rc = -1;
    goto out;
  }
#endif

  /* load config file */
  if (asprintf(&config, "%s/%s", ctx->options.config_dir, CSYNC_CONF_FILE) < 0) {
    rc = -1;
    goto out;
  }

  if (csync_config_load(ctx, config) < 0) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Could not load config file %s, using defaults.", config);
  }

#ifndef _WIN32
  /* load global exclude list */
  if (asprintf(&exclude, "%s/csync/%s", SYSCONFDIR, CSYNC_EXCLUDE_FILE) < 0) {
    ctx->error_code = CSYNC_ERR_UNSPEC;
    rc = -1;
    goto out;
  }

  if (csync_exclude_load(ctx, exclude) < 0) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Could not load %s - %s", exclude,
              errbuf);
  }
  SAFE_FREE(exclude);

  /* load exclude list */
  if (asprintf(&exclude, "%s/%s", ctx->options.config_dir, CSYNC_EXCLUDE_FILE) < 0) {
    ctx->error_code = CSYNC_ERR_UNSPEC;
    rc = -1;
    goto out;
  }

  if (csync_exclude_load(ctx, exclude) < 0) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Could not load %s - %s", exclude, 
              errbuf);
  }
#endif

  /* create/load statedb */
  if (! csync_is_statedb_disabled(ctx)) {
    uint64_t h = csync_create_statedb_hash(ctx);
    if (asprintf(&ctx->statedb.file, "%s/csync_statedb_%llu.db",
          ctx->options.config_dir, (long long unsigned int) h) < 0) {
      ctx->error_code = CSYNC_ERR_UNSPEC;
      rc = -1;
      goto out;
    }
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Remote replica: %s", ctx->remote.uri);
    CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Statedb: %s", ctx->statedb.file);

    if (csync_statedb_load(ctx, ctx->statedb.file) < 0) {
      ctx->error_code = CSYNC_ERR_STATEDB_LOAD;
      rc = -1;
      goto out;
    }
  }

  ctx->local.type = LOCAL_REPLICA;

  /* check for uri */
  if ( !ctx->options.local_only_mode && csync_fnmatch("*://*", ctx->remote.uri, 0) == 0) {
    size_t len;
    len = strstr(ctx->remote.uri, "://") - ctx->remote.uri;
    /* get protocol */
    if (len > 0) {
      char *module = NULL;
      /* module name */
      module = c_strndup(ctx->remote.uri, len);
      if (module == NULL) {
        ctx->error_code = CSYNC_ERR_MODULE;
        rc = -1;
        goto out;
      }
      /* load module */
retry_vio_init:
      rc = csync_vio_init(ctx, module, NULL);
      if (rc < 0) {
        len = strlen(module);

        if (len > 0 && module[len-1] == 's') {
          module[len-1] = '\0';
          goto retry_vio_init;
        }
        /* Now vio init finally failed which means a module could not be found. */
        ctx->error_code = CSYNC_ERR_MODULE;
	CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
		  "The csync module %s could not be loaded.", module);
        SAFE_FREE(module);
        goto out;
      }
      SAFE_FREE(module);
      ctx->remote.type = REMOTE_REPLCIA;
    }
  } else {
    ctx->remote.type = LOCAL_REPLICA;
  }

  if(!ctx->options.local_only_mode) {
    if(ctx->module.capabilities.time_sync_required) {
      timediff = csync_timediff(ctx);
      if (timediff > ctx->options.max_time_difference) {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
                  "Clock skew detected. The time difference is greater than %d seconds!",
                  ctx->options.max_time_difference);
        ctx->error_code = CSYNC_ERR_TIMESKEW;
        rc = -1;
        goto out;
      } else if (timediff < 0) {
        /* error code was set in csync_timediff() */
        CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Synchronisation is not possible!");
	/* do not override error code set by timediff */
	if(ctx->error_code == CSYNC_ERR_NONE) {
	  ctx->error_code = CSYNC_ERR_TIMESKEW;
	}
        rc = -1;
        goto out;
      }
    } else {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Module does not need time synchronization.");
    }

    if(ctx->module.capabilities.unix_extensions == -1) { /* detect */
      if (csync_unix_extensions(ctx) < 0) {
        CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Could not detect filesystem type.");
        ctx->error_code = CSYNC_ERR_FILESYSTEM;
        rc = -1;
        goto out;
      }
    } else {
      /* The module specifies the value for the unix_extensions. */
      ctx->options.unix_extensions = ctx->module.capabilities.unix_extensions;
    }
  }

  if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
    ctx->error_code = CSYNC_ERR_TREE;
    rc = -1;
    goto out;
  }

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

  ctx->status = CSYNC_STATUS_INIT;

  /* initialize random generator */
  srand(time(NULL));

  rc = 0;

out:
  SAFE_FREE(log);
  SAFE_FREE(lock);
  SAFE_FREE(exclude);
  SAFE_FREE(config);
  return rc;
}
Esempio n. 9
0
File: csync.c Progetto: gco/csync
int csync_init(CSYNC *ctx) {
  int rc;
  time_t timediff = -1;
  char *exclude = NULL;
  char *lock = NULL;
  char *config = NULL;
  char errbuf[256] = {0};
  if (ctx == NULL) {
    errno = EBADF;
    return -1;
  }

  ctx->status_code = CSYNC_STATUS_OK;

  /* Do not initialize twice */
  if (ctx->status & CSYNC_STATUS_INIT) {
    return 1;
  }

  /* create dir if it doesn't exist */
  if (! c_isdir(ctx->options.config_dir)) {
    c_mkdirs(ctx->options.config_dir, 0700);
  }

  /* create lock file */
  if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) < 0) {
    rc = -1;
    ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
    goto out;
  }

#ifndef _WIN32
  if (csync_lock(lock) < 0) {
    rc = -1;
    ctx->status_code = CSYNC_STATUS_NO_LOCK;
    goto out;
  }
#endif

  /* load config file */
  if (asprintf(&config, "%s/%s", ctx->options.config_dir, CSYNC_CONF_FILE) < 0) {
    ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
    rc = -1;
    goto out;
  }

  rc = csync_config_parse_file(ctx, config);
  if (rc < 0) {
      CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Could not load config file %s, using defaults.", config);
  }

#ifndef _WIN32
  /* load global exclude list */
  if (asprintf(&exclude, "%s/csync/%s", SYSCONFDIR, CSYNC_EXCLUDE_FILE) < 0) {
    rc = -1;
    ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
    goto out;
  }

  if (csync_exclude_load(ctx, exclude) < 0) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Could not load %s - %s", exclude,
              errbuf);
  }
  SAFE_FREE(exclude);
#endif
  /* load exclude list */
  if (asprintf(&exclude, "%s/%s", ctx->options.config_dir,
        CSYNC_EXCLUDE_FILE) < 0) {
    ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
    rc = -1;
    goto out;
  }

  if (csync_exclude_load(ctx, exclude) < 0) {
    strerror_r(errno, errbuf, sizeof(errbuf));
    CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Could not load %s - %s", exclude,
              errbuf);
  }

  /* 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;
      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;
    }
  }

  ctx->local.type = LOCAL_REPLICA;

  /* check for uri */
  if ( !ctx->options.local_only_mode && csync_fnmatch("*://*", ctx->remote.uri, 0) == 0) {
    size_t len;
    len = strstr(ctx->remote.uri, "://") - ctx->remote.uri;
    /* get protocol */
    if (len > 0) {
      char *module = NULL;
      /* module name */
      module = c_strndup(ctx->remote.uri, len);
      if (module == NULL) {
        rc = -1;
        ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
        goto out;
      }
      /* load module */
retry_vio_init:
      rc = csync_vio_init(ctx, module, NULL);
      if (rc < 0) {
        len = strlen(module);

        if (module[len-1] == 's') {
          module[len-1] = '\0';
          goto retry_vio_init;
        }

        SAFE_FREE(module);
        ctx->status_code = CSYNC_STATUS_NO_MODULE;
        goto out;
      }
      SAFE_FREE(module);
      ctx->remote.type = REMOTE_REPLICA;
    }
  } else {
    ctx->remote.type = LOCAL_REPLICA;
  }

  if( !ctx->options.local_only_mode ) {
      timediff = csync_timediff(ctx);
      if (timediff > ctx->options.max_time_difference) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL,
                    "Clock skew detected. The time difference is greater than %d seconds!",
                    ctx->options.max_time_difference);
          ctx->status_code = CSYNC_STATUS_TIMESKEW;
          rc = -1;
          goto out;
      } else if (timediff < 0) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Synchronisation is not possible!");
          ctx->status_code = CSYNC_STATUS_TIMESKEW;
          rc = -1;
          goto out;
      }

      if (csync_unix_extensions(ctx) < 0) {
          CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Could not detect filesystem type.");
          ctx->status_code = CSYNC_STATUS_FILESYSTEM_UNKNOWN;
          rc = -1;
          goto out;
      }
  }

  /* Install progress callbacks in the module. */
  if (ctx->callbacks.file_progress_cb != NULL) {
      int prc;
      prc = csync_vio_set_property(ctx, "file_progress_callback", &ctx->callbacks.file_progress_cb);
      if (prc == -1) {
          /* The module does not support the callbacks */
          CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Could not install file progress callback!");
          ctx->callbacks.file_progress_cb = NULL;
      }
  }

  if (ctx->callbacks.overall_progress_cb != NULL) {
      int prc;
      prc = csync_vio_set_property(ctx, "overall_progress_callback", &ctx->callbacks.overall_progress_cb);
      if (prc == -1) {
          /* The module does not support the callbacks */
          CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Could not install overall progress callback!");
          ctx->callbacks.overall_progress_cb = NULL;
      }
  }

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

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

  ctx->status = CSYNC_STATUS_INIT;

  /* initialize random generator */
  srand(time(NULL));

  rc = 0;

out:
  SAFE_FREE(lock);
  SAFE_FREE(exclude);
  SAFE_FREE(config);
  return rc;
}