static svn_error_t * test_entries_alloc(apr_pool_t *pool) { svn_wc__db_t *db; const char *local_abspath; svn_wc_adm_access_t *adm_access; apr_hash_t *entries; const svn_wc_entry_t *entry; const char *local_relpath; #undef WC_NAME #define WC_NAME "test_entries_alloc" SVN_ERR(create_open(&db, &local_abspath, WC_NAME, pool)); SVN_ERR(svn_wc_adm_open3(&adm_access, NULL /* associated */, svn_dirent_join("fake-wc", WC_NAME, pool), FALSE /* write_lock */, 0 /* levels_to_lock */, NULL /* cancel_func */, NULL /* cancel_baton */, pool)); SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE /* show_hidden */, pool)); /* The wcroot has 12 BASE children + 1 WORKING child + "this dir". */ SVN_TEST_ASSERT(apr_hash_count(entries) == 14); /* The "D" entry in the entries hash should be what we get from the svn_wc_entry() entrypoint. */ local_relpath = svn_dirent_join_many(pool, "fake-wc", WC_NAME, "D", NULL); SVN_ERR(svn_wc_entry(&entry, local_relpath, adm_access, TRUE, pool)); SVN_TEST_ASSERT(entry == apr_hash_get(entries, "D", APR_HASH_KEY_STRING)); /* This entry should be missing. */ SVN_ERR(svn_wc_entry(&entry, "missing", adm_access, TRUE, pool)); SVN_TEST_ASSERT(entry == NULL); return SVN_NO_ERROR; }
static svn_error_t * test_stubs(apr_pool_t *pool) { svn_wc__db_t *db; const char *local_abspath; const char *local_relpath; svn_wc_adm_access_t *adm_access; svn_wc_adm_access_t *subdir_access; const svn_wc_entry_t *stub_entry; const svn_wc_entry_t *entry; const svn_wc_entry_t *test_entry; apr_hash_t *entries; #undef WC_NAME #define WC_NAME "test_stubs" SVN_ERR(create_open(&db, &local_abspath, WC_NAME, pool)); /* The "M" entry is a subdir. Let's ensure we can reach its stub, and the actual contents. */ local_relpath = svn_dirent_join_many(pool, "fake-wc", WC_NAME, "M", NULL); SVN_ERR(svn_wc_adm_open3(&adm_access, NULL /* associated */, svn_dirent_join("fake-wc", WC_NAME, pool), FALSE /* write_lock */, 0 /* levels_to_lock */, NULL /* cancel_func */, NULL /* cancel_baton */, pool)); /* Ensure we get the stub. NOTE: do this before we have associated the subdir baton with ADM_ACCESS. */ SVN_ERR(svn_wc_entry(&stub_entry, local_relpath, adm_access, TRUE, pool)); SVN_TEST_STRING_ASSERT(stub_entry->name, "M"); SVN_ERR(svn_wc_adm_open3(&subdir_access, adm_access, local_relpath, FALSE /* write_lock */, 0 /* levels_to_lock */, NULL /* cancel_func */, NULL /* cancel_baton */, pool)); /* Ensure we get the real entry. */ SVN_ERR(svn_wc_entry(&entry, local_relpath, subdir_access, TRUE, pool)); SVN_TEST_STRING_ASSERT(entry->name, ""); /* Ensure that we get the SAME entry, even using the parent baton. */ SVN_ERR(svn_wc_entry(&test_entry, local_relpath, adm_access, TRUE, pool)); SVN_TEST_ASSERT(test_entry == entry); /* Ensure we get the stub when reading entries with ADM_ACCESS. */ SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE /* show_hidden */, pool)); SVN_TEST_ASSERT(stub_entry == apr_hash_get(entries, "M", APR_HASH_KEY_STRING)); /* Ensure we get the real entry when reading entries with SUBDIR_ACCESS. */ SVN_ERR(svn_wc_entries_read(&entries, subdir_access, TRUE /* show_hidden */, pool)); SVN_TEST_ASSERT(entry == apr_hash_get(entries, "", APR_HASH_KEY_STRING)); return SVN_NO_ERROR; }
static svn_error_t * entries_dump(const char *dir_path, svn_wc_adm_access_t *related, apr_pool_t *pool) { svn_wc_adm_access_t *adm_access = NULL; apr_hash_t *entries; apr_hash_index_t *hi; svn_boolean_t locked; svn_error_t *err; svn_wc_context_t *wc_ctx = NULL; const char *dir_abspath; err = svn_wc_adm_open3(&adm_access, related, dir_path, FALSE, 0, NULL, NULL, pool); if (!err) { SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, svn_wc__adm_get_db(adm_access), pool)); SVN_ERR(svn_dirent_get_absolute(&dir_abspath, dir_path, pool)); SVN_ERR(svn_wc_locked2(NULL, &locked, wc_ctx, dir_abspath, pool)); SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool)); } else if (err && err->apr_err == SVN_ERR_WC_LOCKED && related && ! strcmp(dir_path, svn_wc_adm_access_path(related))) { /* Common caller error: Can't open a baton when there is one. */ svn_error_clear(err); SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, svn_wc__adm_get_db(related), pool)); SVN_ERR(svn_dirent_get_absolute(&dir_abspath, dir_path, pool)); SVN_ERR(svn_wc_locked2(NULL, &locked, wc_ctx, dir_abspath, pool)); SVN_ERR(svn_wc_entries_read(&entries, related, TRUE, pool)); } else { const char *lockfile_path; svn_node_kind_t kind; /* ### Should svn_wc_adm_open3 be returning UPGRADE_REQUIRED? */ if (err->apr_err != SVN_ERR_WC_NOT_DIRECTORY) return err; svn_error_clear(err); adm_access = NULL; SVN_ERR(svn_dirent_get_absolute(&dir_abspath, dir_path, pool)); SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath, pool, pool)); lockfile_path = svn_dirent_join_many(pool, dir_path, svn_wc_get_adm_dir(pool), "lock", SVN_VA_NULL); SVN_ERR(svn_io_check_path(lockfile_path, &kind, pool)); locked = (kind == svn_node_file); } for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const char *key = apr_hash_this_key(hi); const svn_wc_entry_t *entry = apr_hash_this_val(hi); SVN_ERR_ASSERT(strcmp(key, entry->name) == 0); printf("e = Entry()\n"); str_value("name", entry->name); int_value("revision", entry->revision); str_value("url", entry->url); str_value("repos", entry->repos); str_value("uuid", entry->uuid); int_value("kind", entry->kind); int_value("schedule", entry->schedule); bool_value("copied", entry->copied); bool_value("deleted", entry->deleted); bool_value("absent", entry->absent); bool_value("incomplete", entry->incomplete); str_value("copyfrom_url", entry->copyfrom_url); int_value("copyfrom_rev", entry->copyfrom_rev); str_value("conflict_old", entry->conflict_old); str_value("conflict_new", entry->conflict_new); str_value("conflict_wrk", entry->conflict_wrk); str_value("prejfile", entry->prejfile); /* skip: text_time */ /* skip: prop_time */ /* skip: checksum */ int_value("cmt_rev", entry->cmt_rev); /* skip: cmt_date */ str_value("cmt_author", entry->cmt_author); str_value("lock_token", entry->lock_token); str_value("lock_owner", entry->lock_owner); str_value("lock_comment", entry->lock_comment); /* skip: lock_creation_date */ /* skip: has_props */ /* skip: has_prop_mods */ /* skip: cachable_props */ /* skip: present_props */ str_value("changelist", entry->changelist); /* skip: working_size */ /* skip: keep_local */ int_value("depth", entry->depth); /* skip: tree_conflict_data */ bool_value("file_external", entry->file_external_path != NULL); /* skip: file_external_peg_rev */ /* skip: file_external_rev */ bool_value("locked", locked && *entry->name == '\0'); printf("entries['%s'] = e\n", (const char *)key); } if (wc_ctx) SVN_ERR(svn_wc_context_destroy(wc_ctx)); if (adm_access) SVN_ERR(svn_wc_adm_close2(adm_access, pool)); return SVN_NO_ERROR; }
svn_error_t * svn_wc_relocate3(const char *path, svn_wc_adm_access_t *adm_access, const char *from, const char *to, svn_boolean_t recurse, svn_wc_relocation_validator3_t validator, void *validator_baton, apr_pool_t *pool) { apr_hash_t *entries; apr_hash_index_t *hi; const svn_wc_entry_t *entry; apr_pool_t *subpool; SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, pool)); if (! entry) return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, NULL, NULL); if (entry->kind == svn_node_file || entry->depth == svn_depth_exclude) return relocate_entry(adm_access, entry, from, to, validator, validator_baton, TRUE /* sync */, pool); /* Relocate THIS_DIR first, in order to pre-validate the relocated URL of all of the other entries. This is technically cheating because it relies on knowledge of the libsvn_client implementation, but it significantly cuts down on the number of expensive validations the validator has to do. ### Should svn_wc.h document the ordering? */ SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool)); entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING); SVN_ERR(relocate_entry(adm_access, entry, from, to, validator, validator_baton, FALSE, pool)); subpool = svn_pool_create(pool); for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const void *key; void *val; apr_hash_this(hi, &key, NULL, &val); entry = val; if (strcmp(key, SVN_WC_ENTRY_THIS_DIR) == 0) continue; svn_pool_clear(subpool); if (recurse && (entry->kind == svn_node_dir) && (! entry->deleted || (entry->schedule == svn_wc_schedule_add)) && ! entry->absent && (entry->depth != svn_depth_exclude)) { svn_wc_adm_access_t *subdir_access; const char *subdir = svn_path_join(path, key, subpool); if (svn_wc__adm_missing(adm_access, subdir)) continue; SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir, subpool)); SVN_ERR(svn_wc_relocate3(subdir, subdir_access, from, to, recurse, validator, validator_baton, subpool)); } SVN_ERR(relocate_entry(adm_access, entry, from, to, validator, validator_baton, FALSE, subpool)); } svn_pool_destroy(subpool); SVN_ERR(svn_wc__props_delete(path, svn_wc__props_wcprop, adm_access, pool)); return svn_wc__entries_write(entries, adm_access, pool); }