From: Jocelyn Turcotte Date: Thu, 17 Aug 2017 17:06:58 +0000 (+0200) Subject: csync: Keep the csync_file_stat_t instances created during discovery X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~701^2~91 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ec52807e29dc02f52ba9f9e576acf520c289ad82;p=nextcloud-desktop.git csync: Keep the csync_file_stat_t instances created during discovery Now that they use the same structure, avoid _csync_detect_update having to recreate another instance and transfer everything manually. Any instance created during discovery should now be used all the way up to SyncEngine::treewalkFile. This also makes sure that the path and types are properly set in that object instead of having to pass everything as separate parameters. This gets rid of csync_ftw_flags_e which was now converted from, and to csync_ftw_type_e, already in the csync_file_stat_t. Issue #1817 --- diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp index d3cdfab89..91afc8eb6 100644 --- a/src/csync/csync_update.cpp +++ b/src/csync/csync_update.cpp @@ -51,26 +51,6 @@ #define __STDC_FORMAT_MACROS #include -/* calculate the hash of a given uri */ -static uint64_t _hash_of_file(CSYNC *ctx, const char *file) { - const char *path; - int len; - uint64_t h = 0; - - if( ctx && file ) { - path = file; - if (ctx->current == LOCAL_REPLICA) { - if (strlen(path) <= strlen(ctx->local.uri)) { - return 0; - } - path += strlen(ctx->local.uri) + 1; - } - len = strlen(path); - h = c_jhash64((uint8_t *) path, len, 0); - } - return h; -} - #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) { @@ -96,6 +76,10 @@ static bool _last_db_return_error(CSYNC* ctx) { return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW; } +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 */ @@ -124,34 +108,21 @@ static bool _csync_mtime_equal(time_t a, time_t b) * * See doc/dev/sync-algorithm.md for an overview. */ -static int _csync_detect_update(CSYNC *ctx, const char *file, - const csync_file_stat_t *fs, enum csync_ftw_type_e type) { - uint64_t h = 0; - const char *path = NULL; - std::unique_ptr st; +static int _csync_detect_update(CSYNC *ctx, std::unique_ptr fs) { std::unique_ptr tmp; CSYNC_EXCLUDE_TYPE excluded; - if ((file == NULL) || (fs == NULL)) { + if (fs == NULL) { errno = EINVAL; ctx->status_code = CSYNC_STATUS_PARAM_ERROR; return -1; } - path = file; - if (ctx->current == LOCAL_REPLICA) { - if (strlen(path) <= strlen(ctx->local.uri)) { - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; - } - path += strlen(ctx->local.uri) + 1; - } - - if (type == CSYNC_FTW_TYPE_SKIP) { + if (fs->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); + excluded = csync_excluded_traversal(ctx->excludes, fs->path, fs->type); } if( excluded == CSYNC_NOT_EXCLUDED ) { @@ -160,12 +131,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, * 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)) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "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. */ - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", fs->path.constData(), excluded); if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) { return 1; } @@ -175,26 +146,19 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, } if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) { - if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) { + if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, fs->path)) { return 1; } } - h = _hash_of_file(ctx, file ); - if( h == 0 ) { - return -1; - } - - st.reset(new csync_file_stat_t); - - if (type == CSYNC_FTW_TYPE_FILE ) { + if (fs->type == CSYNC_FTW_TYPE_FILE ) { if (fs->modtime == 0) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", fs->path.constData()); } } - if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) { - st->instruction = CSYNC_INSTRUCTION_IGNORE; + if (excluded > CSYNC_NOT_EXCLUDED || fs->type == CSYNC_FTW_TYPE_SLINK) { + fs->instruction = CSYNC_INSTRUCTION_IGNORE; if (ctx->current_fs) { ctx->current_fs->has_ignored_files = true; } @@ -208,14 +172,14 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, * does not change on rename. */ if (csync_get_statedb_exists(ctx)) { - tmp = csync_statedb_get_stat_by_hash(ctx, h); + tmp = csync_statedb_get_stat_by_hash(ctx, fs->phash); if(_last_db_return_error(ctx)) { ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; return -1; } - if(tmp && tmp->phash == h ) { /* there is an entry in the database */ + if(tmp && tmp->phash == fs->phash ) { /* there is an entry in the database */ /* we have an update! */ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Database entry found, compare: %" PRId64 " <-> %" PRId64 ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64 @@ -224,11 +188,11 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, fs->etag.constData(), tmp->etag.constData(), (uint64_t) fs->inode, (uint64_t) tmp->inode, (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm.constData(), tmp->remotePerm.constData(), tmp->has_ignored_files ); if (ctx->current == REMOTE_REPLICA && fs->etag != tmp->etag) { - st->instruction = CSYNC_INSTRUCTION_EVAL; + fs->instruction = CSYNC_INSTRUCTION_EVAL; // Preserve the EVAL flag later on if the type has changed. if (tmp->type != fs->type) { - st->child_modified = true; + fs->child_modified = true; } goto out; @@ -240,57 +204,57 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, // Checksum comparison at this stage is only enabled for .eml files, // check #4754 #4755 - bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0; + bool isEmlFile = csync_fnmatch("*.eml", fs->path, FNM_CASEFOLD) == 0; if (isEmlFile && fs->size == tmp->size && !tmp->checksumHeader.isEmpty()) { if (ctx->callbacks.checksum_hook) { - st->checksumHeader = ctx->callbacks.checksum_hook( - file, tmp->checksumHeader, + fs->checksumHeader = ctx->callbacks.checksum_hook( + _rel_to_abs(ctx, fs->path), tmp->checksumHeader, ctx->callbacks.checksum_userdata); } bool checksumIdentical = false; - if (!st->checksumHeader.isEmpty()) { - checksumIdentical = st->checksumHeader == tmp->checksumHeader; + if (!fs->checksumHeader.isEmpty()) { + checksumIdentical = fs->checksumHeader == tmp->checksumHeader; } if (checksumIdentical) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path); - st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", fs->path.constData()); + fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; goto out; } } // Preserve the EVAL flag later on if the type has changed. if (tmp->type != fs->type) { - st->child_modified = true; + fs->child_modified = true; } - st->instruction = CSYNC_INSTRUCTION_EVAL; + fs->instruction = CSYNC_INSTRUCTION_EVAL; goto out; } bool metadata_differ = (ctx->current == REMOTE_REPLICA && (fs->file_id != tmp->file_id || fs->remotePerm != tmp->remotePerm)) || (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode); - if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA + if (fs->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); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "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 ) { - st->has_ignored_files = tmp->has_ignored_files; + fs->has_ignored_files = tmp->has_ignored_files; } 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->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", fs->path.constData()); + fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; } else { - st->instruction = CSYNC_INSTRUCTION_NONE; + fs->instruction = CSYNC_INSTRUCTION_NONE; } } else { /* check if it's a file and has been renamed */ @@ -305,13 +269,13 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, } // Default to NEW unless we're sure it's a rename. - st->instruction = CSYNC_INSTRUCTION_NEW; + fs->instruction = CSYNC_INSTRUCTION_NEW; bool isRename = tmp && tmp->inode == fs->inode && tmp->type == fs->type && (tmp->modtime == fs->modtime || fs->type == CSYNC_FTW_TYPE_DIR) #ifdef NO_RENAME_EXTENSION - && _csync_sameextension(tmp->path, path) + && _csync_sameextension(tmp->path, fs->path) #endif ; @@ -319,21 +283,21 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, // Verify the checksum where possible if (isRename && !tmp->checksumHeader.isEmpty() && ctx->callbacks.checksum_hook && fs->type == CSYNC_FTW_TYPE_FILE) { - st->checksumHeader = ctx->callbacks.checksum_hook( - file, tmp->checksumHeader, - ctx->callbacks.checksum_userdata); - if (!st->checksumHeader.isEmpty()) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader.constData(), tmp->checksumHeader.constData()); - isRename = st->checksumHeader == tmp->checksumHeader; + fs->checksumHeader = ctx->callbacks.checksum_hook( + _rel_to_abs(ctx, fs->path), tmp->checksumHeader, + ctx->callbacks.checksum_userdata); + if (!fs->checksumHeader.isEmpty()) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", fs->path.constData(), fs->checksumHeader.constData(), tmp->checksumHeader.constData()); + isRename = fs->checksumHeader == tmp->checksumHeader; } } 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; + fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; if (fs->type == CSYNC_FTW_TYPE_DIR) { - csync_rename_record(ctx, tmp->path, path); + csync_rename_record(ctx, tmp->path, fs->path); } } goto out; @@ -349,28 +313,28 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, if(tmp ) { /* tmp existing at all */ if (tmp->type != fs->type) { CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "file types different is not!"); - st->instruction = CSYNC_INSTRUCTION_NEW; + fs->instruction = CSYNC_INSTRUCTION_NEW; goto out; } - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path.constData(), file); - st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s --> %s", tmp->path.constData(), fs->path.constData()); + fs->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; if (fs->type == CSYNC_FTW_TYPE_DIR) { - csync_rename_record(ctx, tmp->path, path); + csync_rename_record(ctx, tmp->path, fs->path); } else { if( 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; + fs->instruction = CSYNC_INSTRUCTION_NEW; } } goto out; } else { /* file not found in statedb */ - st->instruction = CSYNC_INSTRUCTION_NEW; + fs->instruction = CSYNC_INSTRUCTION_NEW; if (fs->type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) { - if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) { + if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, fs->path, fs->remotePerm)) { return 1; } } @@ -387,66 +351,47 @@ static int _csync_detect_update(CSYNC *ctx, const char *file, 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. */ + if (fs->instruction == CSYNC_INSTRUCTION_IGNORE) { + if( fs->type == CSYNC_FTW_TYPE_SLINK ) { + fs->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. */ + fs->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. */ + fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */ } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */ + fs->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */ } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */ + fs->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; + fs->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN; } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED; + fs->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED; } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE; + fs->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE; } } } - if (st->instruction != CSYNC_INSTRUCTION_NONE - && st->instruction != CSYNC_INSTRUCTION_IGNORE - && st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA - && type != CSYNC_FTW_TYPE_DIR) { - st->child_modified = true; + if (fs->instruction != CSYNC_INSTRUCTION_NONE + && fs->instruction != CSYNC_INSTRUCTION_IGNORE + && fs->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA + && fs->type != CSYNC_FTW_TYPE_DIR) { + fs->child_modified = true; } - ctx->current_fs = st.get(); - - st->inode = fs->inode; - st->size = fs->size; - st->modtime = fs->modtime; - st->type = type; - st->is_hidden = fs->is_hidden; - st->etag = fs->etag; - st->file_id = fs->file_id; - st->directDownloadUrl = fs->directDownloadUrl; - st->directDownloadCookies = fs->directDownloadCookies; - st->remotePerm = fs->remotePerm; - - // For the remote: propagate the discovered checksum - if (ctx->current == REMOTE_REPLICA) { - st->checksumHeader = fs->checksumHeader; - } - - st->phash = h; - st->path = path; + ctx->current_fs = fs.get(); - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", st->path.constData(), - csync_instruction_str(st->instruction)); + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", fs->path.constData(), + csync_instruction_str(fs->instruction)); switch (ctx->current) { case LOCAL_REPLICA: - if (c_rbtree_insert(ctx->local.tree, (void *) st.release()) < 0) { + if (c_rbtree_insert(ctx->local.tree, (void *) fs.release()) < 0) { ctx->status_code = CSYNC_STATUS_TREE_ERROR; return -1; } break; case REMOTE_REPLICA: - if (c_rbtree_insert(ctx->remote.tree, (void *) st.release()) < 0) { + if (c_rbtree_insert(ctx->remote.tree, (void *) fs.release()) < 0) { ctx->status_code = CSYNC_STATUS_TREE_ERROR; return -1; } @@ -458,12 +403,8 @@ out: return 0; } -int csync_walker(CSYNC *ctx, const char *file, const csync_file_stat_t *fs, - int flag) { +int csync_walker(CSYNC *ctx, std::unique_ptr fs) { int rc = -1; - enum csync_ftw_type_e type = CSYNC_FTW_TYPE_SKIP; - std::unique_ptr st; - uint64_t h; if (ctx->abort) { CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!"); @@ -471,51 +412,30 @@ int csync_walker(CSYNC *ctx, const char *file, const csync_file_stat_t *fs, return -1; } - switch (flag) { - case CSYNC_FTW_FLAG_FILE: + switch (fs->type) { + case CSYNC_FTW_TYPE_FILE: if (ctx->current == REMOTE_REPLICA) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id.constData(), fs->size); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", fs->path.constData(), fs->file_id.constData(), fs->size); } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", fs->path.constData(), fs->inode, fs->size); } - type = CSYNC_FTW_TYPE_FILE; break; - case CSYNC_FTW_FLAG_DIR: /* enter directory */ + case CSYNC_FTW_TYPE_DIR: /* enter directory */ if (ctx->current == REMOTE_REPLICA) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id.constData()); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", fs->path.constData(), fs->file_id.constData()); } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", fs->path.constData(), fs->inode); } - type = CSYNC_FTW_TYPE_DIR; break; - case CSYNC_FTW_FLAG_NSTAT: /* not statable file */ - /* if file was here before and now is not longer stat-able, still - * add it to the db, otherwise not. */ - h = _hash_of_file( ctx, file ); - if( h == 0 ) { - return 0; - } - st = csync_statedb_get_stat_by_hash(ctx, h); - if( !st ) { - return 0; - } - st.reset(); - - type = CSYNC_FTW_TYPE_SKIP; - break; - case CSYNC_FTW_FLAG_SLINK: - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file); - type = CSYNC_FTW_TYPE_SLINK; + case CSYNC_FTW_TYPE_SLINK: + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", fs->path.constData()); break; - case CSYNC_FTW_FLAG_DNR: - case CSYNC_FTW_FLAG_DP: - case CSYNC_FTW_FLAG_SLN: default: return 0; break; } - rc = _csync_detect_update(ctx, file, fs, type ); + rc = _csync_detect_update(ctx, std::move(fs)); return rc; } @@ -554,13 +474,12 @@ static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_f int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, unsigned int depth) { QByteArray filename; - QByteArray d_name; + QByteArray fullpath; csync_vio_handle_t *dh = NULL; std::unique_ptr dirent; csync_file_stat_t *previous_fs = NULL; int read_from_db = 0; int rc = 0; - int res = 0; bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db); @@ -628,8 +547,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, } while ((dirent = csync_vio_readdir(ctx, dh))) { - int flag; - /* Conversion error */ if (dirent->path.isEmpty() && !dirent->original_path.isEmpty()) { ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS; @@ -638,65 +555,58 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, goto error; } - d_name = dirent->path; - if (d_name.isEmpty()) { + // 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 ( d_name == "." || d_name == "..") { - dirent.reset(); + if ( filename == "." || filename == "..") { continue; } - if (uri[0] == '\0') { - filename = d_name; - } else { - /* For the local replica, dirent->path only contains the file name */ - filename = uri; - filename += '/'; - filename += d_name; - } - + fullpath = uri; + if (!fullpath.isEmpty()) + fullpath += '/'; + fullpath += filename; /* Only for the local replica we have to stat(), for the remote one we have all data already */ if (ctx->current == LOCAL_REPLICA) { - res = csync_vio_stat(ctx, filename, dirent.get()); - } else { - res = 0; + if (csync_vio_stat(ctx, fullpath, dirent.get()) != 0) { + // Will get excluded by _csync_detect_update. + dirent->type = CSYNC_FTW_TYPE_SKIP; + } } /* if the filename starts with a . we consider it a hidden file * For windows, the hidden state is also discovered within the vio * local stat function. */ - if( d_name[0] == '.' ) { - if (d_name == ".sys.admin#recall#") { /* recall file shall not be ignored (#4420) */ + if( filename[0] == '.' ) { + if (filename == ".sys.admin#recall#") { /* recall file shall not be ignored (#4420) */ dirent->is_hidden = true; } } - flag = CSYNC_FTW_FLAG_NSTAT; - if( res == 0) { - switch (dirent->type) { - case CSYNC_FTW_TYPE_SLINK: - flag = CSYNC_FTW_FLAG_SLINK; - break; - case CSYNC_FTW_TYPE_DIR: - flag = CSYNC_FTW_FLAG_DIR; - break; - case CSYNC_FTW_TYPE_FILE: - flag = CSYNC_FTW_FLAG_FILE; - break; - default: - break; - }; + // 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) { + if (dirent->path.size() <= (int)strlen(ctx->local.uri)) { + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + goto error; + } + // "len + 1" to include the slash in-between. + dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1); } + // We calculate the phash using the relative path. + dirent->phash = c_jhash64((const uint8_t*)dirent->path.constData(), dirent->path.size(), 0); previous_fs = ctx->current_fs; + bool recurse = dirent->type == CSYNC_FTW_TYPE_DIR; /* Call walker function for each file */ - rc = fn(ctx, filename, dirent.get(), flag); + rc = fn(ctx, std::move(dirent)); /* this function may update ctx->current and ctx->read_from_db */ if (rc < 0) { @@ -708,9 +618,9 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, goto error; } - if (flag == CSYNC_FTW_FLAG_DIR && rc == 0 + if (recurse && rc == 0 && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) { - rc = csync_ftw(ctx, filename, fn, depth - 1); + rc = csync_ftw(ctx, fullpath, fn, depth - 1); if (rc < 0) { ctx->current_fs = previous_fs; goto error; @@ -738,7 +648,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, ctx->current_fs = previous_fs; ctx->remote.read_from_db = read_from_db; - dirent.reset(); } csync_vio_closedir(ctx, dh); diff --git a/src/csync/csync_update.h b/src/csync/csync_update.h index b1de56dee..1b4c50995 100644 --- a/src/csync/csync_update.h +++ b/src/csync/csync_update.h @@ -37,22 +37,7 @@ * @{ */ -/** - * Types for files - */ -enum csync_ftw_flags_e { - CSYNC_FTW_FLAG_FILE, /* Regular file. */ - CSYNC_FTW_FLAG_DIR, /* Directory. */ - CSYNC_FTW_FLAG_DNR, /* Unreadable directory. */ - CSYNC_FTW_FLAG_NSTAT, /* Unstatable file. */ - CSYNC_FTW_FLAG_SLINK, /* Symbolic link. */ - /* These flags are only passed from the `nftw' function. */ - CSYNC_FTW_FLAG_DP, /* Directory, all subdirs have been visited. */ - CSYNC_FTW_FLAG_SLN /* Symbolic link naming non-existing file. */ -}; - -typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file, - const csync_file_stat_t *fs, int flag); +typedef int (*csync_walker_fn) (CSYNC *ctx, std::unique_ptr fs); /** * @brief The walker function to use in the file tree walker. @@ -67,7 +52,7 @@ typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file, * * @return 0 on success, < 0 on error. */ -int csync_walker(CSYNC *ctx, const char *file, const csync_file_stat_t *fs, int flag); +int csync_walker(CSYNC *ctx, std::unique_ptr fs); /** * @brief The file tree walker. diff --git a/test/csync/csync_tests/check_csync_update.cpp b/test/csync/csync_tests/check_csync_update.cpp index 184f6877e..f8329465f 100644 --- a/test/csync/csync_tests/check_csync_update.cpp +++ b/test/csync/csync_tests/check_csync_update.cpp @@ -205,14 +205,10 @@ static std::unique_ptr create_fstat(const char *name, } static int failing_fn(CSYNC *ctx, - const char *file, - const csync_file_stat_t *fs, - int flag) + std::unique_ptr fs) { (void) ctx; - (void) file; (void) fs; - (void) flag; return -1; } @@ -227,10 +223,7 @@ static void check_csync_detect_update(void **state) fs = create_fstat("file.txt", 0, 1217597845); - rc = _csync_detect_update(csync, - "/tmp/check_csync1/file.txt", - fs.get(), - CSYNC_FTW_TYPE_FILE); + rc = _csync_detect_update(csync, std::move(fs)); assert_int_equal(rc, 0); /* the instruction should be set to new */ @@ -253,10 +246,7 @@ static void check_csync_detect_update_db_none(void **state) fs = create_fstat("file.txt", 0, 1217597845); - rc = _csync_detect_update(csync, - "/tmp/check_csync1/file.txt", - fs.get(), - CSYNC_FTW_TYPE_FILE); + rc = _csync_detect_update(csync, std::move(fs)); assert_int_equal(rc, 0); /* the instruction should be set to new */ @@ -277,10 +267,7 @@ static void check_csync_detect_update_db_eval(void **state) fs = create_fstat("file.txt", 0, 42); - rc = _csync_detect_update(csync, - "/tmp/check_csync1/file.txt", - fs.get(), - CSYNC_FTW_TYPE_FILE); + rc = _csync_detect_update(csync, std::move(fs)); assert_int_equal(rc, 0); /* the instruction should be set to new */ @@ -303,10 +290,7 @@ static void check_csync_detect_update_db_rename(void **state) fs = create_fstat("wurst.txt", 0, 42); csync_set_statedb_exists(csync, 1); - rc = _csync_detect_update(csync, - "/tmp/check_csync1/wurst.txt", - fs.get(), - CSYNC_FTW_TYPE_FILE); + rc = _csync_detect_update(csync, std::move(fs)); assert_int_equal(rc, 0); /* the instruction should be set to rename */ @@ -330,10 +314,7 @@ static void check_csync_detect_update_db_new(void **state) fs = create_fstat("file.txt", 42000, 0); - rc = _csync_detect_update(csync, - "/tmp/check_csync1/file.txt", - fs.get(), - CSYNC_FTW_TYPE_FILE); + rc = _csync_detect_update(csync, std::move(fs)); assert_int_equal(rc, 0); /* the instruction should be set to new */ @@ -351,18 +332,7 @@ static void check_csync_detect_update_null(void **state) std::unique_ptr fs; int rc; - fs = create_fstat("file.txt", 0, 0); - - rc = _csync_detect_update(csync, - NULL, - fs.get(), - CSYNC_FTW_TYPE_FILE); - assert_int_equal(rc, -1); - - rc = _csync_detect_update(csync, - "/tmp/check_csync1/file.txt", - NULL, - CSYNC_FTW_TYPE_FILE); + rc = _csync_detect_update(csync, NULL); assert_int_equal(rc, -1); }