/* Helper for the remote case of svn_client_proplist. * * Push a new 'svn_client_proplist_item_t *' item onto PROPLIST, * containing the properties for "TARGET_PREFIX/TARGET_RELATIVE" in * REVNUM, obtained using RA_LIB and SESSION. The item->node_name * will be "TARGET_PREFIX/TARGET_RELATIVE", and the value will be a * hash mapping 'const char *' property names onto 'svn_string_t *' * property values. * * Allocate the new item and its contents in POOL. * Do all looping, recursion, and temporary work in SCRATCHPOOL. * * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE". * * If the target is a directory, only fetch properties for the files * and directories at depth DEPTH. */ static svn_error_t * remote_proplist(const char *target_prefix, const char *target_relative, svn_node_kind_t kind, svn_revnum_t revnum, svn_ra_session_t *ra_session, svn_depth_t depth, svn_proplist_receiver_t receiver, void *receiver_baton, apr_pool_t *pool, apr_pool_t *scratchpool) { apr_hash_t *dirents; apr_hash_t *prop_hash, *final_hash; apr_hash_index_t *hi; const char *target_full_url = svn_path_url_add_component2(target_prefix, target_relative, scratchpool); if (kind == svn_node_dir) { SVN_ERR(svn_ra_get_dir2(ra_session, (depth > svn_depth_empty) ? &dirents : NULL, NULL, &prop_hash, target_relative, revnum, SVN_DIRENT_KIND, scratchpool)); } else if (kind == svn_node_file) { SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum, NULL, NULL, &prop_hash, scratchpool)); } else { return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown node kind for '%s'"), target_full_url); } /* Filter out non-regular properties, since the RA layer returns all kinds. Copy regular properties keys/vals from the prop_hash allocated in SCRATCHPOOL to the "final" hash allocated in POOL. */ final_hash = apr_hash_make(pool); for (hi = apr_hash_first(scratchpool, prop_hash); hi; hi = apr_hash_next(hi)) { const char *name = svn__apr_hash_index_key(hi); apr_ssize_t klen = svn__apr_hash_index_klen(hi); svn_string_t *value = svn__apr_hash_index_val(hi); svn_prop_kind_t prop_kind; prop_kind = svn_property_kind(NULL, name); if (prop_kind == svn_prop_regular_kind) { name = apr_pstrdup(pool, name); value = svn_string_dup(value, pool); apr_hash_set(final_hash, name, klen, value); } } SVN_ERR(call_receiver(target_full_url, final_hash, receiver, receiver_baton, pool)); if (depth > svn_depth_empty && (kind == svn_node_dir) && (apr_hash_count(dirents) > 0)) { apr_pool_t *subpool = svn_pool_create(scratchpool); for (hi = apr_hash_first(scratchpool, dirents); hi; hi = apr_hash_next(hi)) { const char *this_name = svn__apr_hash_index_key(hi); svn_dirent_t *this_ent = svn__apr_hash_index_val(hi); const char *new_target_relative; svn_pool_clear(subpool); new_target_relative = svn_relpath_join(target_relative, this_name, subpool); if (this_ent->kind == svn_node_file || depth > svn_depth_files) { svn_depth_t depth_below_here = depth; if (depth == svn_depth_immediates) depth_below_here = svn_depth_empty; SVN_ERR(remote_proplist(target_prefix, new_target_relative, this_ent->kind, revnum, ra_session, depth_below_here, receiver, receiver_baton, pool, subpool)); } } svn_pool_destroy(subpool); } return SVN_NO_ERROR; }
svn_error_t * svn_client__handle_externals(apr_hash_t *externals_new, apr_hash_t *ambient_depths, const char *repos_root_url, const char *target_abspath, svn_depth_t requested_depth, svn_boolean_t *timestamp_sleep, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { apr_hash_t *old_external_defs; apr_hash_index_t *hi; apr_pool_t *iterpool; SVN_ERR_ASSERT(repos_root_url); iterpool = svn_pool_create(scratch_pool); SVN_ERR(svn_wc__externals_defined_below(&old_external_defs, ctx->wc_ctx, target_abspath, scratch_pool, iterpool)); for (hi = apr_hash_first(scratch_pool, externals_new); hi; hi = apr_hash_next(hi)) { const char *local_abspath = svn__apr_hash_index_key(hi); const char *desc_text = svn__apr_hash_index_val(hi); svn_depth_t ambient_depth = svn_depth_infinity; svn_pool_clear(iterpool); if (ambient_depths) { const char *ambient_depth_w; ambient_depth_w = apr_hash_get(ambient_depths, local_abspath, svn__apr_hash_index_klen(hi)); if (ambient_depth_w == NULL) { return svn_error_createf( SVN_ERR_WC_CORRUPT, NULL, _("Traversal of '%s' found no ambient depth"), svn_dirent_local_style(local_abspath, scratch_pool)); } else { ambient_depth = svn_depth_from_word(ambient_depth_w); } } SVN_ERR(handle_externals_change(ctx, repos_root_url, timestamp_sleep, local_abspath, desc_text, old_external_defs, ambient_depth, requested_depth, iterpool)); } /* Remove the remaining externals */ for (hi = apr_hash_first(scratch_pool, old_external_defs); hi; hi = apr_hash_next(hi)) { const char *item_abspath = svn__apr_hash_index_key(hi); const char *defining_abspath = svn__apr_hash_index_val(hi); const char *parent_abspath; svn_pool_clear(iterpool); SVN_ERR(wrap_external_error( ctx, item_abspath, handle_external_item_removal(ctx, defining_abspath, item_abspath, iterpool), iterpool)); /* Are there any unversioned directories between the removed * external and the DEFINING_ABSPATH which we can remove? */ parent_abspath = item_abspath; do { svn_node_kind_t kind; parent_abspath = svn_dirent_dirname(parent_abspath, iterpool); SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, parent_abspath, FALSE /* show_deleted*/, FALSE /* show_hidden */, iterpool)); if (kind == svn_node_none) { svn_error_t *err; err = svn_io_dir_remove_nonrecursive(parent_abspath, iterpool); if (err) { if (APR_STATUS_IS_ENOTEMPTY(err->apr_err)) { svn_error_clear(err); break; /* No parents to delete */ } else if (APR_STATUS_IS_ENOENT(err->apr_err) || APR_STATUS_IS_ENOTDIR(err->apr_err)) { svn_error_clear(err); /* Fall through; parent dir might be unversioned */ } else return svn_error_trace(err); } } } while (strcmp(parent_abspath, defining_abspath) != 0); } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* Write to DIGEST_PATH a representation of CHILDREN (which may be empty, if the versioned path in FS represented by DIGEST_PATH has no children) and LOCK (which may be NULL if that versioned path is lock itself locked). Set the permissions of DIGEST_PATH to those of PERMS_REFERENCE. Use POOL for all allocations. */ static svn_error_t * write_digest_file(apr_hash_t *children, svn_lock_t *lock, const char *fs_path, const char *digest_path, const char *perms_reference, apr_pool_t *pool) { svn_error_t *err = SVN_NO_ERROR; svn_stream_t *stream; apr_hash_index_t *hi; apr_hash_t *hash = apr_hash_make(pool); const char *tmp_path; SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs_path, PATH_LOCKS_DIR, pool), fs_path, pool)); SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_dirname(digest_path, pool), fs_path, pool)); if (lock) { const char *creation_date = NULL, *expiration_date = NULL; if (lock->creation_date) creation_date = svn_time_to_cstring(lock->creation_date, pool); if (lock->expiration_date) expiration_date = svn_time_to_cstring(lock->expiration_date, pool); hash_store(hash, PATH_KEY, sizeof(PATH_KEY)-1, lock->path, APR_HASH_KEY_STRING, pool); hash_store(hash, TOKEN_KEY, sizeof(TOKEN_KEY)-1, lock->token, APR_HASH_KEY_STRING, pool); hash_store(hash, OWNER_KEY, sizeof(OWNER_KEY)-1, lock->owner, APR_HASH_KEY_STRING, pool); hash_store(hash, COMMENT_KEY, sizeof(COMMENT_KEY)-1, lock->comment, APR_HASH_KEY_STRING, pool); hash_store(hash, IS_DAV_COMMENT_KEY, sizeof(IS_DAV_COMMENT_KEY)-1, lock->is_dav_comment ? "1" : "0", 1, pool); hash_store(hash, CREATION_DATE_KEY, sizeof(CREATION_DATE_KEY)-1, creation_date, APR_HASH_KEY_STRING, pool); hash_store(hash, EXPIRATION_DATE_KEY, sizeof(EXPIRATION_DATE_KEY)-1, expiration_date, APR_HASH_KEY_STRING, pool); } if (apr_hash_count(children)) { svn_stringbuf_t *children_list = svn_stringbuf_create("", pool); for (hi = apr_hash_first(pool, children); hi; hi = apr_hash_next(hi)) { svn_stringbuf_appendbytes(children_list, svn__apr_hash_index_key(hi), svn__apr_hash_index_klen(hi)); svn_stringbuf_appendbyte(children_list, '\n'); } hash_store(hash, CHILDREN_KEY, sizeof(CHILDREN_KEY)-1, children_list->data, children_list->len, pool); } SVN_ERR(svn_stream_open_unique(&stream, &tmp_path, svn_dirent_dirname(digest_path, pool), svn_io_file_del_none, pool, pool)); if ((err = svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool))) { svn_error_clear(svn_stream_close(stream)); return svn_error_createf(err->apr_err, err, _("Cannot write lock/entries hashfile '%s'"), svn_dirent_local_style(tmp_path, pool)); } SVN_ERR(svn_stream_close(stream)); SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool)); SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, pool)); return SVN_NO_ERROR; }