diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/libsvn_wc/entries.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/libsvn_wc/entries.c')
-rw-r--r-- | subversion/libsvn_wc/entries.c | 536 |
1 files changed, 328 insertions, 208 deletions
diff --git a/subversion/libsvn_wc/entries.c b/subversion/libsvn_wc/entries.c index 24dae50..1be6a8b 100644 --- a/subversion/libsvn_wc/entries.c +++ b/subversion/libsvn_wc/entries.c @@ -45,9 +45,14 @@ #include "wc_db.h" #include "wc-queries.h" /* for STMT_* */ +#define SVN_WC__I_AM_WC_DB + #include "svn_private_config.h" #include "private/svn_wc_private.h" #include "private/svn_sqlite.h" +#include "token-map.h" + +#include "wc_db_private.h" #define MAYBE_ALLOC(x,p) ((x) ? (x) : apr_pcalloc((p), sizeof(*(x)))) @@ -213,6 +218,8 @@ get_info_for_deleted(svn_wc_entry_t *entry, svn_wc__db_lock_t **lock, svn_wc__db_t *db, const char *entry_abspath, + svn_wc__db_wcroot_t *wcroot, + const char *entry_relpath, const svn_wc_entry_t *parent_entry, svn_boolean_t have_base, svn_boolean_t have_more_work, @@ -221,12 +228,13 @@ get_info_for_deleted(svn_wc_entry_t *entry, { if (have_base && !have_more_work) { + apr_int64_t repos_id; /* This is the delete of a BASE node */ - SVN_ERR(svn_wc__db_base_get_info(NULL, kind, + SVN_ERR(svn_wc__db_base_get_info_internal( + NULL, kind, &entry->revision, repos_relpath, - &entry->repos, - &entry->uuid, + &repos_id, &entry->cmt_rev, &entry->cmt_date, &entry->cmt_author, @@ -236,16 +244,18 @@ get_info_for_deleted(svn_wc_entry_t *entry, lock, &entry->has_props, NULL, NULL, - db, - entry_abspath, + wcroot, entry_relpath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid, + wcroot, repos_id, result_pool)); } else { - const char *work_del_abspath; + const char *work_del_relpath; const char *parent_repos_relpath; - const char *parent_abspath; + const char *parent_relpath; + apr_int64_t repos_id; /* This is a deleted child of a copy/move-here, so we need to scan up the WORKING tree to find the root of @@ -265,30 +275,33 @@ get_info_for_deleted(svn_wc_entry_t *entry, scratch_pool)); /* working_size and text_time unavailable */ - SVN_ERR(svn_wc__db_scan_deletion(NULL, + SVN_ERR(svn_wc__db_scan_deletion_internal( NULL, - &work_del_abspath, NULL, - db, entry_abspath, + NULL, + &work_del_relpath, NULL, + wcroot, entry_relpath, scratch_pool, scratch_pool)); - SVN_ERR_ASSERT(work_del_abspath != NULL); - parent_abspath = svn_dirent_dirname(work_del_abspath, scratch_pool); + SVN_ERR_ASSERT(work_del_relpath != NULL); + parent_relpath = svn_relpath_dirname(work_del_relpath, scratch_pool); /* The parent directory of the delete root must be added, so we can find the required information there */ - SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, + SVN_ERR(svn_wc__db_scan_addition_internal( + NULL, NULL, &parent_repos_relpath, - &entry->repos, - &entry->uuid, - NULL, NULL, NULL, NULL, - db, parent_abspath, + &repos_id, + NULL, NULL, NULL, + wcroot, parent_relpath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid, + wcroot, repos_id, result_pool)); /* Now glue it all together */ *repos_relpath = svn_relpath_join(parent_repos_relpath, - svn_dirent_is_child(parent_abspath, - entry_abspath, - NULL), + svn_relpath_skip_ancestor( + parent_relpath, + entry_relpath), result_pool); @@ -297,11 +310,12 @@ get_info_for_deleted(svn_wc_entry_t *entry, if (have_base) { svn_wc__db_status_t status; - SVN_ERR(svn_wc__db_base_get_info(&status, NULL, &entry->revision, + SVN_ERR(svn_wc__db_base_get_info_internal( + &status, NULL, &entry->revision, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, lock, NULL, NULL, + NULL, NULL, lock, NULL, NULL, NULL, - db, entry_abspath, + wcroot, entry_relpath, result_pool, scratch_pool)); if (status == svn_wc__db_status_not_present) @@ -346,7 +360,7 @@ write_tree_conflicts(const char **conflict_data, { svn_skel_t *c_skel; - SVN_ERR(svn_wc__serialize_conflict(&c_skel, svn__apr_hash_index_val(hi), + SVN_ERR(svn_wc__serialize_conflict(&c_skel, apr_hash_this_val(hi), pool, pool)); svn_skel__prepend(c_skel, skel); } @@ -369,12 +383,17 @@ write_tree_conflicts(const char **conflict_data, If this node is "this dir", then PARENT_ENTRY should be NULL. Otherwise, it should refer to the entry for the child's parent directory. + ### All database read operations should really use wcroot, dir_relpath, + as that restores obstruction compatibility with <= 1.6.0 + but that has been the case since the introduction of WC-NG in 1.7.0 + Temporary allocations are made in SCRATCH_POOL. */ static svn_error_t * read_one_entry(const svn_wc_entry_t **new_entry, svn_wc__db_t *db, - apr_int64_t wc_id, const char *dir_abspath, + svn_wc__db_wcroot_t *wcroot, + const char *dir_relpath, const char *name, const svn_wc_entry_t *parent_entry, apr_pool_t *result_pool, @@ -387,24 +406,28 @@ read_one_entry(const svn_wc_entry_t **new_entry, const svn_checksum_t *checksum; svn_filesize_t translated_size; svn_wc_entry_t *entry = alloc_entry(result_pool); + const char *entry_relpath; const char *entry_abspath; + apr_int64_t repos_id; + apr_int64_t original_repos_id; const char *original_repos_relpath; const char *original_root_url; svn_boolean_t conflicted; svn_boolean_t have_base; svn_boolean_t have_more_work; + svn_boolean_t op_root; - entry->name = name; + entry->name = apr_pstrdup(result_pool, name); + entry_relpath = svn_relpath_join(dir_relpath, entry->name, scratch_pool); entry_abspath = svn_dirent_join(dir_abspath, entry->name, scratch_pool); - SVN_ERR(svn_wc__db_read_info( + SVN_ERR(svn_wc__db_read_info_internal( &status, &kind, &entry->revision, &repos_relpath, - &entry->repos, - &entry->uuid, + &repos_id, &entry->cmt_rev, &entry->cmt_date, &entry->cmt_author, @@ -412,24 +435,27 @@ read_one_entry(const svn_wc_entry_t **new_entry, &checksum, NULL, &original_repos_relpath, - &original_root_url, - NULL, + &original_repos_id, &entry->copyfrom_rev, &lock, &translated_size, &entry->text_time, &entry->changelist, &conflicted, - NULL /* op_root */, + &op_root, &entry->has_props /* have_props */, &entry->has_prop_mods /* props_mod */, &have_base, &have_more_work, NULL /* have_work */, - db, - entry_abspath, - result_pool, - scratch_pool)); + wcroot, entry_relpath, + result_pool, scratch_pool)); + + SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid, + wcroot, repos_id, result_pool)); + SVN_ERR(svn_wc__db_fetch_repos_info(&original_root_url, NULL, + wcroot, original_repos_id, + result_pool)); if (entry->has_prop_mods) entry->has_props = TRUE; @@ -457,9 +483,10 @@ read_one_entry(const svn_wc_entry_t **new_entry, child_abspath = svn_dirent_join(dir_abspath, child_name, scratch_pool); - SVN_ERR(svn_wc__read_conflicts(&child_conflicts, + SVN_ERR(svn_wc__read_conflicts(&child_conflicts, NULL, db, child_abspath, FALSE /* create tempfiles */, + TRUE /* tree_conflicts_only */, scratch_pool, scratch_pool)); for (j = 0; j < child_conflicts->nelts; j++) @@ -493,13 +520,15 @@ read_one_entry(const svn_wc_entry_t **new_entry, /* Grab inherited repository information, if necessary. */ if (repos_relpath == NULL) { - SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, - &entry->repos, - &entry->uuid, - db, - entry_abspath, - result_pool, - scratch_pool)); + SVN_ERR(svn_wc__db_base_get_info_internal( + NULL, NULL, NULL, &repos_relpath, + &repos_id, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, + wcroot, entry_relpath, + result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid, + wcroot, repos_id, result_pool)); } entry->incomplete = (status == svn_wc__db_status_incomplete); @@ -519,13 +548,14 @@ read_one_entry(const svn_wc_entry_t **new_entry, entry->copied = FALSE; else { - const char *work_del_abspath; - SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL, - &work_del_abspath, NULL, - db, entry_abspath, + const char *work_del_relpath; + SVN_ERR(svn_wc__db_scan_deletion_internal( + NULL, NULL, + &work_del_relpath, NULL, + wcroot, entry_relpath, scratch_pool, scratch_pool)); - if (work_del_abspath) + if (work_del_relpath) entry->copied = TRUE; } @@ -563,13 +593,14 @@ read_one_entry(const svn_wc_entry_t **new_entry, /* ENTRY->REVISION is overloaded. When a node is schedule-add or -replace, then REVISION refers to the BASE node's revision that is being overwritten. We need to fetch it now. */ - SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, + SVN_ERR(svn_wc__db_base_get_info_internal( + &base_status, NULL, &entry->revision, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - db, entry_abspath, + NULL, NULL, NULL, + wcroot, entry_relpath, scratch_pool, scratch_pool)); @@ -603,18 +634,27 @@ read_one_entry(const svn_wc_entry_t **new_entry, have important data. Set up stuff to kill that idea off, and finish up this entry. */ { - SVN_ERR(svn_wc__db_scan_addition(&work_status, - &op_root_abspath, + const char *op_root_relpath; + SVN_ERR(svn_wc__db_scan_addition_internal( + &work_status, + &op_root_relpath, &repos_relpath, - &entry->repos, - &entry->uuid, + &repos_id, &scanned_original_relpath, - NULL, NULL, /* original_root|uuid */ + NULL /* original_repos_id */, &original_revision, - db, - entry_abspath, + wcroot, entry_relpath, result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid, + wcroot, repos_id, result_pool)); + + if (!op_root_relpath) + op_root_abspath = NULL; + else + op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath, + scratch_pool); + /* In wc.db we want to keep the valid revision of the not-present BASE_REV, but when we used entries we set the revision to 0 when adding a new node over a not present base node. */ @@ -633,7 +673,7 @@ read_one_entry(const svn_wc_entry_t **new_entry, /* ### scan_addition may need to be updated to avoid returning ### status_copied in this case. */ } - /* For backwards-compatiblity purposes we treat moves just like + /* For backwards-compatibility purposes we treat moves just like * regular copies. */ else if (work_status == svn_wc__db_status_copied || work_status == svn_wc__db_status_moved_here) @@ -675,10 +715,12 @@ read_one_entry(const svn_wc_entry_t **new_entry, mixed-revision situation. */ if (!is_copied_child) { - const char *parent_abspath; + const char *parent_relpath; svn_error_t *err; const char *parent_repos_relpath; const char *parent_root_url; + apr_int64_t parent_repos_id; + const char *op_root_relpath; /* When we insert entries into the database, we will construct additional copyfrom records for mixed-revision @@ -705,15 +747,16 @@ read_one_entry(const svn_wc_entry_t **new_entry, Note that the parent could be added/copied/moved-here. There is no way for it to be deleted/moved-away and have *this* node appear as copied. */ - parent_abspath = svn_dirent_dirname(entry_abspath, - scratch_pool); - err = svn_wc__db_scan_addition(NULL, - &op_root_abspath, - NULL, NULL, NULL, - &parent_repos_relpath, - &parent_root_url, + parent_relpath = svn_relpath_dirname(entry_relpath, + scratch_pool); + err = svn_wc__db_scan_addition_internal( + NULL, + &op_root_relpath, NULL, NULL, - db, parent_abspath, + &parent_repos_relpath, + &parent_repos_id, + NULL, + wcroot, parent_relpath, scratch_pool, scratch_pool); if (err) @@ -721,10 +764,24 @@ read_one_entry(const svn_wc_entry_t **new_entry, if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) return svn_error_trace(err); svn_error_clear(err); + op_root_abspath = NULL; + parent_repos_relpath = NULL; + parent_root_url = NULL; + } + else + { + SVN_ERR(svn_wc__db_fetch_repos_info(&parent_root_url, NULL, + wcroot, parent_repos_id, + scratch_pool)); + op_root_abspath = svn_dirent_join(wcroot->abspath, + op_root_relpath, + scratch_pool); } - else if (parent_root_url != NULL + + if (parent_root_url != NULL && strcmp(original_root_url, parent_root_url) == 0) { + const char *relpath_to_entry = svn_dirent_is_child( op_root_abspath, entry_abspath, NULL); const char *entry_repos_relpath = svn_relpath_join( @@ -827,6 +884,7 @@ read_one_entry(const svn_wc_entry_t **new_entry, &checksum, &lock, db, entry_abspath, + wcroot, entry_relpath, parent_entry, have_base, have_more_work, result_pool, scratch_pool)); @@ -869,7 +927,7 @@ read_one_entry(const svn_wc_entry_t **new_entry, /* We got a SHA-1, get the corresponding MD-5. */ if (checksum->kind != svn_checksum_md5) SVN_ERR(svn_wc__db_pristine_get_md5(&checksum, db, - entry_abspath, checksum, + dir_abspath, checksum, scratch_pool, scratch_pool)); SVN_ERR_ASSERT(checksum->kind == svn_checksum_md5); @@ -881,8 +939,9 @@ read_one_entry(const svn_wc_entry_t **new_entry, svn_skel_t *conflict; svn_boolean_t text_conflicted; svn_boolean_t prop_conflicted; - SVN_ERR(svn_wc__db_read_conflict(&conflict, db, entry_abspath, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, NULL, NULL, + wcroot, entry_relpath, + scratch_pool, scratch_pool)); SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, &text_conflicted, &prop_conflicted, NULL, @@ -955,7 +1014,9 @@ read_one_entry(const svn_wc_entry_t **new_entry, static svn_error_t * read_entries_new(apr_hash_t **result_entries, svn_wc__db_t *db, - const char *local_abspath, + const char *dir_abspath, + svn_wc__db_wcroot_t *wcroot, + const char *dir_relpath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -964,11 +1025,12 @@ read_entries_new(apr_hash_t **result_entries, apr_pool_t *iterpool = svn_pool_create(scratch_pool); int i; const svn_wc_entry_t *parent_entry; - apr_int64_t wc_id = 1; /* ### hacky. should remove. */ entries = apr_hash_make(result_pool); - SVN_ERR(read_one_entry(&parent_entry, db, wc_id, local_abspath, + SVN_ERR(read_one_entry(&parent_entry, + db, dir_abspath, + wcroot, dir_relpath, "" /* name */, NULL /* parent_entry */, result_pool, iterpool)); @@ -977,8 +1039,8 @@ read_entries_new(apr_hash_t **result_entries, /* Use result_pool so that the child names (used by reference, rather than copied) appear in result_pool. */ SVN_ERR(svn_wc__db_read_children(&children, db, - local_abspath, - result_pool, iterpool)); + dir_abspath, + scratch_pool, iterpool)); for (i = children->nelts; i--; ) { const char *name = APR_ARRAY_IDX(children, i, const char *); @@ -987,7 +1049,9 @@ read_entries_new(apr_hash_t **result_entries, svn_pool_clear(iterpool); SVN_ERR(read_one_entry(&entry, - db, wc_id, local_abspath, name, parent_entry, + db, dir_abspath, + wcroot, dir_relpath, + name, parent_entry, result_pool, iterpool)); svn_hash_sets(entries, entry->name, entry); } @@ -1000,28 +1064,20 @@ read_entries_new(apr_hash_t **result_entries, } -/* Read a pair of entries from wc_db in the directory DIR_ABSPATH. Return - the directory's entry in *PARENT_ENTRY and NAME's entry in *ENTRY. The - two returned pointers will be the same if NAME=="" ("this dir"). - - The parent entry must exist. - - The requested entry MAY exist. If it does not, then NULL will be returned. - - The resulting entries are allocated in RESULT_POOL, and all temporary - allocations are made in SCRATCH_POOL. */ static svn_error_t * -read_entry_pair(const svn_wc_entry_t **parent_entry, - const svn_wc_entry_t **entry, - svn_wc__db_t *db, - const char *dir_abspath, - const char *name, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +read_entry_pair_txn(const svn_wc_entry_t **parent_entry, + const svn_wc_entry_t **entry, + svn_wc__db_t *db, + const char *dir_abspath, + svn_wc__db_wcroot_t *wcroot, + const char *dir_relpath, + const char *name, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - apr_int64_t wc_id = 1; /* ### hacky. should remove. */ - - SVN_ERR(read_one_entry(parent_entry, db, wc_id, dir_abspath, + SVN_ERR(read_one_entry(parent_entry, + db, dir_abspath, + wcroot, dir_relpath, "" /* name */, NULL /* parent_entry */, result_pool, scratch_pool)); @@ -1073,7 +1129,9 @@ read_entry_pair(const svn_wc_entry_t **parent_entry, svn_error_t *err; err = read_one_entry(entry, - db, wc_id, dir_abspath, name, *parent_entry, + db, dir_abspath, + wcroot, dir_relpath, + name, *parent_entry, result_pool, scratch_pool); if (err) { @@ -1096,28 +1154,76 @@ read_entry_pair(const svn_wc_entry_t **parent_entry, return SVN_NO_ERROR; } +/* Read a pair of entries from wc_db in the directory DIR_ABSPATH. Return + the directory's entry in *PARENT_ENTRY and NAME's entry in *ENTRY. The + two returned pointers will be the same if NAME=="" ("this dir"). + + The parent entry must exist. + + The requested entry MAY exist. If it does not, then NULL will be returned. + + The resulting entries are allocated in RESULT_POOL, and all temporary + allocations are made in SCRATCH_POOL. */ +static svn_error_t * +read_entry_pair(const svn_wc_entry_t **parent_entry, + const svn_wc_entry_t **entry, + svn_wc__db_t *db, + const char *dir_abspath, + const char *name, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *dir_relpath; + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &dir_relpath, + db, dir_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_WC__DB_WITH_TXN(read_entry_pair_txn(parent_entry, entry, + db, dir_abspath, + wcroot, dir_relpath, + name, + result_pool, scratch_pool), + wcroot); + + return SVN_NO_ERROR; +} /* */ static svn_error_t * read_entries(apr_hash_t **entries, svn_wc__db_t *db, - const char *wcroot_abspath, + const char *dir_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { + svn_wc__db_wcroot_t *wcroot; + const char *dir_relpath; int wc_format; - SVN_ERR(svn_wc__db_temp_get_format(&wc_format, db, wcroot_abspath, + SVN_ERR(svn_wc__db_temp_get_format(&wc_format, db, dir_abspath, scratch_pool)); if (wc_format < SVN_WC__WC_NG_VERSION) return svn_error_trace(svn_wc__read_entries_old(entries, - wcroot_abspath, + dir_abspath, result_pool, scratch_pool)); - return svn_error_trace(read_entries_new(entries, db, wcroot_abspath, - result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &dir_relpath, + db, dir_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_WC__DB_WITH_TXN(read_entries_new(entries, + db, dir_abspath, + wcroot, dir_relpath, + result_pool, scratch_pool), + wcroot); + + return SVN_NO_ERROR; } @@ -1342,7 +1448,7 @@ prune_deleted(apr_hash_t **entries_pruned, svn_boolean_t hidden; SVN_ERR(svn_wc__entry_is_hidden(&hidden, - svn__apr_hash_index_val(hi))); + apr_hash_this_val(hi))); if (hidden) break; } @@ -1360,8 +1466,8 @@ prune_deleted(apr_hash_t **entries_pruned, hi; hi = apr_hash_next(hi)) { - const void *key = svn__apr_hash_index_key(hi); - const svn_wc_entry_t *entry = svn__apr_hash_index_val(hi); + const void *key = apr_hash_this_key(hi); + const svn_wc_entry_t *entry = apr_hash_this_val(hi); svn_boolean_t hidden; SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry)); @@ -1372,25 +1478,6 @@ prune_deleted(apr_hash_t **entries_pruned, return SVN_NO_ERROR; } -struct entries_read_baton_t -{ - apr_hash_t **new_entries; - svn_wc__db_t *db; - const char *local_abspath; - apr_pool_t *result_pool; -}; - -static svn_error_t * -entries_read_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool) -{ - struct entries_read_baton_t *erb = baton; - - SVN_ERR(read_entries(erb->new_entries, erb->db, erb->local_abspath, - erb->result_pool, scratch_pool)); - - return NULL; -} - svn_error_t * svn_wc__entries_read_internal(apr_hash_t **entries, svn_wc_adm_access_t *adm_access, @@ -1405,21 +1492,9 @@ svn_wc__entries_read_internal(apr_hash_t **entries, svn_wc__db_t *db = svn_wc__adm_get_db(adm_access); const char *local_abspath = svn_wc__adm_access_abspath(adm_access); apr_pool_t *result_pool = svn_wc__adm_access_pool_internal(adm_access); - svn_sqlite__db_t *sdb; - struct entries_read_baton_t erb; - - /* ### Use the borrow DB api to handle all calls in a single read - ### transaction. This api is used extensively in our test suite - ### via the entries-read application. */ - SVN_ERR(svn_wc__db_temp_borrow_sdb(&sdb, db, local_abspath, pool)); - - erb.db = db; - erb.local_abspath = local_abspath; - erb.new_entries = &new_entries; - erb.result_pool = result_pool; - - SVN_ERR(svn_sqlite__with_lock(sdb, entries_read_txn, &erb, pool)); + SVN_ERR(read_entries(&new_entries, db, local_abspath, + result_pool, pool)); svn_wc__adm_access_set_entries(adm_access, new_entries); } @@ -1452,23 +1527,31 @@ insert_node(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; + svn_boolean_t present = (node->presence == svn_wc__db_status_normal + || node->presence == svn_wc__db_status_incomplete); SVN_ERR_ASSERT(node->op_depth > 0 || node->repos_relpath); SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnnnsnrisnnni", + SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnnnsn", node->wc_id, node->local_relpath, node->op_depth, node->parent_relpath, /* Setting depth for files? */ - svn_depth_to_word(node->depth), - node->changed_rev, - node->changed_date, - node->changed_author, - node->recorded_time)); + (node->kind == svn_node_dir && present) + ? svn_depth_to_word(node->depth) + : NULL)); - if (node->repos_relpath) + if (present && node->repos_relpath) + { + SVN_ERR(svn_sqlite__bind_revnum(stmt, 11, node->changed_rev)); + SVN_ERR(svn_sqlite__bind_int64(stmt, 12, node->changed_date)); + SVN_ERR(svn_sqlite__bind_text(stmt, 13, node->changed_author)); + } + + if (node->repos_relpath + && node->presence != svn_wc__db_status_base_deleted) { SVN_ERR(svn_sqlite__bind_int64(stmt, 5, node->repos_id)); @@ -1477,26 +1560,14 @@ insert_node(svn_sqlite__db_t *sdb, SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, node->revision)); } - if (node->presence == svn_wc__db_status_normal) - SVN_ERR(svn_sqlite__bind_text(stmt, 8, "normal")); - else if (node->presence == svn_wc__db_status_not_present) - SVN_ERR(svn_sqlite__bind_text(stmt, 8, "not-present")); - else if (node->presence == svn_wc__db_status_base_deleted) - SVN_ERR(svn_sqlite__bind_text(stmt, 8, "base-deleted")); - else if (node->presence == svn_wc__db_status_incomplete) - SVN_ERR(svn_sqlite__bind_text(stmt, 8, "incomplete")); - else if (node->presence == svn_wc__db_status_excluded) - SVN_ERR(svn_sqlite__bind_text(stmt, 8, "excluded")); - else if (node->presence == svn_wc__db_status_server_excluded) - SVN_ERR(svn_sqlite__bind_text(stmt, 8, "server-excluded")); + SVN_ERR(svn_sqlite__bind_token(stmt, 8, presence_map, node->presence)); if (node->kind == svn_node_none) SVN_ERR(svn_sqlite__bind_text(stmt, 10, "unknown")); else - SVN_ERR(svn_sqlite__bind_text(stmt, 10, - svn_node_kind_to_word(node->kind))); + SVN_ERR(svn_sqlite__bind_token(stmt, 10, kind_map, node->kind)); - if (node->kind == svn_node_file) + if (node->kind == svn_node_file && present) { if (!node->checksum && node->op_depth == 0 @@ -1510,19 +1581,25 @@ insert_node(svn_sqlite__db_t *sdb, SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, node->checksum, scratch_pool)); + + if (node->repos_relpath) + { + if (node->recorded_size != SVN_INVALID_FILESIZE) + SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->recorded_size)); + + SVN_ERR(svn_sqlite__bind_int64(stmt, 17, node->recorded_time)); + } } - if (node->properties) /* ### Never set, props done later */ + /* ### Never set, props done later */ + if (node->properties && present && node->repos_relpath) SVN_ERR(svn_sqlite__bind_properties(stmt, 15, node->properties, scratch_pool)); - if (node->recorded_size != SVN_INVALID_FILESIZE) - SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->recorded_size)); - if (node->file_external) SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1)); - if (node->inherited_props) + if (node->inherited_props && present) SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, node->inherited_props, scratch_pool)); @@ -1801,6 +1878,10 @@ write_entry(struct write_baton **entry_node, if (entry->copied) { + db_node_t *work = parent_node->work + ? parent_node->work + : parent_node->below_work; + if (entry->copyfrom_url) { working_node->repos_id = repos_id; @@ -1810,20 +1891,37 @@ write_entry(struct write_baton **entry_node, working_node->revision = entry->copyfrom_rev; working_node->op_depth = svn_wc__db_op_depth_for_upgrade(local_relpath); + + if (work && work->repos_relpath + && work->repos_id == repos_id + && work->revision == entry->copyfrom_rev) + { + const char *name; + + name = svn_relpath_skip_ancestor(work->repos_relpath, + working_node->repos_relpath); + + if (name + && !strcmp(name, svn_relpath_basename(local_relpath, NULL))) + { + working_node->op_depth = work->op_depth; + } + } } - else if (parent_node->work && parent_node->work->repos_relpath) + else if (work && work->repos_relpath) { working_node->repos_id = repos_id; working_node->repos_relpath - = svn_relpath_join(parent_node->work->repos_relpath, + = svn_relpath_join(work->repos_relpath, svn_relpath_basename(local_relpath, NULL), result_pool); - working_node->revision = parent_node->work->revision; - working_node->op_depth = parent_node->work->op_depth; + working_node->revision = work->revision; + working_node->op_depth = work->op_depth; } else if (parent_node->below_work && parent_node->below_work->repos_relpath) { + /* Parent deleted, this not-present or similar */ working_node->repos_id = repos_id; working_node->repos_relpath = svn_relpath_join(parent_node->below_work->repos_relpath, @@ -1837,6 +1935,29 @@ write_entry(struct write_baton **entry_node, _("No copyfrom URL for '%s'"), svn_dirent_local_style(local_relpath, scratch_pool)); + + if (work && work->op_depth != working_node->op_depth + && work->repos_relpath + && work->repos_id == working_node->repos_id + && work->presence == svn_wc__db_status_normal + && !below_working_node) + { + /* Introduce a not-present node! */ + below_working_node = MAYBE_ALLOC(below_working_node, scratch_pool); + + below_working_node->wc_id = wc_id; + below_working_node->op_depth = work->op_depth; + below_working_node->local_relpath = local_relpath; + below_working_node->parent_relpath = parent_relpath; + + below_working_node->presence = svn_wc__db_status_not_present; + below_working_node->repos_id = repos_id; + below_working_node->repos_relpath = working_node->local_relpath; + + SVN_ERR(insert_node(sdb, below_working_node, scratch_pool)); + + below_working_node = NULL; /* Don't write a present intermediate! */ + } } if (entry->conflict_old) @@ -1892,7 +2013,7 @@ write_entry(struct write_baton **entry_node, scratch_pool); tree_conflicts = apr_hash_make(result_pool); skel = skel->children; - while(skel) + while (skel) { svn_wc_conflict_description2_t *conflict; svn_skel_t *new_skel; @@ -1909,11 +2030,6 @@ write_entry(struct write_baton **entry_node, WRITE_ENTRY_ASSERT(conflict->kind == svn_wc_conflict_kind_tree); - /* Fix dubious data stored by old clients, local adds don't have - a repository URL. */ - if (conflict->reason == svn_wc_conflict_reason_added) - conflict->src_left_version = NULL; - SVN_ERR(svn_wc__serialize_conflict(&new_skel, conflict, scratch_pool, scratch_pool)); @@ -2295,6 +2411,11 @@ write_entry(struct write_baton **entry_node, { working_node->op_depth = parent_node->work->op_depth; } + else if (working_node->presence == svn_wc__db_status_excluded + && parent_node->work) + { + working_node->op_depth = parent_node->work->op_depth; + } else if (!entry->copied) { working_node->op_depth @@ -2358,9 +2479,9 @@ write_actual_only_entries(apr_hash_t *tree_conflicts, actual_node = MAYBE_ALLOC(actual_node, scratch_pool); actual_node->wc_id = wc_id; - actual_node->local_relpath = svn__apr_hash_index_key(hi); + actual_node->local_relpath = apr_hash_this_key(hi); actual_node->parent_relpath = parent_relpath; - actual_node->tree_conflict_data = svn__apr_hash_index_val(hi); + actual_node->tree_conflict_data = apr_hash_this_val(hi); SVN_ERR(insert_actual_node(sdb, db, wri_abspath, actual_node, scratch_pool)); @@ -2418,8 +2539,8 @@ svn_wc__write_upgraded_entries(void **dir_baton, for (hi = apr_hash_first(scratch_pool, entries); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); - const svn_wc_entry_t *this_entry = svn__apr_hash_index_val(hi); + const char *name = apr_hash_this_key(hi); + const svn_wc_entry_t *this_entry = apr_hash_this_val(hi); const char *child_abspath, *child_relpath; svn_wc__text_base_info_t *text_base_info = svn_hash_gets(text_bases_info, name); @@ -2573,8 +2694,8 @@ walker_helper(const char *dirpath, /* Loop over each of the other entries. */ for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); - const svn_wc_entry_t *current_entry = svn__apr_hash_index_val(hi); + const char *name = apr_hash_this_key(hi); + const svn_wc_entry_t *current_entry = apr_hash_this_val(hi); const char *entrypath; const char *entry_abspath; svn_boolean_t hidden; @@ -2661,11 +2782,11 @@ svn_wc_walk_entries3(const char *path, svn_wc__db_t *db = svn_wc__adm_get_db(adm_access); svn_error_t *err; svn_node_kind_t kind; - svn_depth_t depth; + svn_wc__db_status_t status; SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); - err = svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, &depth, NULL, NULL, + err = svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -2684,7 +2805,9 @@ svn_wc_walk_entries3(const char *path, walk_baton, pool); } - if (kind == svn_node_file || depth == svn_depth_exclude) + if (kind == svn_node_file + || status == svn_wc__db_status_excluded + || status == svn_wc__db_status_server_excluded) { const svn_wc_entry_t *entry; @@ -2693,27 +2816,24 @@ svn_wc_walk_entries3(const char *path, ### we should not call handle_error for an error the *callback* ### gave us. let it deal with the problem before returning. */ - if (!show_hidden) + if (!show_hidden + && (status == svn_wc__db_status_not_present + || status == svn_wc__db_status_excluded + || status == svn_wc__db_status_server_excluded)) { - svn_boolean_t hidden; - SVN_ERR(svn_wc__db_node_hidden(&hidden, db, local_abspath, pool)); - - if (hidden) - { - /* The fool asked to walk a "hidden" node. Report the node as - unversioned. - - ### this is incorrect behavior. see depth_test 36. the walk - ### API will be revamped to avoid entry structures. we should - ### be able to solve the problem with the new API. (since we - ### shouldn't return a hidden entry here) */ - return walk_callbacks->handle_error( - path, svn_error_createf( - SVN_ERR_UNVERSIONED_RESOURCE, NULL, - _("'%s' is not under version control"), - svn_dirent_local_style(local_abspath, pool)), - walk_baton, pool); - } + /* The fool asked to walk a "hidden" node. Report the node as + unversioned. + + ### this is incorrect behavior. see depth_test 36. the walk + ### API will be revamped to avoid entry structures. we should + ### be able to solve the problem with the new API. (since we + ### shouldn't return a hidden entry here) */ + return walk_callbacks->handle_error( + path, svn_error_createf( + SVN_ERR_UNVERSIONED_RESOURCE, NULL, + _("'%s' is not under version control"), + svn_dirent_local_style(local_abspath, pool)), + walk_baton, pool); } SVN_ERR(svn_wc__get_entry(&entry, db, local_abspath, FALSE, |