From: Olivier Goffart Date: Wed, 25 Jul 2018 14:00:16 +0000 (+0200) Subject: Remove csync_update and csync_reconcile X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~540 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=0a6d2d0f465d003aae21f9dc1b4a73d07337dc73;p=nextcloud-desktop.git Remove csync_update and csync_reconcile I guess some other csync utilities can also be remove dnow but that will be for later --- diff --git a/src/csync/CMakeLists.txt b/src/csync/CMakeLists.txt index 008eb818a..58ddc14d5 100644 --- a/src/csync/CMakeLists.txt +++ b/src/csync/CMakeLists.txt @@ -35,13 +35,6 @@ set(csync_SRCS csync_util.cpp csync_misc.cpp - csync_update.cpp - csync_reconcile.cpp - - csync_rename.cpp - - vio/csync_vio.cpp - std/c_alloc.c std/c_string.c std/c_time.c diff --git a/src/csync/csync.cpp b/src/csync/csync.cpp index 60c44f2c5..3f3d17778 100644 --- a/src/csync/csync.cpp +++ b/src/csync/csync.cpp @@ -25,301 +25,11 @@ #define _GNU_SOURCE #endif -#include -#include -#include -#include -#include -#include - - -#include "c_lib.h" #include "csync_private.h" -#include "csync_exclude.h" -#include "csync_util.h" -#include "csync_misc.h" -#include "std/c_private.h" -#include "csync_update.h" -#include "csync_reconcile.h" -#include "vio/csync_vio.h" - -#include "csync_rename.h" -#include "common/c_jhash.h" #include "common/syncjournalfilerecord.h" -Q_LOGGING_CATEGORY(lcCSync, "nextcloud.sync.csync.csync", QtInfoMsg) - - -csync_s::csync_s(const char *localUri, OCC::SyncJournalDb *statedb) - : statedb(statedb) -{ - size_t len = 0; - - /* remove trailing slashes */ - len = strlen(localUri); - while(len > 0 && localUri[len - 1] == '/') --len; - - local.uri = c_strndup(localUri, len); -} - -int csync_update(CSYNC *ctx) { - int rc = -1; - - if (!ctx) { - errno = EBADF; - return -1; - } - ctx->status_code = CSYNC_STATUS_OK; - - ctx->status_code = CSYNC_STATUS_OK; - - csync_memstat_check(); - - if (!ctx->exclude_traversal_fn) { - qCInfo(lcCSync, "No exclude file loaded or defined!"); - } - - /* update detection for local replica */ - QElapsedTimer timer; - timer.start(); - ctx->current = LOCAL_REPLICA; - - qCInfo(lcCSync, "## Starting local discovery ##"); - - 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 rc; - } - - qCInfo(lcCSync) << "Update detection for local replica took" << timer.elapsed() / 1000. - << "seconds walking" << ctx->local.files.size() << "files"; - csync_memstat_check(); - - /* update detection for remote replica */ - timer.restart(); - ctx->current = REMOTE_REPLICA; - - qCInfo(lcCSync, "## Starting remote discovery ##"); - - rc = csync_ftw(ctx, "", 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 rc; - } - - - qCInfo(lcCSync) << "Update detection for remote replica took" << timer.elapsed() / 1000. - << "seconds walking" << ctx->remote.files.size() << "files"; - csync_memstat_check(); - - ctx->status |= CSYNC_STATUS_UPDATE; - - rc = 0; - return rc; -} - -int csync_reconcile(CSYNC *ctx) { - Q_ASSERT(ctx); - ctx->status_code = CSYNC_STATUS_OK; - - /* Reconciliation for local replica */ - QElapsedTimer timer; - timer.start(); - - ctx->current = LOCAL_REPLICA; - - csync_reconcile_updates(ctx); - - qCInfo(lcCSync) << "Reconciliation for local replica took " << timer.elapsed() / 1000. - << "seconds visiting " << ctx->local.files.size() << " files."; - - /* Reconciliation for remote replica */ - timer.restart(); - - ctx->current = REMOTE_REPLICA; - - csync_reconcile_updates(ctx); - - qCInfo(lcCSync) << "Reconciliation for remote replica took " << timer.elapsed() / 1000. - << "seconds visiting " << ctx->remote.files.size() << " files."; - - ctx->status |= CSYNC_STATUS_RECONCILE; - return 0; -} - -/* - * local visitor which calls the user visitor with repacked stat info. - */ -static int _csync_treewalk_visitor(csync_file_stat_t *cur, CSYNC * ctx, const csync_treewalk_visit_func &visitor) { - csync_s::FileMap *other_tree = nullptr; - - /* we need the opposite tree! */ - switch (ctx->current) { - case LOCAL_REPLICA: - other_tree = &ctx->remote.files; - break; - case REMOTE_REPLICA: - other_tree = &ctx->local.files; - break; - default: - break; - } - - csync_s::FileMap::const_iterator other_file_it = other_tree->find(cur->path); - - if (other_file_it == other_tree->cend()) { - /* Check the renamed path as well. */ - QByteArray renamed_path = csync_rename_adjust_parent_path(ctx, cur->path); - if (renamed_path != cur->path) - other_file_it = other_tree->find(renamed_path); - } - - if (other_file_it == other_tree->cend()) { - /* Check the source path as well. */ - QByteArray renamed_path = csync_rename_adjust_parent_path_source(ctx, cur->path); - if (renamed_path != cur->path) - other_file_it = other_tree->find(renamed_path); - } - - csync_file_stat_t *other = (other_file_it != other_tree->cend()) ? other_file_it->second.get() : nullptr; - - ctx->status_code = CSYNC_STATUS_OK; - - Q_ASSERT(visitor); - return visitor(cur, other); -} - -/* - * treewalk function, called from its wrappers below. - */ -static int _csync_walk_tree(CSYNC *ctx, csync_s::FileMap &tree, const csync_treewalk_visit_func &visitor) -{ - for (auto &pair : tree) { - if (_csync_treewalk_visitor(pair.second.get(), ctx, visitor) < 0) { - return -1; - } - } - return 0; -} - -/* - * wrapper function for treewalk on the remote tree - */ -int csync_walk_remote_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor) -{ - ctx->status_code = CSYNC_STATUS_OK; - ctx->current = REMOTE_REPLICA; - return _csync_walk_tree(ctx, ctx->remote.files, visitor); -} - -/* - * wrapper function for treewalk on the local tree - */ -int csync_walk_local_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor) -{ - ctx->status_code = CSYNC_STATUS_OK; - ctx->current = LOCAL_REPLICA; - return _csync_walk_tree(ctx, ctx->local.files, visitor); -} - -int csync_s::reinitialize() { - int rc = 0; - - status_code = CSYNC_STATUS_OK; - - remote.read_from_db = false; - read_remote_from_db = true; - - local.files.clear(); - remote.files.clear(); - - renames.folder_renamed_from.clear(); - renames.folder_renamed_to.clear(); - - status = CSYNC_STATUS_INIT; - error_string.clear(); - - rc = 0; - return rc; -} - -csync_s::~csync_s() { - SAFE_FREE(local.uri); -} - -void *csync_get_userdata(CSYNC *ctx) { - if (!ctx) { - return nullptr; - } - return ctx->callbacks.userdata; -} - -int csync_set_userdata(CSYNC *ctx, void *userdata) { - if (!ctx) { - return -1; - } - - ctx->callbacks.userdata = userdata; - - return 0; -} - -csync_auth_callback csync_get_auth_callback(CSYNC *ctx) { - if (!ctx) { - return nullptr; - } - - return ctx->callbacks.auth_function; -} - -int csync_set_status(CSYNC *ctx, int status) { - if (!ctx || status < 0) { - return -1; - } - - ctx->status = status; - - return 0; -} - -CSYNC_STATUS csync_get_status(CSYNC *ctx) { - if (!ctx) { - return CSYNC_STATUS_ERROR; - } - - return ctx->status_code; -} - -void csync_request_abort(CSYNC *ctx) -{ - if (ctx) { - ctx->abort = true; - } -} - -void csync_resume(CSYNC *ctx) -{ - if (ctx) { - ctx->abort = false; - } -} - -int csync_abort_requested(CSYNC *ctx) -{ - if (ctx) { - return ctx->abort; - } else { - return (1 == 0); - } -} - std::unique_ptr csync_file_stat_t::fromSyncJournalFileRecord(const OCC::SyncJournalFileRecord &rec) { std::unique_ptr st(new csync_file_stat_t); diff --git a/src/csync/csync.h b/src/csync/csync.h index ccc7b1480..3af8137c0 100644 --- a/src/csync/csync.h +++ b/src/csync/csync.h @@ -193,127 +193,6 @@ struct OCSYNC_EXPORT csync_file_stat_t { */ using CSYNC = struct csync_s; -using csync_auth_callback = int (*)(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata); - -using csync_update_callback = void (*)(bool local, const char *dirUrl, void *userdata); - -using csync_vio_handle_t = void; -using csync_vio_opendir_hook = csync_vio_handle_t *(*)(const char *url, void *userdata); -using csync_vio_readdir_hook = std::unique_ptr (*)(csync_vio_handle_t *dhandle, void *userdata); -using csync_vio_closedir_hook = void (*)(csync_vio_handle_t *dhandle, void *userdata); - -/* Compute the checksum of the given \a checksumTypeId for \a path. */ -using csync_checksum_hook = QByteArray (*)(const QByteArray &path, const QByteArray &otherChecksumHeader, void *userdata); - -/** - * @brief Update detection - * - * @param ctx The context to run the update detection on. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_update(CSYNC *ctx); - -/** - * @brief Reconciliation - * - * @param ctx The context to run the reconciliation on. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_reconcile(CSYNC *ctx); - -/** - * @brief Get the userdata saved in the context. - * - * @param ctx The csync context. - * - * @return The userdata saved in the context, \c nullptr if an error - * occurred. - */ -void *csync_get_userdata(CSYNC *ctx); - -/** - * @brief Save userdata to the context which is passed to the auth - * callback function. - * - * @param ctx The csync context. - * - * @param userdata The userdata to be stored in the context. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_set_userdata(CSYNC *ctx, void *userdata); - -/** - * @brief Get the authentication callback set. - * - * @param ctx The csync context. - * - * @return The authentication callback set or \c nullptr if an error - * occurred. - */ -csync_auth_callback OCSYNC_EXPORT csync_get_auth_callback(CSYNC *ctx); - -/** - * @brief Set the authentication callback. - * - * @param ctx The csync context. - * - * @param cb The authentication callback. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb); - -/* Used for special modes or debugging */ -CSYNC_STATUS OCSYNC_EXPORT csync_get_status(CSYNC *ctx); - -/* Used for special modes or debugging */ -int OCSYNC_EXPORT csync_set_status(CSYNC *ctx, int status); - -using csync_treewalk_visit_func = std::function; - -/** - * @brief Walk the local file tree and call a visitor function for each file. - * - * @param ctx The csync context. - * @param visitor A callback function to handle the file info. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_walk_local_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor); - -/** - * @brief Walk the remote file tree and call a visitor function for each file. - * - * @param ctx The csync context. - * @param visitor A callback function to handle the file info. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_walk_remote_tree(CSYNC *ctx, const csync_treewalk_visit_func &visitor); - -/** - * @brief Aborts the current sync run as soon as possible. Can be called from another thread. - * - * @param ctx The csync context. - */ -void OCSYNC_EXPORT csync_request_abort(CSYNC *ctx); - -/** - * @brief Clears the abort flag. Can be called from another thread. - * - * @param ctx The csync context. - */ -void OCSYNC_EXPORT csync_resume(CSYNC *ctx); - -/** - * @brief Checks for the abort flag, to be used from the modules. - * - * @param ctx The csync context. - */ -int OCSYNC_EXPORT csync_abort_requested(CSYNC *ctx); time_t OCSYNC_EXPORT oc_httpdate_parse( const char *date ); diff --git a/src/csync/csync_private.h b/src/csync/csync_private.h index d64a8c41e..1d55af0b0 100644 --- a/src/csync/csync_private.h +++ b/src/csync/csync_private.h @@ -114,115 +114,6 @@ struct ByteArrayRefHash { uint operator()(const ByteArrayRef &a) const { return */ struct OCSYNC_EXPORT csync_s { - class FileMap : public std::unordered_map, ByteArrayRefHash> { - public: - csync_file_stat_t *findFile(const ByteArrayRef &key) const { - auto it = find(key); - return it != end() ? it->second.get() : nullptr; - } - csync_file_stat_t *findFileMangledName(const ByteArrayRef &key) const { - auto it = begin(); - while (it != end()) { - csync_file_stat_t *fs = it->second.get(); - if (fs->e2eMangledName == key) { - return fs; - } - ++it; - } - return nullptr; - } - }; - - struct { - csync_auth_callback auth_function = nullptr; - void *userdata = nullptr; - csync_update_callback update_callback = nullptr; - void *update_callback_userdata = nullptr; - - /* hooks for checking the white list (uses the update_callback_userdata) */ - int (*checkSelectiveSyncBlackListHook)(void*, const QByteArray &) = nullptr; - int (*checkSelectiveSyncNewFolderHook)(void *, const QByteArray & /* path */, OCC::RemotePermissions) = nullptr; - - - csync_vio_opendir_hook remote_opendir_hook = nullptr; - csync_vio_readdir_hook remote_readdir_hook = nullptr; - csync_vio_closedir_hook remote_closedir_hook = nullptr; - void *vio_userdata = nullptr; - - /* hook for comparing checksums of files during discovery */ - csync_checksum_hook checksum_hook = nullptr; - void *checksum_userdata = nullptr; - - } callbacks; - - OCC::SyncJournalDb *statedb; - - /** - * Function used to determine whether an item is excluded - * during the update phase. - * - * See ExcludedFiles in csync_exclude. - */ - std::function exclude_traversal_fn; - - struct { - std::unordered_map folder_renamed_to; // map from->to - std::unordered_map folder_renamed_from; // map to->from - } renames; - - struct { - char *uri = nullptr; - FileMap files; - } local; - - struct { - FileMap files; - bool read_from_db = false; - OCC::RemotePermissions root_perms; /* Permission of the root folder. (Since the root folder is not in the db tree, we need to keep a separate entry.) */ - } remote; - - /* replica we are currently walking */ - enum csync_replica_e current = LOCAL_REPLICA; - - /* Used in the update phase so changes in the sub directories can be notified to - parent directories */ - csync_file_stat_t *current_fs = nullptr; - - /* csync error code */ - enum CSYNC_STATUS status_code = CSYNC_STATUS_OK; - - /* Some additional string information which is added to the error message corresponding to the error code in errno. - * Usually a filename - */ - QString error_string; - - int status = CSYNC_STATUS_INIT; - volatile bool abort = false; - - /** - * Specify if it is allowed to read the remote tree from the DB (default to enabled) - */ - bool read_remote_from_db = false; - - std::function should_discover_locally_fn; - - bool ignore_hidden_files = true; - - bool upload_conflict_files = false; - - /** - * Whether new remote files should start out as virtual. - */ - bool new_files_are_virtual = false; - - /** - * The suffix to use for virtual files. - */ - QByteArray virtual_file_suffix; - - csync_s(const char *localUri, OCC::SyncJournalDb *statedb); - ~csync_s(); - int reinitialize(); // For some reason MSVC references the copy constructor and/or the assignment operator // if a class is exported. This is a problem since unique_ptr isn't copyable. diff --git a/src/csync/csync_reconcile.cpp b/src/csync/csync_reconcile.cpp deleted file mode 100644 index 4891c506c..000000000 --- a/src/csync/csync_reconcile.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config_csync.h" - -#include -#include "csync_private.h" -#include "csync_reconcile.h" -#include "csync_util.h" -#include "csync_rename.h" -#include "common/c_jhash.h" -#include "common/asserts.h" -#include "common/syncjournalfilerecord.h" - -#include -Q_LOGGING_CATEGORY(lcReconcile, "nextcloud.sync.csync.reconciler", QtInfoMsg) - -// Needed for PRIu64 on MinGW in C++ mode. -#define __STDC_FORMAT_MACROS -#include - -/* Check if a file is ignored because one parent is ignored. - * return the node of the ignored directoy if it's the case, or \c nullptr if it is not ignored */ -static csync_file_stat_t *_csync_check_ignored(csync_s::FileMap *tree, const ByteArrayRef &path) -{ - /* compute the size of the parent directory */ - int parentlen = path.size() - 1; - while (parentlen > 0 && path.at(parentlen) != '/') { - parentlen--; - } - if (parentlen <= 0) { - return nullptr; - } - ByteArrayRef parentPath = path.left(parentlen); - csync_file_stat_t *fs = tree->findFile(parentPath); - if (fs) { - if (fs->instruction == CSYNC_INSTRUCTION_IGNORE) { - /* Yes, we are ignored */ - return fs; - } else { - /* Not ignored */ - return nullptr; - } - } else { - /* Try if the parent itself is ignored */ - return _csync_check_ignored(tree, parentPath); - } -} - - -/** - * The main function in the reconcile pass. - * - * It's called for each entry in the local and remote files by - * csync_reconcile() - * - * Before the reconcile phase the trees already know about changes - * relative to the sync journal. This function's job is to spot conflicts - * between local and remote changes and adjust the nodes accordingly. - * - * See doc/dev/sync-algorithm.md for an overview. - * - * - * Older detail comment: - * - * 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 void _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) { - csync_s::FileMap *our_tree = nullptr; - csync_s::FileMap *other_tree = nullptr; - - /* we need the opposite tree! */ - switch (ctx->current) { - case LOCAL_REPLICA: - our_tree = &ctx->local.files; - other_tree = &ctx->remote.files; - break; - case REMOTE_REPLICA: - our_tree = &ctx->remote.files; - other_tree = &ctx->local.files; - break; - default: - break; - } - - csync_file_stat_t *other = other_tree->findFile(cur->path); - - if (!other) { - if (ctx->current == REMOTE_REPLICA) { - // The file was not found and the other tree is the local one - // check if the path doesn't match a mangled file name - other = other_tree->findFileMangledName(cur->path); - } else { - other = other_tree->findFile(cur->e2eMangledName); - } - } - - if (!other) { - /* Check the renamed path as well. */ - other = other_tree->findFile(csync_rename_adjust_parent_path(ctx, cur->path)); - } - if (!other) { - /* Check if it is ignored */ - other = _csync_check_ignored(other_tree, cur->path); - /* If it is ignored, other->instruction will be IGNORE so this one will also be ignored */ - } - - // If the user adds a file locally check whether a virtual file for that name exists. - // If so, go to "potential conflict" mode by switching the remote entry to be a - // real file. - if (!other - && ctx->current == LOCAL_REPLICA - && cur->instruction == CSYNC_INSTRUCTION_NEW - && cur->type != ItemTypeVirtualFile) { - // Check if we have a virtual file entry in the remote tree - auto virtualFilePath = cur->path; - virtualFilePath.append(ctx->virtual_file_suffix); - other = other_tree->findFile(virtualFilePath); - if (!other) { - /* Check the renamed path as well. */ - other = other_tree->findFile(csync_rename_adjust_parent_path(ctx, virtualFilePath)); - } - if (other && other->type == ItemTypeVirtualFile) { - qCInfo(lcReconcile) << "Found virtual file for local" << cur->path << "in remote tree"; - other->path = cur->path; - other->type = ItemTypeVirtualFileDownload; - other->instruction = CSYNC_INSTRUCTION_EVAL; - } else { - other = nullptr; - } - } - - /* file only found on current replica */ - if (!other) { - 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: - case CSYNC_INSTRUCTION_UPDATE_METADATA: - if (cur->has_ignored_files) { - /* Do not remove a directory that has ignored files */ - break; - } - if (cur->child_modified) { - /* re-create directory that has modified contents */ - cur->instruction = CSYNC_INSTRUCTION_NEW; - break; - } - /* If the local virtual file is gone, it should be reestablished. - * Unless the base file is seen in the local tree now. */ - if (cur->type == ItemTypeVirtualFile - && ctx->current == REMOTE_REPLICA - && cur->path.endsWith(ctx->virtual_file_suffix) - && !other_tree->findFile(cur->path.left(cur->path.size() - ctx->virtual_file_suffix.size()))) { - cur->instruction = CSYNC_INSTRUCTION_NEW; - break; - } - - /* If a virtual file is supposed to be downloaded, the local tree - * will see "foo.owncloud" NONE while the remote might see "foo". - * In the common case of remote NEW we don't want to trigger the REMOVE - * that would normally be done for foo.owncloud since the download for - * "foo" will take care of it. - * If it was removed remotely, or moved remotely, the REMOVE is what we want. - */ - if (cur->type == ItemTypeVirtualFileDownload - && ctx->current == LOCAL_REPLICA - && cur->path.endsWith(ctx->virtual_file_suffix)) { - auto actualOther = other_tree->findFile(cur->path.left(cur->path.size() - ctx->virtual_file_suffix.size())); - if (actualOther - && (actualOther->instruction == CSYNC_INSTRUCTION_NEW - || actualOther->instruction == CSYNC_INSTRUCTION_CONFLICT)) { - cur->instruction = CSYNC_INSTRUCTION_NONE; - break; - } - } - cur->instruction = CSYNC_INSTRUCTION_REMOVE; - break; - case CSYNC_INSTRUCTION_EVAL_RENAME: { - // By default, the EVAL_RENAME decays into a NEW - cur->instruction = CSYNC_INSTRUCTION_NEW; - - bool processedRename = false; - auto renameCandidateProcessing = [&](const QByteArray &basePath) { - if (processedRename) - return; - if (basePath.isEmpty()) - return; - - /* First, check that the file is NOT in our tree (another file with the same name was added) */ - if (our_tree->findFile(basePath)) { - other = nullptr; - qCInfo(lcReconcile, "Origin found in our tree : %s", basePath.constData()); - } else { - /* Find the potential rename source file in the other tree. - * If the renamed file could not be found in the opposite tree, that is because it - * is not longer existing there, maybe because it was renamed or deleted. - * The journal is cleaned up later after propagation. - */ - other = other_tree->findFile(basePath); - qCInfo(lcReconcile, "Rename origin in other tree (%s) %s", - basePath.constData(), other ? "found" : "not found"); - } - - const auto curParentPath = [=]{ - const auto slashPosition = cur->path.lastIndexOf('/'); - if (slashPosition >= 0) { - return cur->path.left(slashPosition); - } else { - return QByteArray(); - } - }(); - auto curParent = our_tree->findFile(curParentPath); - - if (!other - || !other->e2eMangledName.isEmpty() - || (curParent && curParent->isE2eEncrypted)) { - // Stick with the NEW since there's no "other" file - // or if there's an "other" file it involves E2EE and - // we want to always issue delete + upload in such cases - return; - } else if (other->instruction == CSYNC_INSTRUCTION_RENAME) { - // Some other EVAL_RENAME already claimed other. - // We do nothing: maybe a different candidate for - // other is found as well? - qCInfo(lcReconcile, "Other has already been renamed to %s", - other->rename_path.constData()); - } else if (cur->type == ItemTypeDirectory - // The local replica is reconciled first, so the remote tree would - // have either NONE or UPDATE_METADATA if the remote file is safe to - // move. - // In the remote replica, REMOVE is also valid (local has already - // been reconciled). NONE can still happen if the whole parent dir - // was set to REMOVE by the local reconcile. - || other->instruction == CSYNC_INSTRUCTION_NONE - || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA - || other->instruction == CSYNC_INSTRUCTION_REMOVE) { - qCInfo(lcReconcile, "Switching %s to RENAME to %s", - other->path.constData(), cur->path.constData()); - other->instruction = CSYNC_INSTRUCTION_RENAME; - other->rename_path = cur->path; - if( !cur->file_id.isEmpty() ) { - other->file_id = cur->file_id; - } - if (ctx->current == LOCAL_REPLICA) { - // Keep the local mtime. - other->modtime = cur->modtime; - } - other->inode = cur->inode; - cur->instruction = CSYNC_INSTRUCTION_NONE; - // We have consumed 'other': exit this loop to not consume another one. - processedRename = true; - } else if (our_tree->findFile(csync_rename_adjust_parent_path(ctx, other->path)) == cur) { - // If we're here, that means that the other side's reconcile will be able - // to work against cur: The filename itself didn't change, only a parent - // directory was renamed! In that case it's safe to ignore the rename - // since the parent directory rename will already deal with it. - - // Local: The remote reconcile will be able to deal with this. - // Remote: The local replica has already dealt with this. - // See the EVAL_RENAME case when other was found directly. - qCInfo(lcReconcile, "File in a renamed directory, other side's instruction: %d", - other->instruction); - cur->instruction = CSYNC_INSTRUCTION_NONE; - } else { - // This can, for instance, happen when there was a local change in other - // and the instruction in the local tree is NEW while cur has EVAL_RENAME - // due to a remote move of the same file. In these scenarios we just - // want the instruction to stay NEW. - qCInfo(lcReconcile, "Other already has instruction %d", - other->instruction); - } - }; - - if (ctx->current == LOCAL_REPLICA) { - /* use the old name to find the "other" node */ - OCC::SyncJournalFileRecord base; - qCInfo(lcReconcile, "Finding rename origin through inode %" PRIu64 "", - cur->inode); - ctx->statedb->getFileRecordByInode(cur->inode, &base); - renameCandidateProcessing(base._path); - } else { - ASSERT(ctx->current == REMOTE_REPLICA); - - // The update phase has already mapped out all dir->dir renames, check the - // path that is consistent with that first. Otherwise update mappings and - // reconcile mappings might disagree, leading to odd situations down the - // line. - auto basePath = csync_rename_adjust_full_path_source(ctx, cur->path); - if (basePath != cur->path) { - qCInfo(lcReconcile, "Trying rename origin by csync_rename mapping %s", - basePath.constData()); - // We go through getFileRecordsByFileId to ensure the basePath - // computed in this way also has the expected fileid. - ctx->statedb->getFileRecordsByFileId(cur->file_id, - [&](const OCC::SyncJournalFileRecord &base) { - if (base._path == basePath) - renameCandidateProcessing(basePath); - }); - } - - // Also feed all the other files with the same fileid if necessary - if (!processedRename) { - qCInfo(lcReconcile, "Finding rename origin through file ID %s", - cur->file_id.constData()); - ctx->statedb->getFileRecordsByFileId(cur->file_id, - [&](const OCC::SyncJournalFileRecord &base) { renameCandidateProcessing(base._path); }); - } - } - - break; - } - default: - break; - } - } else { - /* - * file found on the other replica - */ - - switch (cur->instruction) { - case CSYNC_INSTRUCTION_UPDATE_METADATA: - if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) { - // Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last. - cur->instruction = CSYNC_INSTRUCTION_NONE; - } - break; - case CSYNC_INSTRUCTION_EVAL_RENAME: - /* If the file already exist on the other side, we have a conflict. - Abort the rename and consider it is a new file. */ - cur->instruction = CSYNC_INSTRUCTION_NEW; - /* fall through */ - /* file on current replica is changed or new */ - case CSYNC_INSTRUCTION_EVAL: - case CSYNC_INSTRUCTION_NEW: - switch (other->instruction) { - /* file on other replica is changed or new */ - case CSYNC_INSTRUCTION_NEW: - case CSYNC_INSTRUCTION_EVAL: - // PORTED - - break; - /* file on the other replica has not been modified */ - case CSYNC_INSTRUCTION_NONE: - case CSYNC_INSTRUCTION_UPDATE_METADATA: - if (cur->type != other->type) { - // If the type of the entity changed, it's like NEW, but - // needs to delete the other entity first. - cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE; - other->instruction = CSYNC_INSTRUCTION_NONE; - } else if (cur->type == ItemTypeDirectory) { - cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - other->instruction = CSYNC_INSTRUCTION_NONE; - } else { - if (cur->instruction != CSYNC_INSTRUCTION_NEW - && cur->instruction != CSYNC_INSTRUCTION_SYNC) { - cur->instruction = CSYNC_INSTRUCTION_SYNC; - } - other->instruction = CSYNC_INSTRUCTION_NONE; - } - break; - case CSYNC_INSTRUCTION_IGNORE: - cur->instruction = CSYNC_INSTRUCTION_IGNORE; - break; - default: - break; - } - // Ensure we're not leaving discovery-only instructions - // in place. This can happen, for instance, when other's - // instruction is EVAL_RENAME because the parent dir was renamed. - // NEW is safer than EVAL because it will end up with - // propagation unless it's changed by something, and EVAL and - // NEW are treated equivalently during reconcile. - if (cur->instruction == CSYNC_INSTRUCTION_EVAL) - cur->instruction = CSYNC_INSTRUCTION_NEW; - break; - case CSYNC_INSTRUCTION_NONE: - // NONE/NONE on virtual files might become a REMOVE if the base file - // is found in the local tree. - if (cur->type == ItemTypeVirtualFile - && other->instruction == CSYNC_INSTRUCTION_NONE - && ctx->current == LOCAL_REPLICA - && cur->path.endsWith(ctx->virtual_file_suffix) - && ctx->local.files.findFile(cur->path.left(cur->path.size() - ctx->virtual_file_suffix.size()))) { - cur->instruction = CSYNC_INSTRUCTION_REMOVE; - } - break; - default: - break; - } - } - - //hide instruction NONE messages when log level is set to debug, - //only show these messages on log level trace - const char *repo = ctx->current == REMOTE_REPLICA ? "server" : "client"; - if(cur->instruction ==CSYNC_INSTRUCTION_NONE) - { - if(cur->type == ItemTypeDirectory) - { - qCDebug(lcReconcile, - "%-30s %s dir: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path.constData()); - } - else - { - qCDebug(lcReconcile, - "%-30s %s file: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path.constData()); - } - } - else - { - if(cur->type == ItemTypeDirectory) - { - qCInfo(lcReconcile, - "%-30s %s dir: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path.constData()); - } - else - { - qCInfo(lcReconcile, - "%-30s %s file: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path.constData()); - } - } -} - -void csync_reconcile_updates(CSYNC *ctx) { - csync_s::FileMap *tree = nullptr; - - switch (ctx->current) { - case LOCAL_REPLICA: - tree = &ctx->local.files; - break; - case REMOTE_REPLICA: - tree = &ctx->remote.files; - break; - default: - break; - } - - for (auto &pair : *tree) { - _csync_merge_algorithm_visitor(pair.second.get(), ctx); - } -} - -/* vim: set ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_reconcile.h b/src/csync/csync_reconcile.h deleted file mode 100644 index 4b69250d0..000000000 --- a/src/csync/csync_reconcile.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _CSYNC_RECONCILE_H -#define _CSYNC_RECONCILE_H - -/** - * @file csync_reconcile.h - * - * @brief Reconciliation - * - * The most important component is the update detector, because the reconciler - * depends on it. The correctness of reconciler is mandatory because it can - * damage a filesystem. It decides which file: - * - * - stays untouched - * - has a conflict - * - gets synchronized - * - or is deleted. - * - * @defgroup csyncReconcilationInternals csync reconciliation internals - * @ingroup csyncInternalAPI - * - * @{ - */ - -/** - * @brief Reconcile the files. - * - * @param ctx The csync context to use. - * - * @todo Add an argument to set the algorithm to use. - */ -void OCSYNC_EXPORT csync_reconcile_updates(CSYNC *ctx); - -/** - * }@ - */ -#endif /* _CSYNC_RECONCILE_H */ - -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_rename.cpp b/src/csync/csync_rename.cpp deleted file mode 100644 index 80b3f1439..000000000 --- a/src/csync/csync_rename.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2012 by Olivier Goffart - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; 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_rename.h" - -#include - -static ByteArrayRef _parentDir(const ByteArrayRef &path) { - int len = path.length(); - while(len > 0 && path.at(len-1)!='/') len--; - while(len > 0 && path.at(len-1)=='/') len--; - return path.left(len); -} - -void csync_rename_record(CSYNC* ctx, const QByteArray &from, const QByteArray &to) -{ - ctx->renames.folder_renamed_to[from] = to; - ctx->renames.folder_renamed_from[to] = from; -} - -QByteArray csync_rename_adjust_parent_path(CSYNC *ctx, const QByteArray &path) -{ - if (ctx->renames.folder_renamed_to.empty()) - return path; - for (auto p = _parentDir(path); !p.isEmpty(); p = _parentDir(p)) { - auto it = ctx->renames.folder_renamed_to.find(p); - if (it != ctx->renames.folder_renamed_to.end()) { - QByteArray rep = it->second + path.mid(p.length()); - return rep; - } - } - return path; -} - -QByteArray csync_rename_adjust_parent_path_source(CSYNC *ctx, const QByteArray &path) -{ - if (ctx->renames.folder_renamed_from.empty()) - return path; - for (ByteArrayRef p = _parentDir(path); !p.isEmpty(); p = _parentDir(p)) { - auto it = ctx->renames.folder_renamed_from.find(p); - if (it != ctx->renames.folder_renamed_from.end()) { - QByteArray rep = it->second + path.mid(p.length()); - return rep; - } - } - return path; -} - -QByteArray csync_rename_adjust_full_path_source(CSYNC *ctx, const QByteArray &path) -{ - if (ctx->renames.folder_renamed_from.empty()) - return path; - for (ByteArrayRef p = path; !p.isEmpty(); p = _parentDir(p)) { - auto it = ctx->renames.folder_renamed_from.find(p); - if (it != ctx->renames.folder_renamed_from.end()) { - QByteArray rep = it->second + path.mid(p.length()); - return rep; - } - } - return path; -} - -bool csync_rename_count(CSYNC *ctx) { - return ctx->renames.folder_renamed_from.size(); -} diff --git a/src/csync/csync_rename.h b/src/csync/csync_rename.h deleted file mode 100644 index 825f45f4e..000000000 --- a/src/csync/csync_rename.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2012 by Olivier Goffart - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -#include "csync.h" - -/* Return the final destination path of a given patch in case of renames - * - * Does only map the parent directories. If the directory "A" is renamed to - * "B" then this function will not map "A" to "B". Only "A/foo" -> "B/foo". -*/ -QByteArray OCSYNC_EXPORT csync_rename_adjust_parent_path(CSYNC *ctx, const QByteArray &path); - -/* Return the source of a given path in case of renames */ -QByteArray OCSYNC_EXPORT csync_rename_adjust_parent_path_source(CSYNC *ctx, const QByteArray &path); - -/* like the parent_path variant, but applying to the full path */ -QByteArray OCSYNC_EXPORT csync_rename_adjust_full_path_source(CSYNC *ctx, const QByteArray &path); - -void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const QByteArray &from, const QByteArray &to); -/* Return the amount of renamed item recorded */ -bool OCSYNC_EXPORT csync_rename_count(CSYNC *ctx); diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp deleted file mode 100644 index 12448ed68..000000000 --- a/src/csync/csync_update.cpp +++ /dev/null @@ -1,673 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include - -#include "c_lib.h" - -#include "csync_private.h" -#include "csync_exclude.h" -#include "csync_update.h" -#include "csync_util.h" -#include "csync_misc.h" - -#include "vio/csync_vio.h" - -#include "csync_rename.h" - -#include "common/utility.h" -#include "common/asserts.h" - -#include -#include - -// Needed for PRIu64 on MinGW in C++ mode. -#define __STDC_FORMAT_MACROS -#include - -Q_LOGGING_CATEGORY(lcUpdate, "nextcloud.sync.csync.updater", QtInfoMsg) - -#ifdef NO_RENAME_EXTENSION -/* Return true if the two path have the same extension. false otherwise. */ -static bool _csync_sameextension(const char *p1, const char *p2) { - /* Find pointer to the extensions */ - const char *e1 = strrchr(p1, '.'); - const char *e2 = strrchr(p2, '.'); - - /* If the found extension contains a '/', it is because the . was in the folder name - * => no extensions */ - if (e1 && strchr(e1, '/')) e1 = nullptr; - if (e2 && strchr(e2, '/')) e2 = nullptr; - - /* If none have extension, it is the same extension */ - if (!e1 && !e2) - return true; - - /* c_streq takes care of the rest */ - return c_streq(e1, e2); -} -#endif - -static QByteArray _rel_to_abs(CSYNC* ctx, const QByteArray &relativePath) { - return QByteArray() % const_cast(ctx->local.uri) % '/' % relativePath; -} - -/* Return true if two mtime are considered equal - * We consider mtime that are one hour difference to be equal if they are one hour appart - * because on some system (FAT) the date is changing when the daylight saving is changing */ -static bool _csync_mtime_equal(time_t a, time_t b) -{ - if (a == b) - return true; - - /* 1h of difference +- 1 second because the accuracy of FAT is 2 seconds (#2438) */ - if (fabs(3600 - fabs(difftime(a, b))) < 2) - return true; - - return false; -} - -/** - * The main function of the discovery/update pass. - * - * It's called (indirectly) by csync_update(), once for each entity in the - * local filesystem and once for each entity in the server data. - * - * It has two main jobs: - * - figure out whether anything happened compared to the sync journal - * and set (primarily) the instruction flag accordingly - * - build the ctx->local.tree / ctx->remote.tree - * - * See doc/dev/sync-algorithm.md for an overview. - */ -static int _csync_detect_update(CSYNC *ctx, std::unique_ptr fs) { - Q_ASSERT(fs); - OCC::SyncJournalFileRecord base; - CSYNC_EXCLUDE_TYPE excluded = CSYNC_NOT_EXCLUDED; - if (fs->type == ItemTypeSkip) { - excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED; - } else { - /* Check if file is excluded */ - if (ctx->exclude_traversal_fn) - excluded = ctx->exclude_traversal_fn(fs->path, fs->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->is_hidden - && !fs->path.endsWith(".sync-exclude.lst")) { - qCInfo(lcUpdate, "file excluded because it is a hidden file: %s", fs->path.constData()); - excluded = CSYNC_FILE_EXCLUDE_HIDDEN; - } - } else { - /* File is ignored because it's matched by a user- or system exclude pattern. */ - qCInfo(lcUpdate, "%s excluded (%d)", fs->path.constData(), 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, fs->path)) { - return 1; - } - } - - - if (fs->type == ItemTypeFile ) { - if (fs->modtime == 0) { - qCInfo(lcUpdate, "file: %s - mtime is zero!", fs->path.constData()); - } - } - -#if 0 // PORTED - if (excluded > CSYNC_NOT_EXCLUDED || fs->type == ItemTypeSoftLink) { - fs->instruction = CSYNC_INSTRUCTION_IGNORE; - if (ctx->current_fs) { - ctx->current_fs->has_ignored_files = true; - } - - goto out; - } -#endif - - /* 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(!ctx->statedb->getFileRecord(fs->path, &base)) { - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - - /* - * When file is encrypted it's phash (path hash) will not match the local file phash, - * we could match the e2eMangledName but that might be slow wihout index, and it's - * not UNIQUE at the moment. - */ - if (!base.isValid()) { - if(!ctx->statedb->getFileRecordByE2eMangledName(fs->path, &base)) { - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - } - - // The db entry might be for a virtual file, so look for that on the - // remote side. If we find one, change the current fs to look like a - // virtual file too, because that's what one would see if the remote - // db was filled from the database. - if (ctx->current == REMOTE_REPLICA && !base.isValid() && fs->type == ItemTypeFile) { - auto virtualFilePath = fs->path; - virtualFilePath.append(ctx->virtual_file_suffix); - ctx->statedb->getFileRecord(virtualFilePath, &base); - if (base.isValid() && base._type == ItemTypeVirtualFile) { - fs->type = ItemTypeVirtualFile; - fs->path = virtualFilePath; - } else { - base = OCC::SyncJournalFileRecord(); - } - } - - if(base.isValid()) { /* there is an entry in the database */ - // When the file is loaded from the file system it misses - // the e2e mangled name and e2e encryption status - fs->isE2eEncrypted = base._isE2eEncrypted; - if (fs->e2eMangledName.isEmpty() && !base._e2eMangledName.isEmpty()) { - fs->e2eMangledName = base._e2eMangledName; - fs->path = base._path; - } - - /* we have an update! */ - qCInfo(lcUpdate, "Database entry found for %s, compare: %" PRId64 " <-> %" PRId64 - ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64 - ", size: %" PRId64 " <-> %" PRId64 ", perms: %x <-> %x" - ", checksum: %s <-> %s, type: %d <-> %d, ignore: %d, e2e: %s", - base._path.constData(), ((int64_t) fs->modtime), ((int64_t) base._modtime), - fs->etag.constData(), base._etag.constData(), (uint64_t) fs->inode, (uint64_t) base._inode, - (uint64_t) fs->size, (uint64_t) base._fileSize, *reinterpret_cast(&fs->remotePerm), *reinterpret_cast(&base._remotePerm), - fs->checksumHeader.constData(), base._checksumHeader.constData(), - fs->type, base._type, - base._serverHasIgnoredFiles, base._e2eMangledName.constData()); - - // If the db suggests a virtual file should be downloaded, - // treat the file as new on the remote. - if (ctx->current == REMOTE_REPLICA && base._type == ItemTypeVirtualFileDownload) { - fs->instruction = CSYNC_INSTRUCTION_NEW; - fs->type = ItemTypeVirtualFileDownload; - goto out; - } - - // If what the db thinks is a virtual file is actually a file/dir, - // treat it as new locally. - if (ctx->current == LOCAL_REPLICA - && (base._type == ItemTypeVirtualFile || base._type == ItemTypeVirtualFileDownload) - && fs->type != ItemTypeVirtualFile) { - fs->instruction = CSYNC_INSTRUCTION_EVAL; - goto out; - } - - if (ctx->current == REMOTE_REPLICA && fs->etag != base._etag) { - fs->instruction = CSYNC_INSTRUCTION_EVAL; - - if (fs->type == ItemTypeVirtualFile) { - // If the local thing is a virtual file, we just update the metadata - fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } else if (base._type != fs->type) { - // Preserve the EVAL flag later on if the type has changed. - fs->child_modified = true; - } - - goto out; - } - if (ctx->current == LOCAL_REPLICA && - (!_csync_mtime_equal(fs->modtime, base._modtime) - // zero size in statedb can happen during migration - || (base._fileSize != 0 && fs->size != base._fileSize))) { - // PORTED: EML - - // Preserve the EVAL flag later on if the type has changed. - if (base._type != fs->type) { - fs->child_modified = true; - } - - fs->instruction = CSYNC_INSTRUCTION_EVAL; - goto out; - } - bool metadata_differ = (ctx->current == REMOTE_REPLICA && (fs->file_id != base._fileId - || fs->remotePerm != base._remotePerm)) - || (ctx->current == LOCAL_REPLICA && fs->inode != base._inode); - if (fs->type == ItemTypeDirectory && 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 - */ - qCInfo(lcUpdate, "Reading from database: %s", fs->path.constData()); - ctx->remote.read_from_db = 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 ) { - fs->has_ignored_files = base._serverHasIgnoredFiles; - } - if (metadata_differ) { - /* file id or permissions has changed. Which means we need to update them in the DB. */ - qCInfo(lcUpdate, "Need to update metadata for: %s", fs->path.constData()); - fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } else { - fs->instruction = CSYNC_INSTRUCTION_NONE; - } - } else { - /* check if it's a file and has been renamed */ - if (ctx->current == LOCAL_REPLICA) { - /* ... PORTED */ - - } else { /*... PORTED ... */ - } - } - -out: - -#if 0 -PORTED - /* Set the ignored error string. */ - if (fs->instruction == CSYNC_INSTRUCTION_IGNORE) { - if( fs->type == ItemTypeSoftLink ) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */ - } else { - if (excluded == CSYNC_FILE_EXCLUDE_LIST) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN; - } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED; - } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE; - } else if (excluded == CSYNC_FILE_EXCLUDE_CANNOT_ENCODE) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_CANNOT_ENCODE; - } - } - } - if (fs->instruction != CSYNC_INSTRUCTION_NONE - && fs->instruction != CSYNC_INSTRUCTION_IGNORE - && fs->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA - && fs->type != ItemTypeDirectory) { - fs->child_modified = true; - } -#endif - - // If conflict files are uploaded, they won't be marked as IGNORE / CSYNC_FILE_EXCLUDE_CONFLICT - // but we still want them marked! - if (ctx->upload_conflict_files) { - if (OCC::Utility::isConflictFile(fs->path.constData())) { - fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE; - } - } - - ctx->current_fs = fs.get(); - - qCInfo(lcUpdate, "file: %s, instruction: %s <<=", fs->path.constData(), - csync_instruction_str(fs->instruction)); - - QByteArray path = fs->path; - switch (ctx->current) { - case LOCAL_REPLICA: - ctx->local.files[path] = std::move(fs); - break; - case REMOTE_REPLICA: - ctx->remote.files[path] = std::move(fs); - break; - default: - break; - } - - return 0; -} - -int csync_walker(CSYNC *ctx, std::unique_ptr fs) { - int rc = -1; - - if (ctx->abort) { - qCDebug(lcUpdate, "Aborted!"); - ctx->status_code = CSYNC_STATUS_ABORTED; - return -1; - } - - switch (fs->type) { - case ItemTypeFile: - if (ctx->current == REMOTE_REPLICA) { - qCDebug(lcUpdate, "file: %s [file_id=%s size=%" PRIu64 "]", fs->path.constData(), fs->file_id.constData(), fs->size); - } else { - qCDebug(lcUpdate, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", fs->path.constData(), fs->inode, fs->size); - } - break; - case ItemTypeDirectory: /* enter directory */ - if (ctx->current == REMOTE_REPLICA) { - qCDebug(lcUpdate, "directory: %s [file_id=%s]", fs->path.constData(), fs->file_id.constData()); - } else { - qCDebug(lcUpdate, "directory: %s [inode=%" PRIu64 "]", fs->path.constData(), fs->inode); - } - break; - case ItemTypeSoftLink: - qCInfo(lcUpdate, "symlink: %s - not supported", fs->path.constData()); - break; - default: - qCInfo(lcUpdate, "item: %s - item type %d not iterated", fs->path.constData(), fs->type); - return 0; - } - - rc = _csync_detect_update(ctx, std::move(fs)); - - return rc; -} - -static bool fill_tree_from_db(CSYNC *ctx, const char *uri, bool singleFile = false) -{ - int64_t count = 0; - QByteArray skipbase; - auto &files = ctx->current == LOCAL_REPLICA ? ctx->local.files : ctx->remote.files; - auto rowCallback = [ctx, &count, &skipbase, &files](const OCC::SyncJournalFileRecord &rec) { - if (ctx->current == REMOTE_REPLICA) { - /* When selective sync is used, the database may have subtrees with a parent - * whose etag is _invalid_. These are ignored and shall not appear in the - * remote tree. - * Sometimes folders that are not ignored by selective sync get marked as - * _invalid_, but that is not a problem as the next discovery will retrieve - * their correct etags again and we don't run into this case. - */ - if (rec._etag == "_invalid_") { - qCInfo(lcUpdate, "%s selective sync excluded", rec._path.constData()); - skipbase = rec._path; - skipbase += '/'; - return; - } - - /* Skip over all entries with the same base path. Note that this depends - * strongly on the ordering of the retrieved items. */ - if (!skipbase.isEmpty() && rec._path.startsWith(skipbase)) { - qCDebug(lcUpdate, "%s selective sync excluded because the parent is", rec._path.constData()); - return; - } else { - skipbase.clear(); - } - } - - std::unique_ptr st = csync_file_stat_t::fromSyncJournalFileRecord(rec); - - /* Check for exclusion from the tree. - * Note that this is only a safety net in case the ignore list changes - * without a full remote discovery being triggered. */ - CSYNC_EXCLUDE_TYPE excluded = CSYNC_NOT_EXCLUDED; - if (ctx->exclude_traversal_fn) - excluded = ctx->exclude_traversal_fn(st->path, st->type); - if (excluded != CSYNC_NOT_EXCLUDED) { - qInfo(lcUpdate, "%s excluded from db read (%d)", st->path.constData(), excluded); - - if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE - || excluded == CSYNC_FILE_SILENTLY_EXCLUDED) { - return; - } - - st->instruction = CSYNC_INSTRUCTION_IGNORE; - } - - /* store into result list. */ - files[rec._path] = std::move(st); - ++count; - }; - - if (singleFile) { - OCC::SyncJournalFileRecord record; - if (ctx->statedb->getFileRecord(QByteArray(uri), &record) && record.isValid()) { - rowCallback(record); - } else { - ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR; - return false; - } - } else { - if (!ctx->statedb->getFilesBelowPath(uri, rowCallback)) { - ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR; - return false; - } - } - qInfo(lcUpdate, "%" PRId64 " entries read below path %s from db.", count, uri); - - return true; -} - -/* set the current item to an ignored state. - * If the item is set to ignored, the update phase continues, ie. its not a hard error */ -static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status ) -{ - if(!ctx) { - return false; - } - - if (ctx->current_fs) { - ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE; - ctx->current_fs->error_status = status; - /* If a directory has ignored files, put the flag on the parent directory as well */ - if( previous_fs ) { - previous_fs->has_ignored_files = true; - } - return true; - } - return false; -} - -/* File tree walker */ -int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, - unsigned int depth) { - QByteArray filename; - QByteArray fullpath; - csync_vio_handle_t *dh = nullptr; - std::unique_ptr dirent; - csync_file_stat_t *previous_fs = nullptr; - int read_from_db = 0; - int rc = 0; - - bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db); - const char *db_uri = uri; - - if (ctx->current == LOCAL_REPLICA && ctx->should_discover_locally_fn) { - const char *local_uri = uri + strlen(ctx->local.uri); - if (*local_uri == '/') - ++local_uri; - db_uri = local_uri; - do_read_from_db = !ctx->should_discover_locally_fn(QByteArray(local_uri)); - } - - if (!depth) { - mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_INDIVIDUAL_TOO_DEEP); - return 0; - } - - read_from_db = ctx->remote.read_from_db; - - // if the etag of this dir is still the same, its content is restored from the - // database. - if( do_read_from_db ) { - if(!fill_tree_from_db(ctx, db_uri)) { - errno = ENOENT; - ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR; - goto error; - } - return 0; - } - - - while (true) { - // Get the next item in the directory - errno = 0; - dirent = csync_vio_readdir(ctx, dh); - if (!dirent) { - if (errno != 0) { - // Note: Windows vio converts any error into EACCES - qCWarning(lcUpdate, "readdir failed for file in %s - errno %d", uri, errno); - goto error; - } - - // Normal case: End of items in directory - break; - } - - /* Conversion error */ - if (dirent->path.isEmpty() && !dirent->original_path.isEmpty()) { - ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS; - ctx->error_string = QString::fromUtf8(dirent->original_path); - dirent->original_path.clear(); - goto error; - } - - // At this point dirent->path only contains the file name. - filename = dirent->path; - if (filename.isEmpty()) { - ctx->status_code = CSYNC_STATUS_READDIR_ERROR; - goto error; - } - - /* skip "." and ".." */ - if ( filename == "." || filename == "..") { - continue; - } - - if (uri[0] == '\0') { - fullpath = filename; - } else { - fullpath = QByteArray() % uri % '/' % filename; - } - - // When encountering virtual files, read the relevant - // entry from the db instead. - if (ctx->current == LOCAL_REPLICA - && dirent->type == ItemTypeFile - && filename.endsWith(ctx->virtual_file_suffix)) { - QByteArray db_uri = fullpath.mid(strlen(ctx->local.uri) + 1); - - if( ! fill_tree_from_db(ctx, db_uri.constData(), true) ) { - qCWarning(lcUpdate) << "Virtual file without db entry for" << filename; - QFile::remove(fullpath); - } - - continue; - } - - -#if 0 - // Now process to have a relative path to the sync root for the local replica, or to the data root on the remote. - dirent->path = fullpath; - if (ctx->current == LOCAL_REPLICA) { - ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri - // "len + 1" to include the slash in-between. - size_t uriLength = strlen(ctx->local.uri); - dirent->path = dirent->path.mid(OCC::Utility::convertSizeToInt(uriLength) + 1); - } - - previous_fs = ctx->current_fs; - bool recurse = dirent->type == ItemTypeDirectory; - - /* Call walker function for each file */ - rc = fn(ctx, std::move(dirent)); - /* this function may update ctx->current and ctx->read_from_db */ - - if (rc < 0) { - if (CSYNC_STATUS_IS_OK(ctx->status_code)) { - ctx->status_code = CSYNC_STATUS_UPDATE_ERROR; - } - - ctx->current_fs = previous_fs; - goto error; - } - -PORTED - if (recurse && rc == 0 - && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) { - rc = csync_ftw(ctx, fullpath, fn, depth - 1); - if (rc < 0) { - ctx->current_fs = previous_fs; - goto error; - } - - if (ctx->current_fs && !ctx->current_fs->child_modified - && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) { - if (ctx->current == REMOTE_REPLICA) { - ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } else { - ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE; - } - } - - if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) { - /* If a directory has ignored files, put the flag on the parent directory as well */ - previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files; - } - } - - if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) { - /* If a directory has modified files, put the flag on the parent directory as well */ - previous_fs->child_modified = ctx->current_fs->child_modified; - } - - ctx->current_fs = previous_fs; - ctx->remote.read_from_db = read_from_db; -#endif - } - - csync_vio_closedir(ctx, dh); - qCInfo(lcUpdate, " <= Closing walk for %s with read_from_db %d", uri, read_from_db); - - return rc; - -error: - ctx->remote.read_from_db = read_from_db; - if (dh) { - csync_vio_closedir(ctx, dh); - } - return -1; -} - -/* vim: set ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_update.h b/src/csync/csync_update.h deleted file mode 100644 index 66afd7c07..000000000 --- a/src/csync/csync_update.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _CSYNC_UPDATE_H -#define _CSYNC_UPDATE_H - -#include "csync.h" - -/** - * @file csync_update.h - * - * @brief Update Detection - * - * TODO - * - * @defgroup csyncUpdateDetectionInternals csync update detection internals - * @ingroup csyncInternalAPI - * - * @{ - */ - -using csync_walker_fn = int (*)(CSYNC *ctx, std::unique_ptr fs); - -/** - * @brief The walker function to use in the file tree walker. - * - * @param ctx The used csync context. - * - * @param file The file we are researching. - * - * @param fs The stat information we got. - * - * @param flag The flag describing the type of the file. - * - * @return 0 on success, < 0 on error. - */ -int csync_walker(CSYNC *ctx, std::unique_ptr fs); - -/** - * @brief The file tree walker. - * - * This function walks through the directory tree that is located under the uri - * specified. It calls a walker function which is provided as a function pointer - * once for each entry in the tree. By default, directories are handled before - * the files and subdirectories they contain (pre-order traversal). - * - * @param ctx The csync context to use. - * - * @param uri The uri/path to the directory tree to walk. - * - * @param fn The walker function to call once for each entry. - * - * @param depth The max depth to walk down the tree. - * - * @return 0 on success, < 0 on error. If fn() returns non-zero, then the tree - * walk is terminated and the value returned by fn() is returned as the - * result. - */ -int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, - unsigned int depth); - -#endif /* _CSYNC_UPDATE_H */ - -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_util.cpp b/src/csync/csync_util.cpp index 1daedafce..d36677b25 100644 --- a/src/csync/csync_util.cpp +++ b/src/csync/csync_util.cpp @@ -32,7 +32,6 @@ #include "common/c_jhash.h" #include "csync_util.h" -#include "vio/csync_vio.h" Q_LOGGING_CATEGORY(lcCSyncUtils, "nextcloud.sync.csync.utils", QtInfoMsg) diff --git a/src/csync/vio/csync_vio.cpp b/src/csync/vio/csync_vio.cpp deleted file mode 100644 index 31f168a6c..000000000 --- a/src/csync/vio/csync_vio.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include "common/asserts.h" - -#include "csync_private.h" -#include "csync_util.h" -#include "vio/csync_vio.h" -#include "vio/csync_vio_local.h" -#include "common/c_jhash.h" - -csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) { - switch(ctx->current) { - case REMOTE_REPLICA: - ASSERT(!ctx->remote.read_from_db); - return ctx->callbacks.remote_opendir_hook(name, ctx->callbacks.vio_userdata); - break; - case LOCAL_REPLICA: - if( ctx->callbacks.update_callback ) { - ctx->callbacks.update_callback(/*local=*/true, name, ctx->callbacks.update_callback_userdata); - } - return csync_vio_local_opendir(name); - break; - default: - ASSERT(false); - } - return nullptr; -} - -int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) { - int rc = -1; - - if (!dhandle) { - errno = EBADF; - return -1; - } - - switch(ctx->current) { - case REMOTE_REPLICA: - ASSERT(!ctx->remote.read_from_db); - ctx->callbacks.remote_closedir_hook(dhandle, ctx->callbacks.vio_userdata); - rc = 0; - break; - case LOCAL_REPLICA: - rc = csync_vio_local_closedir(dhandle); - break; - default: - ASSERT(false); - break; - } - return rc; -} - -std::unique_ptr csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) { - switch(ctx->current) { - case REMOTE_REPLICA: - ASSERT(!ctx->remote.read_from_db); - return ctx->callbacks.remote_readdir_hook(dhandle, ctx->callbacks.vio_userdata); - break; - case LOCAL_REPLICA: - return csync_vio_local_readdir(dhandle); - break; - default: - ASSERT(false); - } - - return nullptr; -} - diff --git a/src/csync/vio/csync_vio.h b/src/csync/vio/csync_vio.h deleted file mode 100644 index f14c95a70..000000000 --- a/src/csync/vio/csync_vio.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _CSYNC_VIO_H -#define _CSYNC_VIO_H - -#include -#include -#include -#include "c_private.h" -#include "csync.h" -#include "csync_private.h" - -struct fhandle_t { - int fd; -}; - -csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name); -int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle); -std::unique_ptr csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle); -#endif /* _CSYNC_VIO_H */ diff --git a/src/csync/vio/csync_vio_local.h b/src/csync/vio/csync_vio_local.h index eae64f02d..734f60211 100644 --- a/src/csync/vio/csync_vio_local.h +++ b/src/csync/vio/csync_vio_local.h @@ -21,6 +21,8 @@ #ifndef _CSYNC_VIO_LOCAL_H #define _CSYNC_VIO_LOCAL_H +struct csync_vio_handle_t; + csync_vio_handle_t OCSYNC_EXPORT *csync_vio_local_opendir(const char *name); int OCSYNC_EXPORT csync_vio_local_closedir(csync_vio_handle_t *dhandle); std::unique_ptr OCSYNC_EXPORT csync_vio_local_readdir(csync_vio_handle_t *dhandle); diff --git a/src/csync/vio/csync_vio_local_unix.cpp b/src/csync/vio/csync_vio_local_unix.cpp index d1ecf9978..a3eaade75 100644 --- a/src/csync/vio/csync_vio_local_unix.cpp +++ b/src/csync/vio/csync_vio_local_unix.cpp @@ -33,7 +33,6 @@ #include "c_string.h" #include "c_utf8.h" #include "csync_util.h" -#include "csync_vio.h" #include "vio/csync_vio_local.h" diff --git a/src/libsync/discoveryphase.cpp b/src/libsync/discoveryphase.cpp index 855d941cb..a784a7ad9 100644 --- a/src/libsync/discoveryphase.cpp +++ b/src/libsync/discoveryphase.cpp @@ -19,7 +19,6 @@ #include "common/checksums.h" #include -#include #include #include diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 5e5a9068c..68b778a7c 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -89,10 +89,7 @@ SyncEngine::SyncEngine(AccountPtr account, const QString &localPath, // Everything in the SyncEngine expects a trailing slash for the localPath. ASSERT(localPath.endsWith(QLatin1Char('/'))); - _csync_ctx.reset(new CSYNC(localPath.toUtf8().data(), journal)); - _excludedFiles.reset(new ExcludedFiles(localPath)); - _csync_ctx->exclude_traversal_fn = _excludedFiles->csyncTraversalMatchFun(); _syncFileStatusTracker.reset(new SyncFileStatusTracker(this)); @@ -621,46 +618,11 @@ int SyncEngine::treewalkFile(csync_file_stat_t * /*file*/, csync_file_stat_t * / return 0; } -void SyncEngine::handleSyncError(CSYNC *ctx, const char *state) -{ - CSYNC_STATUS err = csync_get_status(ctx); - QString errMsg = ctx->error_string; - QString errStr = csyncErrorToString(err); - if (!errMsg.isEmpty()) { - if (!errStr.endsWith(" ")) { - errStr.append(" "); - } - errStr += errMsg; - } - // Special handling CSYNC_STATUS_INVALID_CHARACTERS - if (err == CSYNC_STATUS_INVALID_CHARACTERS) { - errStr = tr("Invalid characters, please rename \"%1\"").arg(errMsg); - } - - // if there is csyncs url modifier in the error message, replace it. - if (errStr.contains("ownclouds://")) - errStr.replace("ownclouds://", "https://"); - if (errStr.contains("owncloud://")) - errStr.replace("owncloud://", "http://"); - - qCWarning(lcEngine) << "ERROR during " << state << ": " << errStr; - - if (CSYNC_STATUS_IS_EQUAL(err, CSYNC_STATUS_ABORTED)) { - qCInfo(lcEngine) << "Update phase was aborted by user!"; - } else if (CSYNC_STATUS_IS_EQUAL(err, CSYNC_STATUS_SERVICE_UNAVAILABLE)) { - emit csyncUnavailable(); - } else { - csyncError(errStr); - } - finalize(false); -} - void SyncEngine::csyncError(const QString &message) { emit syncError(message, ErrorCategory::Normal); } - void SyncEngine::startSync() { if (_journal->exists()) { @@ -728,8 +690,6 @@ void SyncEngine::startSync() _syncItems.clear(); _needsUpdate = false; - csync_resume(_csync_ctx.data()); - if (!_journal->exists()) { qCInfo(lcEngine) << "New sync (no sync journal exists)"; } else { @@ -757,17 +717,11 @@ void SyncEngine::startSync() // undo the filter to allow this sync to retrieve and store the correct etags. _journal->clearEtagStorageFilter(); - _csync_ctx->upload_conflict_files = _account->capabilities().uploadConflictFiles(); _excludedFiles->setExcludeConflictFiles(!_account->capabilities().uploadConflictFiles()); - _csync_ctx->read_remote_from_db = true; - _lastLocalDiscoveryStyle = _localDiscoveryStyle; - _csync_ctx->new_files_are_virtual = _syncOptions._newFilesAreVirtual; - _csync_ctx->virtual_file_suffix = _syncOptions._virtualFileSuffix.toUtf8(); - - if (_csync_ctx->new_files_are_virtual && _csync_ctx->virtual_file_suffix.isEmpty()) { + if (_syncOptions._newFilesAreVirtual && _syncOptions._virtualFileSuffix.isEmpty()) { csyncError(tr("Using virtual files but suffix is not set")); finalize(false); return; @@ -847,11 +801,6 @@ void SyncEngine::slotStartDiscovery() finalize(false); return; } - csync_set_userdata(_csync_ctx.data(), this); - - // Set up checksumming hook - _csync_ctx->callbacks.checksum_hook = &CSyncChecksumHook::hook; - _csync_ctx->callbacks.checksum_userdata = &_checksum_hook; _stopWatch.start(); _progressInfo->_status = ProgressInfo::Starting; @@ -977,16 +926,6 @@ void SyncEngine::slotDiscoveryJobFinished() _journal->commitIfNeededAndStartNewTransaction("Post discovery"); } - // FIXME: This is a reasonable safety check, but specifically just a hotfix. - // See: https://github.com/nextcloud/desktop/issues/1433 - // It's still unclear why we can get an empty FileMap even though folder isn't empty - // For now: Re-check if folder is really empty, if not bail out - if (_csync_ctx.data()->local.files.empty() && QDir(_localPath).entryInfoList(QDir::NoDotAndDotDot).count() > 0) { - qCWarning(lcEngine) << "Received local tree with empty FileMap but sync folder isn't empty. Won't reconcile."; - finalize(false); - return; - } - _progressInfo->_currentDiscoveredRemoteFolder.clear(); _progressInfo->_currentDiscoveredLocalFolder.clear(); _progressInfo->_status = ProgressInfo::Reconcile; @@ -1034,8 +973,6 @@ void SyncEngine::slotDiscoveryJobFinished() // make sure everything is allowed // TODO checkForPermission(_syncItems); - // Re-init the csync context to free memory - _csync_ctx->reinitialize(); _localDiscoveryPaths.clear(); // To announce the beginning of the sync @@ -1163,7 +1100,6 @@ void SyncEngine::slotFinished(bool success) void SyncEngine::finalize(bool success) { - _csync_ctx->reinitialize(); _journal->close(); qCInfo(lcEngine) << "CSync run took " << _stopWatch.addLapTime(QLatin1String("Sync Finished")) << "ms"; @@ -1263,16 +1199,15 @@ void SyncEngine::checkForPermission(SyncFileItemVector &syncItems) (*it)->_instruction = CSYNC_INSTRUCTION_CONFLICT; (*it)->_direction = SyncFileItem::Down; (*it)->_isRestoration = true; - // Take the things to write to the db from the "other" node (i.e: info from server). + /*// Take the things to write to the db from the "other" node (i.e: info from server). // Do a lookup into the csync remote tree to get the metadata we need to restore. - ASSERT(_csync_ctx->status != CSYNC_STATUS_INIT); auto csyncIt = _csync_ctx->remote.files.find((*it)->_file.toUtf8()); if (csyncIt != _csync_ctx->remote.files.end()) { (*it)->_modtime = csyncIt->second->modtime; (*it)->_size = csyncIt->second->size; (*it)->_fileId = csyncIt->second->file_id; (*it)->_etag = csyncIt->second->etag; - } + }*/ (*it)->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring"); continue; } @@ -1421,17 +1356,8 @@ void SyncEngine::checkForPermission(SyncFileItemVector &syncItems) RemotePermissions SyncEngine::getPermissions(const QString &file) const { - // Fetch from the csync context while we still have it. - ASSERT(_csync_ctx->status != CSYNC_STATUS_INIT); - - if (file == QLatin1String("")) - return _csync_ctx->remote.root_perms; - - auto it = _csync_ctx->remote.files.find(file.toUtf8()); - if (it != _csync_ctx->remote.files.end()) { - return it->second->remotePerm; - } - return {}; + qFatal("FIXME"); + return RemotePermissions(); } void SyncEngine::restoreOldFiles(SyncFileItemVector &syncItems) @@ -1547,9 +1473,6 @@ void SyncEngine::abort() if (_propagator) qCInfo(lcEngine) << "Aborting sync"; - // Sets a flag for the update phase - csync_request_abort(_csync_ctx.data()); - // Aborts the discovery phase job if (_discoveryJob) { _discoveryJob->abort(); diff --git a/src/libsync/syncengine.h b/src/libsync/syncengine.h index c724a4416..61ec37289 100644 --- a/src/libsync/syncengine.h +++ b/src/libsync/syncengine.h @@ -79,8 +79,8 @@ public: SyncOptions syncOptions() const { return _syncOptions; } void setSyncOptions(const SyncOptions &options) { _syncOptions = options; } - bool ignoreHiddenFiles() const { return _csync_ctx->ignore_hidden_files; } - void setIgnoreHiddenFiles(bool ignore) { _csync_ctx->ignore_hidden_files = ignore; } + bool ignoreHiddenFiles() const { return _ignore_hidden_files; } + void setIgnoreHiddenFiles(bool ignore) { _ignore_hidden_files = ignore; } ExcludedFiles &excludedFiles() { return *_excludedFiles; } Utility::StopWatch &stopWatch() { return _stopWatch; } @@ -208,7 +208,6 @@ private slots: void slotInsufficientRemoteStorage(); private: - void handleSyncError(CSYNC *ctx, const char *state); void csyncError(const QString &message); int treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other, bool); @@ -236,7 +235,6 @@ private: QVector _syncItems; AccountPtr _account; - QScopedPointer _csync_ctx; bool _needsUpdate; bool _syncRunning; QString _localPath; @@ -292,6 +290,9 @@ private: // number of files which goes back in time from the server int _backInTimeFiles; + // If ignored files should be ignored + bool _ignore_hidden_files; + int _uploadLimit; int _downloadLimit; diff --git a/test/csync/CMakeLists.txt b/test/csync/CMakeLists.txt index e40294723..cdb45d81e 100644 --- a/test/csync/CMakeLists.txt +++ b/test/csync/CMakeLists.txt @@ -29,7 +29,6 @@ add_cmocka_test(check_csync_util csync_tests/check_csync_util.cpp ${TEST_TARGET_ add_cmocka_test(check_csync_misc csync_tests/check_csync_misc.cpp ${TEST_TARGET_LIBRARIES}) # vio -add_cmocka_test(check_vio vio_tests/check_vio.cpp ${TEST_TARGET_LIBRARIES}) add_cmocka_test(check_vio_ext vio_tests/check_vio_ext.cpp ${TEST_TARGET_LIBRARIES}) # encoding diff --git a/test/csync/csync_tests/check_csync_exclude.cpp b/test/csync/csync_tests/check_csync_exclude.cpp index 97aa7bb5b..61f7283e2 100644 --- a/test/csync/csync_tests/check_csync_exclude.cpp +++ b/test/csync/csync_tests/check_csync_exclude.cpp @@ -38,25 +38,15 @@ class ExcludedFilesTest { public: -static int setup(void **state) { - CSYNC *csync = nullptr; - - csync = new CSYNC("/tmp/check_csync1", new OCC::SyncJournalDb("")); +static int setup(void **) { excludedFiles = new ExcludedFiles; excludedFiles->setWildcardsMatchSlash(false); - csync->exclude_traversal_fn = excludedFiles->csyncTraversalMatchFun(); - - *state = csync; return 0; } -static int setup_init(void **state) { - CSYNC *csync = nullptr; - - csync = new CSYNC("/tmp/check_csync1", new OCC::SyncJournalDb("")); +static int setup_init(void **) { excludedFiles = new ExcludedFiles; excludedFiles->setWildcardsMatchSlash(false); - csync->exclude_traversal_fn = excludedFiles->csyncTraversalMatchFun(); excludedFiles->addExcludeFilePath(EXCLUDE_LIST_FILE); assert_true(excludedFiles->reloadExcludeFiles()); @@ -69,18 +59,12 @@ static int setup_init(void **state) { excludedFiles->addManualExclude("latex/*/*.tex.tmp"); assert_true(excludedFiles->reloadExcludeFiles()); - - *state = csync; return 0; } -static int teardown(void **state) { - auto *csync = (CSYNC*)*state; +static int teardown(void **) { int rc = 0; - auto statedb = csync->statedb; - delete csync; - delete statedb; delete excludedFiles; rc = system("rm -rf /tmp/check_csync1"); @@ -88,8 +72,6 @@ static int teardown(void **state) { rc = system("rm -rf /tmp/check_csync2"); assert_int_equal(rc, 0); - *state = nullptr; - return 0; } diff --git a/test/csync/vio_tests/check_vio.cpp b/test/csync/vio_tests/check_vio.cpp deleted file mode 100644 index c38e1022f..000000000 --- a/test/csync/vio_tests/check_vio.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include -#include -#include - -#include "csync_private.h" -#include "std/c_utf8.h" -#include "vio/csync_vio.h" - -#include "torture.h" - -#define CSYNC_TEST_DIR "/tmp/csync_test/" -#define CSYNC_TEST_DIRS "/tmp/csync_test/this/is/a/mkdirs/test" -#define CSYNC_TEST_FILE "/tmp/csync_test/file.txt" - -#define MKDIR_MASK (S_IRWXU |S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) - -#define WD_BUFFER_SIZE 255 - -static char wd_buffer[WD_BUFFER_SIZE]; - -static int setup(void **state) -{ - CSYNC *csync = nullptr; - int rc = 0; - - assert_non_null(getcwd(wd_buffer, WD_BUFFER_SIZE)); - - rc = system("rm -rf /tmp/csync_test"); - assert_int_equal(rc, 0); - - csync = new CSYNC("/tmp/check_csync1", new OCC::SyncJournalDb("")); - - csync->current = LOCAL_REPLICA; - - *state = csync; - return 0; -} - -static int setup_dir(void **state) { - int rc = 0; - mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR); - - setup(state); - - rc = _tmkdir(dir, MKDIR_MASK); - c_free_locale_string(dir); - assert_int_equal(rc, 0); - - assert_non_null(getcwd(wd_buffer, WD_BUFFER_SIZE)); - - rc = chdir(CSYNC_TEST_DIR); - assert_int_equal(rc, 0); - return 0; -} - -static int teardown(void **state) { - auto *csync = (CSYNC*)*state; - int rc = 0; - - auto statedb = csync->statedb; - delete csync; - delete statedb; - - rc = chdir(wd_buffer); - assert_int_equal(rc, 0); - - rc = system("rm -rf /tmp/csync_test/"); - assert_int_equal(rc, 0); - - *state = nullptr; - return 0; -} - - -/* - * Test directory function - */ - -static void check_csync_vio_opendir(void **state) -{ - auto *csync = (CSYNC*)*state; - csync_vio_handle_t *dh = nullptr; - int rc = 0; - - dh = csync_vio_opendir(csync, CSYNC_TEST_DIR); - assert_non_null(dh); - - rc = csync_vio_closedir(csync, dh); - assert_int_equal(rc, 0); -} - -static void check_csync_vio_opendir_perm(void **state) -{ - auto *csync = (CSYNC*)*state; - csync_vio_handle_t *dh = nullptr; - int rc = 0; - mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR); - - assert_non_null(dir); - - rc = _tmkdir(dir, (S_IWUSR|S_IXUSR)); - assert_int_equal(rc, 0); - - dh = csync_vio_opendir(csync, CSYNC_TEST_DIR); - assert_null(dh); - assert_int_equal(errno, EACCES); - - _tchmod(dir, MKDIR_MASK); - c_free_locale_string(dir); -} - -static void check_csync_vio_closedir_null(void **state) -{ - auto *csync = (CSYNC*)*state; - int rc = 0; - - rc = csync_vio_closedir(csync, nullptr); - assert_int_equal(rc, -1); -} - -int torture_run_tests(void) -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(check_csync_vio_opendir, setup_dir, teardown), - cmocka_unit_test_setup_teardown(check_csync_vio_opendir_perm, setup, teardown), - cmocka_unit_test(check_csync_vio_closedir_null), - }; - - return cmocka_run_group_tests(tests, nullptr, nullptr); -} diff --git a/test/csync/vio_tests/check_vio_ext.cpp b/test/csync/vio_tests/check_vio_ext.cpp index ab1b3fb1d..6d02ae210 100644 --- a/test/csync/vio_tests/check_vio_ext.cpp +++ b/test/csync/vio_tests/check_vio_ext.cpp @@ -26,7 +26,7 @@ #include "csync_private.h" #include "std/c_utf8.h" -#include "vio/csync_vio.h" +#include "vio/csync_vio_local.h" #ifdef _WIN32 #include @@ -44,7 +44,6 @@ static mbchar_t wd_buffer[WD_BUFFER_SIZE]; struct statevar { - CSYNC *csync; char *result; char *ignored_dir; }; @@ -97,10 +96,6 @@ static int setup_testenv(void **state) { auto *mystate = (statevar*)malloc( sizeof(statevar) ); mystate->result = nullptr; - mystate->csync = new CSYNC("/tmp/check_csync1", new OCC::SyncJournalDb("")); - - mystate->csync->current = LOCAL_REPLICA; - *state = mystate; return 0; } @@ -118,16 +113,10 @@ static void output( const char *text ) } static int teardown(void **state) { - auto *sv = (statevar*) *state; - CSYNC *csync = sv->csync; int rc = 0; output("================== Tearing down!\n"); - auto statedb = csync->statedb; - delete csync; - delete statedb; - rc = _tchdir(wd_buffer); assert_int_equal(rc, 0); @@ -188,7 +177,6 @@ static void traverse_dir(void **state, const char *dir, int *cnt) csync_vio_handle_t *dh = nullptr; std::unique_ptr dirent; auto *sv = (statevar*) *state; - CSYNC *csync = sv->csync; char *subdir = nullptr; char *subdir_out = nullptr; int rc = 0; @@ -202,10 +190,10 @@ static void traverse_dir(void **state, const char *dir, int *cnt) const char *format_str = "%s C:%s"; #endif - dh = csync_vio_opendir(csync, dir); + dh = csync_vio_local_opendir(dir); assert_non_null(dh); - while( (dirent = csync_vio_readdir(csync, dh)) ) { + while( (dirent = csync_vio_local_readdir(dh)) ) { assert_non_null(dirent.get()); if (!dirent->original_path.isEmpty()) { sv->ignored_dir = c_strdup(dirent->original_path); @@ -250,7 +238,7 @@ static void traverse_dir(void **state, const char *dir, int *cnt) SAFE_FREE(subdir_out); } - rc = csync_vio_closedir(csync, dh); + rc = csync_vio_local_closedir(dh); assert_int_equal(rc, 0); }