static const char * simple_extend(const char *adm_path, /* ### adm_abspath? */ svn_boolean_t use_tmp, const char *subdir, const char *child, const char *extension, apr_pool_t *result_pool) { if (subdir) child = svn_dirent_join(subdir, child, result_pool); if (extension) child = apr_pstrcat(result_pool, child, extension, (char *)NULL); if (use_tmp) return svn_dirent_join_many(result_pool, adm_path, adm_dir_name, SVN_WC__ADM_TMP, child, NULL); return svn_dirent_join_many(result_pool, adm_path, adm_dir_name, child, NULL); }
/* Return the path of the lock/entries file for which DIGEST is the hashed repository relative path. */ static const char * digest_path_from_digest(const char *fs_path, const char *digest, apr_pool_t *pool) { return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR, apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN), digest, NULL); }
/* Return the absolute path to the temporary directory for pristine text files within WCROOT. */ static char * pristine_get_tempdir(svn_wc__db_wcroot_t *wcroot, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { return svn_dirent_join_many(result_pool, wcroot->abspath, svn_wc_get_adm_dir(scratch_pool), PRISTINE_TEMPDIR_RELPATH, SVN_VA_NULL); }
/* Returns in PRISTINE_ABSPATH a new string allocated from RESULT_POOL, holding the local absolute path to the file location that is dedicated to hold CHECKSUM's pristine file, relating to the pristine store configured for the working copy indicated by PDH. The returned path does not necessarily currently exist. Any other allocations are made in SCRATCH_POOL. */ static svn_error_t * get_pristine_fname(const char **pristine_abspath, const char *wcroot_abspath, const svn_checksum_t *sha1_checksum, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *base_dir_abspath; const char *hexdigest = svn_checksum_to_cstring(sha1_checksum, scratch_pool); char subdir[3]; /* ### code is in transition. make sure we have the proper data. */ SVN_ERR_ASSERT(pristine_abspath != NULL); SVN_ERR_ASSERT(svn_dirent_is_absolute(wcroot_abspath)); SVN_ERR_ASSERT(sha1_checksum != NULL); SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); base_dir_abspath = svn_dirent_join_many(scratch_pool, wcroot_abspath, svn_wc_get_adm_dir(scratch_pool), PRISTINE_STORAGE_RELPATH, SVN_VA_NULL); /* We should have a valid checksum and (thus) a valid digest. */ SVN_ERR_ASSERT(hexdigest != NULL); /* Get the first two characters of the digest, for the subdir. */ subdir[0] = hexdigest[0]; subdir[1] = hexdigest[1]; subdir[2] = '\0'; hexdigest = apr_pstrcat(scratch_pool, hexdigest, PRISTINE_STORAGE_EXT, SVN_VA_NULL); /* The file is located at DIR/.svn/pristine/XX/XXYYZZ...svn-base */ *pristine_abspath = svn_dirent_join_many(result_pool, base_dir_abspath, subdir, hexdigest, SVN_VA_NULL); return SVN_NO_ERROR; }
static svn_error_t * recover_fully_packed(const svn_test_opts_t *opts, apr_pool_t *pool) { apr_pool_t *subpool; svn_fs_t *fs; svn_fs_txn_t *txn; svn_fs_root_t *txn_root; const char *conflict; svn_revnum_t after_rev; svn_error_t *err; /* Bail (with success) on known-untestable scenarios */ if ((strcmp(opts->fs_type, "fsfs") != 0) || (opts->server_minor_version && (opts->server_minor_version < 7))) return SVN_NO_ERROR; /* Create a packed FS for which every revision will live in a pack digest file, and then recover it. */ SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool)); SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool)); /* Add another revision, re-pack, re-recover. */ subpool = svn_pool_create(pool); SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, subpool)); SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool)); SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool)); SVN_ERR(svn_test__set_file_contents(txn_root, "A/mu", "new-mu", subpool)); SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool)); SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev)); svn_pool_destroy(subpool); SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool)); SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool)); /* Now, delete the youngest revprop file, and recover again. This time we want to see an error! */ SVN_ERR(svn_io_remove_file2( svn_dirent_join_many(pool, REPO_NAME, PATH_REVPROPS_DIR, apr_psprintf(pool, "%ld/%ld", after_rev / SHARD_SIZE, after_rev), NULL), FALSE, pool)); err = svn_fs_recover(REPO_NAME, NULL, NULL, pool); if (! err) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Expected SVN_ERR_FS_CORRUPT error; got none"); if (err->apr_err != SVN_ERR_FS_CORRUPT) return svn_error_create(SVN_ERR_TEST_FAILED, err, "Expected SVN_ERR_FS_CORRUPT error; got:"); svn_error_clear(err); return SVN_NO_ERROR; }
/* Set *DIGEST_PATH to the path to the lock/entries digest file associate with PATH, where PATH is the path to the lock file or lock entries file in FS. */ static svn_error_t * digest_path_from_path(const char **digest_path, const char *fs_path, const char *path, apr_pool_t *pool) { const char *digest; SVN_ERR(make_digest(&digest, path, pool)); *digest_path = svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR, apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN), digest, NULL); return SVN_NO_ERROR; }
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 * pack_even_filesystem(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_node_kind_t kind; const char *path; /* Bail (with success) on known-untestable scenarios */ if ((strcmp(opts->fs_type, "fsfs") != 0) || (opts->server_minor_version && (opts->server_minor_version < 6))) return SVN_NO_ERROR; SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool)); path = svn_dirent_join_many(pool, REPO_NAME, "revs", "2.pack", NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_dir) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Packing did not complete as expected"); 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; }
static svn_error_t * pack_filesystem(const svn_test_opts_t *opts, apr_pool_t *pool) { int i; svn_node_kind_t kind; const char *path; char buf[80]; apr_file_t *file; apr_size_t len; /* Bail (with success) on known-untestable scenarios */ if ((strcmp(opts->fs_type, "fsfs") != 0) || (opts->server_minor_version && (opts->server_minor_version < 6))) return SVN_NO_ERROR; SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool)); /* Check to see that the pack files exist, and that the rev directories don't. */ for (i = 0; i < (MAX_REV + 1) / SHARD_SIZE; i++) { path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d.pack", i / SHARD_SIZE), "pack", NULL); /* These files should exist. */ SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_file) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Expected pack file '%s' not found", path); path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d.pack", i / SHARD_SIZE), "manifest", NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_file) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Expected manifest file '%s' not found", path); /* This directory should not exist. */ path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d", i / SHARD_SIZE), NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_none) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Unexpected directory '%s' found", path); } /* Ensure the min-unpacked-rev jives with the above operations. */ SVN_ERR(svn_io_file_open(&file, svn_dirent_join(REPO_NAME, PATH_MIN_UNPACKED_REV, pool), APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool)); len = sizeof(buf); SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); SVN_ERR(svn_io_file_close(file, pool)); if (SVN_STR_TO_REV(buf) != (MAX_REV / SHARD_SIZE) * SHARD_SIZE) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Bad '%s' contents", PATH_MIN_UNPACKED_REV); /* Finally, make sure the final revision directory does exist. */ path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d", (i / SHARD_SIZE) + 1), NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_none) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Expected directory '%s' not found", path); return SVN_NO_ERROR; }