static svn_error_t * test_access_baton_like_locking(apr_pool_t *pool) { svn_wc__db_t *db; svn_wc_context_t *wc_ctx, *wc_ctx2; const char *local_abspath; const char *D, *D1, *D2, *D3, *D4; svn_boolean_t locked_here, locked; svn_error_t *err; svn_wc_adm_access_t *adm_access, *subdir_access; #undef WC_NAME #define WC_NAME "test_access_batons" SVN_ERR(create_open(&db, &local_abspath, WC_NAME, pool)); D = svn_dirent_join(local_abspath, "DD", pool); D1 = svn_dirent_join(D, "DD", pool); D2 = svn_dirent_join(D1, "DD", pool); D3 = svn_dirent_join(D2, "DD", pool); D4 = svn_dirent_join(D3, "DD", pool); SVN_ERR(svn_io_make_dir_recursively(D4, pool)); /* Use the legacy interface */ SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, local_abspath, TRUE, 0, NULL, NULL, pool)); SVN_ERR(svn_wc_add3(D, adm_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, D, pool)); SVN_ERR(svn_wc_add3(D1, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, D1, pool)); SVN_ERR(svn_wc_add3(D2, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, D2, pool)); SVN_ERR(svn_wc_add3(D3, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add3(D4, subdir_access, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked(&locked, D3, pool)); SVN_TEST_ASSERT(locked); SVN_ERR(svn_wc_locked(&locked, D4, pool)); SVN_TEST_ASSERT(locked); SVN_ERR(svn_wc_delete3(D4, subdir_access, NULL, NULL, NULL, NULL, FALSE, pool)); SVN_ERR(svn_wc_locked(&locked, D4, pool)); SVN_TEST_ASSERT(!locked); SVN_ERR(svn_wc_revert3(D, adm_access, svn_depth_infinity, FALSE, NULL, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked(&locked, D3, pool)); SVN_TEST_ASSERT(!locked); SVN_ERR(svn_wc_locked(&locked, local_abspath, pool)); SVN_TEST_ASSERT(locked); SVN_ERR(svn_wc_adm_close2(adm_access, pool)); SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool)); /* Obtain a lock for the root, which is extended on each level */ SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, local_abspath, 0, FALSE, pool)); SVN_ERR(svn_io_make_dir_recursively(D4, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D1, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D2, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_add4(wc_ctx, D3, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D3, pool)); SVN_TEST_ASSERT(locked_here && locked); /* Test if the not added path is already locked */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D4, pool)); SVN_TEST_ASSERT(!locked_here && !locked); SVN_ERR(svn_wc_add4(wc_ctx, D4, svn_depth_infinity, NULL, SVN_INVALID_REVNUM, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D4, pool)); SVN_TEST_ASSERT(locked_here && locked); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, local_abspath, pool)); /* Should be unlocked */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, local_abspath, pool)); SVN_TEST_ASSERT(!locked_here && !locked); /* Lock shouldn't be released */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx, D, pool)); SVN_TEST_ASSERT(locked_here && locked); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D1, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D2, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D3, pool)); /* Try reobtaining lock on D3; should succeed */ SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, D3, 0, FALSE, pool)); SVN_ERR(svn_wc__db_wclock_release(wc_ctx->db, D4, pool)); /* D3 should still be locked; try stealing in a different context */ SVN_ERR(svn_wc_context_create(&wc_ctx2, NULL, pool, pool)); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx2, D3, pool)); SVN_TEST_ASSERT(!locked_here && locked); err = svn_wc__db_wclock_obtain(wc_ctx2->db, D3, 0, FALSE, pool); if (err && err->apr_err != SVN_ERR_WC_LOCKED) return svn_error_trace(err); svn_error_clear(err); SVN_TEST_ASSERT(err != NULL); /* Can't lock, as it is still locked */ err = svn_wc__db_wclock_release(wc_ctx2->db, D4, pool); if (err && err->apr_err != SVN_ERR_WC_NOT_LOCKED) return svn_error_trace(err); svn_error_clear(err); SVN_TEST_ASSERT(err != NULL); /* Can't unlock, as it is not ours */ /* Now steal the lock */ SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx2->db, D3, 0, TRUE, pool)); /* We should own the lock now */ SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx2, D3, pool)); SVN_TEST_ASSERT(locked_here && locked); err = svn_wc__db_wclock_release(wc_ctx2->db, D4, pool); if (err && err->apr_err != SVN_ERR_WC_NOT_LOCKED) return svn_error_trace(err); svn_error_clear(err); SVN_TEST_ASSERT(err != NULL); /* Can't unlock a not locked path */ /* Now create a separate working copy from the same repository directly below this WC and test if our code really sees it as a separate wc, for locking and normal operation */ { const char *url, *repos_root_url, *repos_uuid; const char *subdir = svn_dirent_join(local_abspath, "sub-wc", pool); svn_boolean_t is_root; SVN_ERR(svn_wc__node_get_url(&url, wc_ctx, local_abspath, pool, pool)); SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, &repos_uuid, wc_ctx, local_abspath, pool, pool)); SVN_ERR(svn_io_make_dir_recursively(subdir, pool)); SVN_ERR(svn_wc_ensure_adm3(subdir, repos_uuid, svn_path_url_add_component2(url, "sub-wc", pool), repos_root_url, 0, svn_depth_infinity, pool)); SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL, wc_ctx->db, subdir, pool)); SVN_TEST_ASSERT(is_root); SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL, wc_ctx2->db, subdir, pool)); /* This test was added to show a regression where the next check failed, but the check above this succeeded */ SVN_TEST_ASSERT(is_root); SVN_ERR(svn_wc_locked2(&locked_here, &locked, wc_ctx2, subdir, pool)); SVN_TEST_ASSERT(!locked_here && !locked); } 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; }