diff options
Diffstat (limited to 'subversion/libsvn_wc/workqueue.c')
-rw-r--r-- | subversion/libsvn_wc/workqueue.c | 746 |
1 files changed, 386 insertions, 360 deletions
diff --git a/subversion/libsvn_wc/workqueue.c b/subversion/libsvn_wc/workqueue.c index 48bed38..b034d7d 100644 --- a/subversion/libsvn_wc/workqueue.c +++ b/subversion/libsvn_wc/workqueue.c @@ -34,6 +34,7 @@ #include "wc_db.h" #include "workqueue.h" #include "adm_files.h" +#include "conflicts.h" #include "translate.h" #include "svn_private_config.h" @@ -41,7 +42,6 @@ /* Workqueue operation names. */ -#define OP_BASE_REMOVE "base-remove" #define OP_FILE_COMMIT "file-commit" #define OP_FILE_INSTALL "file-install" #define OP_FILE_REMOVE "file-remove" @@ -49,18 +49,26 @@ #define OP_FILE_COPY_TRANSLATED "file-translate" #define OP_SYNC_FILE_FLAGS "sync-file-flags" #define OP_PREJ_INSTALL "prej-install" +#define OP_DIRECTORY_REMOVE "dir-remove" +#define OP_DIRECTORY_INSTALL "dir-install" + +#define OP_POSTUPGRADE "postupgrade" + +/* Legacy items */ +#define OP_BASE_REMOVE "base-remove" #define OP_RECORD_FILEINFO "record-fileinfo" #define OP_TMP_SET_TEXT_CONFLICT_MARKERS "tmp-set-text-conflict-markers" #define OP_TMP_SET_PROPERTY_CONFLICT_MARKER "tmp-set-property-conflict-marker" -#define OP_POSTUPGRADE "postupgrade" /* For work queue debugging. Generates output about its operation. */ /* #define SVN_DEBUG_WORK_QUEUE */ +typedef struct work_item_baton_t work_item_baton_t; struct work_item_dispatch { const char *name; - svn_error_t *(*func)(svn_wc__db_t *db, + svn_error_t *(*func)(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -68,30 +76,12 @@ struct work_item_dispatch { apr_pool_t *scratch_pool); }; - +/* Forward definition */ static svn_error_t * -get_and_record_fileinfo(svn_wc__db_t *db, +get_and_record_fileinfo(work_item_baton_t *wqb, const char *local_abspath, svn_boolean_t ignore_enoent, - apr_pool_t *scratch_pool) -{ - const svn_io_dirent2_t *dirent; - - SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, ignore_enoent, - scratch_pool, scratch_pool)); - - if (dirent->kind == svn_node_none) - { - /* Skip file not found if ignore_enoent */ - return SVN_NO_ERROR; - } - - return svn_error_trace(svn_wc__db_global_record_fileinfo( - db, local_abspath, - dirent->filesize, dirent->mtime, - scratch_pool)); -} - + apr_pool_t *scratch_pool); /* ------------------------------------------------------------------------ */ /* OP_REMOVE_BASE */ @@ -99,116 +89,14 @@ get_and_record_fileinfo(svn_wc__db_t *db, /* Removes a BASE_NODE and all it's data, leaving any adds and copies as is. Do this as a depth first traversal to make sure than any parent still exists on error conditions. - - ### This function needs review for 4th tree behavior.*/ -static svn_error_t * -remove_base_node(svn_wc__db_t *db, - const char *local_abspath, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) -{ - svn_wc__db_status_t base_status, wrk_status; - svn_wc__db_kind_t base_kind, wrk_kind; - svn_boolean_t have_base, have_work; - svn_error_t *err; - - if (cancel_func) - SVN_ERR(cancel_func(cancel_baton)); - - err = svn_wc__db_read_info(&wrk_status, &wrk_kind, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, - &have_base, NULL, &have_work, - db, local_abspath, scratch_pool, scratch_pool); - if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) - { - /* No node to delete, this can happen when the wq item is rerun. */ - svn_error_clear(err); - return SVN_NO_ERROR; - } - - if(! have_base) - /* No base node to delete, this can happen when the wq item is rerun. */ - return SVN_NO_ERROR; - - if (wrk_status == svn_wc__db_status_normal - || wrk_status == svn_wc__db_status_not_present - || wrk_status == svn_wc__db_status_server_excluded) - { - base_status = wrk_status; - base_kind = wrk_kind; - } - else - SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - db, local_abspath, - scratch_pool, scratch_pool)); - - /* Children first */ - if (base_kind == svn_wc__db_kind_dir - && (base_status == svn_wc__db_status_normal - || base_status == svn_wc__db_status_incomplete)) - { - const apr_array_header_t *children; - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - int i; - - SVN_ERR(svn_wc__db_base_get_children(&children, db, local_abspath, - scratch_pool, iterpool)); - - for (i = 0; i < children->nelts; i++) - { - const char *child_name = APR_ARRAY_IDX(children, i, const char *); - const char *child_abspath; - - svn_pool_clear(iterpool); - - child_abspath = svn_dirent_join(local_abspath, child_name, iterpool); - - SVN_ERR(remove_base_node(db, child_abspath, cancel_func, cancel_baton, - iterpool)); - } - - svn_pool_destroy(iterpool); - } - - if (base_status == svn_wc__db_status_normal - && wrk_status != svn_wc__db_status_added - && wrk_status != svn_wc__db_status_excluded) - { - if (wrk_status != svn_wc__db_status_deleted - && (base_kind == svn_wc__db_kind_file - || base_kind == svn_wc__db_kind_symlink)) - { - SVN_ERR(svn_io_remove_file2(local_abspath, TRUE, scratch_pool)); - } - else if (base_kind == svn_wc__db_kind_dir - && wrk_status != svn_wc__db_status_deleted) - { - err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool); - if (err && (APR_STATUS_IS_ENOENT(err->apr_err) - || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err) - || APR_STATUS_IS_ENOTEMPTY(err->apr_err))) - svn_error_clear(err); - else - SVN_ERR(err); - } - } - - SVN_ERR(svn_wc__db_base_remove(db, local_abspath, scratch_pool)); - - return SVN_NO_ERROR; -} - + */ /* Process the OP_REMOVE_BASE work item WORK_ITEM. * See svn_wc__wq_build_remove_base() which generates this work item. * Implements (struct work_item_dispatch).func. */ static svn_error_t * -run_base_remove(svn_wc__db_t *db, +run_base_remove(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -219,8 +107,6 @@ run_base_remove(svn_wc__db_t *db, const char *local_relpath; const char *local_abspath; svn_revnum_t not_present_rev = SVN_INVALID_REVNUM; - svn_wc__db_kind_t not_present_kind; - const char *repos_relpath, *repos_root_url, *repos_uuid; apr_int64_t val; local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); @@ -233,23 +119,6 @@ run_base_remove(svn_wc__db_t *db, not_present_rev = (svn_revnum_t)val; SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool)); - not_present_kind = (svn_wc__db_kind_t)val; - - if (SVN_IS_VALID_REVNUM(not_present_rev)) - { - const char *dir_abspath, *name; - - /* This wq operation is restartable, so we can't assume the node - to be here. But we can assume that the parent is still there */ - svn_dirent_split(&dir_abspath, &name, local_abspath, scratch_pool); - - SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url, - &repos_uuid, - db, dir_abspath, - scratch_pool, scratch_pool)); - - repos_relpath = svn_relpath_join(repos_relpath, name, scratch_pool); - } } else { @@ -261,55 +130,22 @@ run_base_remove(svn_wc__db_t *db, if (keep_not_present) { - SVN_ERR(svn_wc__db_base_get_info(NULL, ¬_present_kind, - ¬_present_rev, &repos_relpath, - &repos_root_url, &repos_uuid, NULL, + SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, + ¬_present_rev, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, + NULL, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); } } - SVN_ERR(remove_base_node(db, local_abspath, - cancel_func, cancel_baton, - scratch_pool)); - - if (SVN_IS_VALID_REVNUM(not_present_rev)) - { - SVN_ERR(svn_wc__db_base_add_not_present_node(db, local_abspath, - repos_relpath, - repos_root_url, - repos_uuid, - not_present_rev, - not_present_kind, - NULL, - NULL, - scratch_pool)); - } - - return SVN_NO_ERROR; -} - -svn_error_t * -svn_wc__wq_build_base_remove(svn_skel_t **work_item, - svn_wc__db_t *db, - const char *local_abspath, - svn_revnum_t not_present_revision, - svn_wc__db_kind_t not_present_kind, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *local_relpath; - *work_item = svn_skel__make_empty_list(result_pool); - - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - local_abspath, result_pool, scratch_pool)); - - svn_skel__prepend_int(not_present_kind, *work_item, result_pool); - svn_skel__prepend_int(not_present_revision, *work_item, result_pool); - svn_skel__prepend_str(local_relpath, *work_item, result_pool); - svn_skel__prepend_str(OP_BASE_REMOVE, *work_item, result_pool); + SVN_ERR(svn_wc__db_base_remove(db, local_abspath, + FALSE /* keep_as_working */, + TRUE /* queue_deletes */, + FALSE /* remove_locks */, + not_present_rev, + NULL, NULL, scratch_pool)); return SVN_NO_ERROR; } @@ -499,7 +335,8 @@ process_commit_file_install(svn_wc__db_t *db, static svn_error_t * -run_file_commit(svn_wc__db_t *db, +run_file_commit(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -536,10 +373,6 @@ svn_wc__wq_build_file_commit(svn_skel_t **work_item, SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, local_abspath, result_pool, scratch_pool)); - /* This are currently ignored, they are here for compat. */ - svn_skel__prepend_int(FALSE, *work_item, result_pool); - svn_skel__prepend_int(FALSE, *work_item, result_pool); - svn_skel__prepend_str(local_relpath, *work_item, result_pool); svn_skel__prepend_str(OP_FILE_COMMIT, *work_item, result_pool); @@ -551,7 +384,8 @@ svn_wc__wq_build_file_commit(svn_skel_t **work_item, /* OP_POSTUPGRADE */ static svn_error_t * -run_postupgrade(svn_wc__db_t *db, +run_postupgrade(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -570,6 +404,8 @@ run_postupgrade(svn_wc__db_t *db, if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND) /* No entry, this can happen when the wq item is rerun. */ svn_error_clear(err); + else + SVN_ERR(err); SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath, scratch_pool, scratch_pool)); @@ -617,7 +453,8 @@ svn_wc__wq_build_postupgrade(svn_skel_t **work_item, * See svn_wc__wq_build_file_install() which generates this work item. * Implements (struct work_item_dispatch).func. */ static svn_error_t * -run_file_install(svn_wc__db_t *db, +run_file_install(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -715,6 +552,8 @@ run_file_install(svn_wc__db_t *db, scratch_pool)); /* No need to set exec or read-only flags on special files. */ + + /* ### Shouldn't this record a timestamp and size, etc.? */ return SVN_NO_ERROR; } @@ -781,12 +620,27 @@ run_file_install(svn_wc__db_t *db, } /* Tweak the on-disk file according to its properties. */ - if (props - && (apr_hash_get(props, SVN_PROP_NEEDS_LOCK, APR_HASH_KEY_STRING) - || apr_hash_get(props, SVN_PROP_EXECUTABLE, APR_HASH_KEY_STRING))) +#ifndef WIN32 + if (props && svn_hash_gets(props, SVN_PROP_EXECUTABLE)) + SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE, + scratch_pool)); +#endif + + /* Note that this explicitly checks the pristine properties, to make sure + that when the lock is locally set (=modification) it is not read only */ + if (props && svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)) { - SVN_ERR(svn_wc__sync_flags_with_props(NULL, db, local_abspath, - scratch_pool)); + svn_wc__db_status_t status; + svn_wc__db_lock_t *lock; + SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &lock, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + db, local_abspath, + scratch_pool, scratch_pool)); + + if (!lock && status != svn_wc__db_status_added) + SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool)); } if (use_commit_times) @@ -800,7 +654,7 @@ run_file_install(svn_wc__db_t *db, /* ### this should happen before we rename the file into place. */ if (record_fileinfo) { - SVN_ERR(get_and_record_fileinfo(db, local_abspath, + SVN_ERR(get_and_record_fileinfo(wqb, local_abspath, FALSE /* ignore_enoent */, scratch_pool)); } @@ -820,19 +674,25 @@ svn_wc__wq_build_file_install(svn_skel_t **work_item, apr_pool_t *scratch_pool) { const char *local_relpath; + const char *wri_abspath; *work_item = svn_skel__make_empty_list(result_pool); + /* Use the directory of the file to install as wri_abspath to avoid + filestats on just obtaining the wc-root */ + wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool); + /* If a SOURCE_ABSPATH was provided, then put it into the skel. If this - value is not provided, then the file's pristine contents will be used. */ + value is not provided, then the file's pristine contents will be used. */ if (source_abspath != NULL) { - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - source_abspath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, + source_abspath, + result_pool, scratch_pool)); svn_skel__prepend_str(local_relpath, *work_item, result_pool); } - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, + SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, local_abspath, result_pool, scratch_pool)); svn_skel__prepend_int(record_fileinfo, *work_item, result_pool); @@ -852,12 +712,13 @@ svn_wc__wq_build_file_install(svn_skel_t **work_item, * See svn_wc__wq_build_file_remove() which generates this work item. * Implements (struct work_item_dispatch).func. */ static svn_error_t * -run_file_remove(svn_wc__db_t *db, - const svn_skel_t *work_item, - const char *wri_abspath, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) +run_file_remove(work_item_baton_t *wqb, + svn_wc__db_t *db, + const svn_skel_t *work_item, + const char *wri_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) { const svn_skel_t *arg1 = work_item->children->next; const char *local_relpath; @@ -876,6 +737,7 @@ run_file_remove(svn_wc__db_t *db, svn_error_t * svn_wc__wq_build_file_remove(svn_skel_t **work_item, svn_wc__db_t *db, + const char *wri_abspath, const char *local_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -883,7 +745,7 @@ svn_wc__wq_build_file_remove(svn_skel_t **work_item, const char *local_relpath; *work_item = svn_skel__make_empty_list(result_pool); - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, + SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, local_abspath, result_pool, scratch_pool)); svn_skel__prepend_str(local_relpath, *work_item, result_pool); @@ -894,18 +756,101 @@ svn_wc__wq_build_file_remove(svn_skel_t **work_item, /* ------------------------------------------------------------------------ */ +/* OP_DIRECTORY_REMOVE */ + +/* Process the OP_FILE_REMOVE work item WORK_ITEM. + * See svn_wc__wq_build_file_remove() which generates this work item. + * Implements (struct work_item_dispatch).func. */ +static svn_error_t * +run_dir_remove(work_item_baton_t *wqb, + svn_wc__db_t *db, + const svn_skel_t *work_item, + const char *wri_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + const svn_skel_t *arg1 = work_item->children->next; + const char *local_relpath; + const char *local_abspath; + svn_boolean_t recursive; + + local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); + SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, + local_relpath, scratch_pool, scratch_pool)); + + recursive = FALSE; + if (arg1->next) + { + apr_int64_t val; + SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool)); + + recursive = (val != 0); + } + + /* Remove the path, no worrying if it isn't there. */ + if (recursive) + return svn_error_trace( + svn_io_remove_dir2(local_abspath, TRUE, + cancel_func, cancel_baton, + scratch_pool)); + else + { + svn_error_t *err; + + err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool); + + if (err && (APR_STATUS_IS_ENOENT(err->apr_err) + || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err) + || APR_STATUS_IS_ENOTEMPTY(err->apr_err))) + { + svn_error_clear(err); + err = NULL; + } + + return svn_error_trace(err); + } +} + +svn_error_t * +svn_wc__wq_build_dir_remove(svn_skel_t **work_item, + svn_wc__db_t *db, + const char *wri_abspath, + const char *local_abspath, + svn_boolean_t recursive, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const char *local_relpath; + *work_item = svn_skel__make_empty_list(result_pool); + + SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath, + local_abspath, result_pool, scratch_pool)); + + if (recursive) + svn_skel__prepend_int(TRUE, *work_item, result_pool); + + svn_skel__prepend_str(local_relpath, *work_item, result_pool); + svn_skel__prepend_str(OP_DIRECTORY_REMOVE, *work_item, result_pool); + + return SVN_NO_ERROR; +} + +/* ------------------------------------------------------------------------ */ + /* OP_FILE_MOVE */ /* Process the OP_FILE_MOVE work item WORK_ITEM. * See svn_wc__wq_build_file_move() which generates this work item. * Implements (struct work_item_dispatch).func. */ static svn_error_t * -run_file_move(svn_wc__db_t *db, - const svn_skel_t *work_item, - const char *wri_abspath, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) +run_file_move(work_item_baton_t *wqb, + svn_wc__db_t *db, + const svn_skel_t *work_item, + const char *wri_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) { const svn_skel_t *arg1 = work_item->children->next; const char *src_abspath, *dst_abspath; @@ -982,7 +927,8 @@ svn_wc__wq_build_file_move(svn_skel_t **work_item, * See run_file_copy_translated() which generates this work item. * Implements (struct work_item_dispatch).func. */ static svn_error_t * -run_file_copy_translated(svn_wc__db_t *db, +run_file_copy_translated(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -1071,6 +1017,52 @@ svn_wc__wq_build_file_copy_translated(svn_skel_t **work_item, return SVN_NO_ERROR; } +/* ------------------------------------------------------------------------ */ + +/* OP_DIRECTORY_INSTALL */ + +static svn_error_t * +run_dir_install(work_item_baton_t *wqb, + svn_wc__db_t *db, + const svn_skel_t *work_item, + const char *wri_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + const svn_skel_t *arg1 = work_item->children->next; + const char *local_relpath; + const char *local_abspath; + + local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); + SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, + local_relpath, scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__ensure_directory(local_abspath, scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__wq_build_dir_install(svn_skel_t **work_item, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *scratch_pool, + apr_pool_t *result_pool) +{ + const char *local_relpath; + + *work_item = svn_skel__make_empty_list(result_pool); + + SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, + local_abspath, result_pool, scratch_pool)); + svn_skel__prepend_str(local_relpath, *work_item, result_pool); + + svn_skel__prepend_str(OP_DIRECTORY_INSTALL, *work_item, result_pool); + + return SVN_NO_ERROR; +} + /* ------------------------------------------------------------------------ */ @@ -1080,7 +1072,8 @@ svn_wc__wq_build_file_copy_translated(svn_skel_t **work_item, * See svn_wc__wq_build_sync_file_flags() which generates this work item. * Implements (struct work_item_dispatch).func. */ static svn_error_t * -run_sync_file_flags(svn_wc__db_t *db, +run_sync_file_flags(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -1125,7 +1118,8 @@ svn_wc__wq_build_sync_file_flags(svn_skel_t **work_item, /* OP_PREJ_INSTALL */ static svn_error_t * -run_prej_install(svn_wc__db_t *db, +run_prej_install(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -1135,29 +1129,34 @@ run_prej_install(svn_wc__db_t *db, const svn_skel_t *arg1 = work_item->children->next; const char *local_relpath; const char *local_abspath; - const svn_skel_t *conflict_skel; + svn_skel_t *conflicts; + const svn_skel_t *prop_conflict_skel; const char *tmp_prejfile_abspath; const char *prejfile_abspath; local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len); SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath, local_relpath, scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__conflict_read_prop_conflict(&prejfile_abspath, + NULL, NULL, NULL, NULL, + db, local_abspath, conflicts, + scratch_pool, scratch_pool)); + if (arg1->next != NULL) - conflict_skel = arg1->next; + prop_conflict_skel = arg1->next; else SVN_ERR_MALFUNCTION(); /* ### wc_db can't provide it ... yet. */ /* Construct a property reject file in the temporary area. */ SVN_ERR(svn_wc__create_prejfile(&tmp_prejfile_abspath, db, local_abspath, - conflict_skel, + prop_conflict_skel, scratch_pool, scratch_pool)); - /* Get the (stored) name of where it should go. */ - SVN_ERR(svn_wc__get_prejfile_abspath(&prejfile_abspath, db, local_abspath, - scratch_pool, scratch_pool)); - SVN_ERR_ASSERT(prejfile_abspath != NULL); - /* ... and atomically move it into place. */ SVN_ERR(svn_io_file_rename(tmp_prejfile_abspath, prejfile_abspath, @@ -1199,7 +1198,8 @@ svn_wc__wq_build_prej_install(svn_skel_t **work_item, static svn_error_t * -run_record_fileinfo(svn_wc__db_t *db, +run_record_fileinfo(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -1244,49 +1244,24 @@ run_record_fileinfo(svn_wc__db_t *db, } - return svn_error_trace(get_and_record_fileinfo(db, local_abspath, + return svn_error_trace(get_and_record_fileinfo(wqb, local_abspath, TRUE /* ignore_enoent */, scratch_pool)); } - -svn_error_t * -svn_wc__wq_build_record_fileinfo(svn_skel_t **work_item, - svn_wc__db_t *db, - const char *local_abspath, - apr_time_t set_time, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *local_relpath; - *work_item = svn_skel__make_empty_list(result_pool); - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); - - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - local_abspath, result_pool, scratch_pool)); - - if (set_time) - svn_skel__prepend_int(set_time, *work_item, result_pool); - - svn_skel__prepend_str(local_relpath, *work_item, result_pool); - svn_skel__prepend_str(OP_RECORD_FILEINFO, *work_item, result_pool); - - return SVN_NO_ERROR; -} - /* ------------------------------------------------------------------------ */ /* OP_TMP_SET_TEXT_CONFLICT_MARKERS */ static svn_error_t * -run_set_text_conflict_markers(svn_wc__db_t *db, - const svn_skel_t *work_item, - const char *wri_abspath, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) +run_set_text_conflict_markers(work_item_baton_t *wqb, + svn_wc__db_t *db, + const svn_skel_t *work_item, + const char *wri_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) { const svn_skel_t *arg = work_item->children->next; const char *local_relpath; @@ -1331,58 +1306,42 @@ run_set_text_conflict_markers(svn_wc__db_t *db, scratch_pool, scratch_pool)); } - return svn_error_trace( - svn_wc__db_temp_op_set_text_conflict_marker_files(db, - local_abspath, - old_abspath, - new_abspath, - wrk_abspath, - scratch_pool)); -} - + /* Upgrade scenario: We have a workqueue item that describes how to install a + non skel conflict. Fetch all the information we can to create a new style + conflict. */ + /* ### Before format 30 this is/was a common code path as we didn't install + ### the conflict directly in the db. It just calls the wc_db code + ### to set the right fields. */ -svn_error_t * -svn_wc__wq_tmp_build_set_text_conflict_markers(svn_skel_t **work_item, - svn_wc__db_t *db, - const char *local_abspath, - const char *old_abspath, - const char *new_abspath, - const char *wrk_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *local_relpath; - *work_item = svn_skel__make_empty_list(result_pool); - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); - - /* Abspaths in the workqueue won't work if the WC is moved. */ - if (wrk_abspath) - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - wrk_abspath, result_pool, scratch_pool)); - - svn_skel__prepend_str(wrk_abspath ? local_relpath : "", - *work_item, result_pool); + { + /* Check if we should combine with a property conflict... */ + svn_skel_t *conflicts; - if (new_abspath) - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - new_abspath, result_pool, scratch_pool)); - svn_skel__prepend_str(new_abspath ? local_relpath : "", - *work_item, result_pool); + SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath, + scratch_pool, scratch_pool)); - if (old_abspath) - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - old_abspath, result_pool, scratch_pool)); - svn_skel__prepend_str(old_abspath ? local_relpath : "", - *work_item, result_pool); + if (! conflicts) + { + /* No conflict exists, create a basic skel */ + conflicts = svn_wc__conflict_skel_create(scratch_pool); - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - local_abspath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__conflict_skel_set_op_update(conflicts, NULL, NULL, + scratch_pool, + scratch_pool)); + } - svn_skel__prepend_str(local_relpath, *work_item, result_pool); - svn_skel__prepend_str(OP_TMP_SET_TEXT_CONFLICT_MARKERS, *work_item, - result_pool); + /* Add the text conflict to the existing onflict */ + SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflicts, db, + local_abspath, + wrk_abspath, + old_abspath, + new_abspath, + scratch_pool, + scratch_pool)); + SVN_ERR(svn_wc__db_op_mark_conflict(db, local_abspath, conflicts, + NULL, scratch_pool)); + } return SVN_NO_ERROR; } @@ -1391,7 +1350,8 @@ svn_wc__wq_tmp_build_set_text_conflict_markers(svn_skel_t **work_item, /* OP_TMP_SET_PROPERTY_CONFLICT_MARKER */ static svn_error_t * -run_set_property_conflict_marker(svn_wc__db_t *db, +run_set_property_conflict_marker(work_item_baton_t *wqb, + svn_wc__db_t *db, const svn_skel_t *work_item, const char *wri_abspath, svn_cancel_func_t cancel_func, @@ -1411,47 +1371,43 @@ run_set_property_conflict_marker(svn_wc__db_t *db, arg = arg->next; local_relpath = arg->len ? apr_pstrmemdup(scratch_pool, arg->data, arg->len) - : NULL; + : NULL; if (local_relpath) SVN_ERR(svn_wc__db_from_relpath(&prej_abspath, db, wri_abspath, local_relpath, scratch_pool, scratch_pool)); - return svn_error_trace( - svn_wc__db_temp_op_set_property_conflict_marker_file(db, - local_abspath, - prej_abspath, - scratch_pool)); -} - -svn_error_t * -svn_wc__wq_tmp_build_set_property_conflict_marker(svn_skel_t **work_item, - svn_wc__db_t *db, - const char *local_abspath, - const char *prej_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *local_relpath; - *work_item = svn_skel__make_empty_list(result_pool); - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + { + /* Check if we should combine with a text conflict... */ + svn_skel_t *conflicts; + apr_hash_t *prop_names; - if (prej_abspath) - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - prej_abspath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath, + scratch_pool, scratch_pool)); - svn_skel__prepend_str(prej_abspath ? local_relpath : "", - *work_item, result_pool); + if (! conflicts) + { + /* No conflict exists, create a basic skel */ + conflicts = svn_wc__conflict_skel_create(scratch_pool); - SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath, - local_abspath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__conflict_skel_set_op_update(conflicts, NULL, NULL, + scratch_pool, + scratch_pool)); + } - svn_skel__prepend_str(local_relpath, *work_item, result_pool); - svn_skel__prepend_str(OP_TMP_SET_PROPERTY_CONFLICT_MARKER, *work_item, - result_pool); + prop_names = apr_hash_make(scratch_pool); + SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflicts, db, + local_abspath, + prej_abspath, + NULL, NULL, NULL, + prop_names, + scratch_pool, + scratch_pool)); + SVN_ERR(svn_wc__db_op_mark_conflict(db, local_abspath, conflicts, + NULL, scratch_pool)); + } return SVN_NO_ERROR; } @@ -1465,21 +1421,35 @@ static const struct work_item_dispatch dispatch_table[] = { { OP_FILE_COPY_TRANSLATED, run_file_copy_translated }, { OP_SYNC_FILE_FLAGS, run_sync_file_flags }, { OP_PREJ_INSTALL, run_prej_install }, - { OP_RECORD_FILEINFO, run_record_fileinfo }, - { OP_BASE_REMOVE, run_base_remove }, - { OP_TMP_SET_TEXT_CONFLICT_MARKERS, run_set_text_conflict_markers }, - { OP_TMP_SET_PROPERTY_CONFLICT_MARKER, run_set_property_conflict_marker }, + { OP_DIRECTORY_REMOVE, run_dir_remove }, + { OP_DIRECTORY_INSTALL, run_dir_install }, /* Upgrade steps */ { OP_POSTUPGRADE, run_postupgrade }, + /* Legacy workqueue items. No longer created */ + { OP_BASE_REMOVE, run_base_remove }, + { OP_RECORD_FILEINFO, run_record_fileinfo }, + { OP_TMP_SET_TEXT_CONFLICT_MARKERS, run_set_text_conflict_markers }, + { OP_TMP_SET_PROPERTY_CONFLICT_MARKER, run_set_property_conflict_marker }, + /* Sentinel. */ { NULL } }; +struct work_item_baton_t +{ + apr_pool_t *result_pool; /* Pool to allocate result in */ + + svn_boolean_t used; /* needs reset */ + + apr_hash_t *record_map; /* const char * -> svn_io_dirent2_t map */ +}; + static svn_error_t * -dispatch_work_item(svn_wc__db_t *db, +dispatch_work_item(work_item_baton_t *wqb, + svn_wc__db_t *db, const char *wri_abspath, const svn_skel_t *work_item, svn_cancel_func_t cancel_func, @@ -1497,7 +1467,7 @@ dispatch_work_item(svn_wc__db_t *db, #ifdef SVN_DEBUG_WORK_QUEUE SVN_DBG(("dispatch: operation='%s'\n", scan->name)); #endif - SVN_ERR((*scan->func)(db, work_item, wri_abspath, + SVN_ERR((*scan->func)(wqb, db, work_item, wri_abspath, cancel_func, cancel_baton, scratch_pool)); @@ -1526,10 +1496,7 @@ dispatch_work_item(svn_wc__db_t *db, Contrary to issue #1581, we cannot simply remove work items and continue, so bail out with an error. */ return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, NULL, - _("Unrecognized work item in the queue " - "associated with '%s'"), - svn_dirent_local_style(wri_abspath, - scratch_pool)); + _("Unrecognized work item in the queue")); } return SVN_NO_ERROR; @@ -1545,6 +1512,8 @@ svn_wc__wq_run(svn_wc__db_t *db, { apr_pool_t *iterpool = svn_pool_create(scratch_pool); apr_uint64_t last_id = 0; + work_item_baton_t wib = { 0 }; + wib.result_pool = svn_pool_create(scratch_pool); #ifdef SVN_DEBUG_WORK_QUEUE SVN_DBG(("wq_run: wri='%s'\n", wri_abspath)); @@ -1561,14 +1530,33 @@ svn_wc__wq_run(svn_wc__db_t *db, { apr_uint64_t id; svn_skel_t *work_item; + svn_error_t *err; svn_pool_clear(iterpool); - /* Make sure to do this *early* in the loop iteration. There may - be a LAST_ID that needs to be marked as completed, *before* we - start worrying about anything else. */ - SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, wri_abspath, - last_id, iterpool, iterpool)); + if (! wib.used) + { + /* Make sure to do this *early* in the loop iteration. There may + be a LAST_ID that needs to be marked as completed, *before* we + start worrying about anything else. */ + SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, wri_abspath, + last_id, iterpool, iterpool)); + } + else + { + /* Make sure to do this *early* in the loop iteration. There may + be a LAST_ID that needs to be marked as completed, *before* we + start worrying about anything else. */ + SVN_ERR(svn_wc__db_wq_record_and_fetch_next(&id, &work_item, + db, wri_abspath, + last_id, wib.record_map, + iterpool, + wib.result_pool)); + + svn_pool_clear(wib.result_pool); + wib.record_map = NULL; + wib.used = FALSE; + } /* Stop work queue processing, if requested. A future 'svn cleanup' should be able to continue the processing. Note that we may @@ -1580,8 +1568,20 @@ svn_wc__wq_run(svn_wc__db_t *db, we're done. */ if (work_item == NULL) break; - SVN_ERR(dispatch_work_item(db, wri_abspath, work_item, - cancel_func, cancel_baton, iterpool)); + + err = dispatch_work_item(&wib, db, wri_abspath, work_item, + cancel_func, cancel_baton, iterpool); + if (err) + { + const char *skel = svn_skel__unparse(work_item, scratch_pool)->data; + + return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, err, + _("Failed to run the WC DB work queue " + "associated with '%s', work item %d %s"), + svn_dirent_local_style(wri_abspath, + scratch_pool), + (int)id, skel); + } /* The work item finished without error. Mark it completed in the next loop. */ @@ -1639,3 +1639,29 @@ svn_wc__wq_merge(svn_skel_t *work_item1, svn_skel__append(work_item1, work_item2->children); return work_item1; } + + +static svn_error_t * +get_and_record_fileinfo(work_item_baton_t *wqb, + const char *local_abspath, + svn_boolean_t ignore_enoent, + apr_pool_t *scratch_pool) +{ + const svn_io_dirent2_t *dirent; + + SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, ignore_enoent, + wqb->result_pool, scratch_pool)); + + if (dirent->kind != svn_node_file) + return SVN_NO_ERROR; + + wqb->used = TRUE; + + if (! wqb->record_map) + wqb->record_map = apr_hash_make(wqb->result_pool); + + svn_hash_sets(wqb->record_map, apr_pstrdup(wqb->result_pool, local_abspath), + dirent); + + return SVN_NO_ERROR; +} |