#include "svn_client.h"
#include "svn_path.h"
#include "svn_pools.h"
#include "svn_time.h"
#include "svn_sorts.h"
#include "svn_props.h"
#include "client.h"
#include "svn_private_config.h"
static svn_error_t *
get_dir_contents(apr_uint32_t dirent_fields,
const char *dir,
svn_revnum_t rev,
svn_ra_session_t *ra_session,
apr_hash_t *locks,
const char *fs_path,
svn_depth_t depth,
svn_client_ctx_t *ctx,
svn_client_list_func_t list_func,
void *baton,
apr_pool_t *pool)
{
apr_hash_t *tmpdirents;
apr_pool_t *iterpool = svn_pool_create(pool);
apr_array_header_t *array;
svn_error_t *err;
int i;
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
err = svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
dir, rev, dirent_fields, pool);
if (err && ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) ||
(err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
{
svn_error_clear(err);
return SVN_NO_ERROR;
}
SVN_ERR(err);
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
array = svn_sort__hash(tmpdirents, svn_sort_compare_items_lexically, pool);
for (i = 0; i < array->nelts; ++i)
{
svn_sort__item_t *item = &APR_ARRAY_IDX(array, i, svn_sort__item_t);
const char *path;
svn_dirent_t *the_ent = apr_hash_get(tmpdirents, item->key, item->klen);
svn_lock_t *lock;
svn_pool_clear(iterpool);
path = svn_path_join(dir, item->key, iterpool);
if (locks)
{
const char *abs_path = svn_path_join(fs_path, path, iterpool);
lock = apr_hash_get(locks, abs_path, APR_HASH_KEY_STRING);
}
else
lock = NULL;
if (the_ent->kind == svn_node_file
|| depth == svn_depth_immediates
|| depth == svn_depth_infinity)
SVN_ERR(list_func(baton, path, the_ent, lock, fs_path, iterpool));
if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
SVN_ERR(get_dir_contents(dirent_fields, path, rev,
ra_session, locks, fs_path, depth, ctx,
list_func, baton, iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_list2(const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_depth_t depth,
apr_uint32_t dirent_fields,
svn_boolean_t fetch_locks,
svn_client_list_func_t list_func,
void *baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
svn_ra_session_t *ra_session;
svn_revnum_t rev;
svn_dirent_t *dirent;
const char *url;
const char *repos_root;
const char *fs_path;
svn_error_t *err;
apr_hash_t *locks;
dirent_fields |= SVN_DIRENT_KIND;
SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev,
&url, path_or_url, NULL,
peg_revision,
revision, ctx, pool));
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
SVN_ERR(svn_client__path_relative_to_root(&fs_path, url, repos_root,
TRUE, ra_session, NULL, pool));
err = svn_ra_stat(ra_session, "", rev, &dirent, pool);
if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
{
svn_node_kind_t kind;
svn_error_clear(err);
SVN_ERR(svn_ra_check_path(ra_session, "", rev, &kind, pool));
if (kind != svn_node_none)
{
if (strcmp(url, repos_root) != 0)
{
svn_ra_session_t *parent_session;
apr_hash_t *parent_ents;
const char *parent_url, *base_name;
svn_path_split(url, &parent_url, &base_name, pool);
base_name = svn_path_uri_decode(base_name, pool);
SVN_ERR(svn_client__open_ra_session_internal(&parent_session,
parent_url, NULL,
NULL, NULL, FALSE,
TRUE, ctx, pool));
SVN_ERR(svn_ra_get_dir2(parent_session, &parent_ents, NULL,
NULL, "", rev, dirent_fields, pool));
dirent = apr_hash_get(parent_ents, base_name,
APR_HASH_KEY_STRING);
}
else
{
dirent = apr_palloc(pool, sizeof(*dirent));
dirent->kind = kind;
dirent->size = 0;
if (dirent_fields & SVN_DIRENT_HAS_PROPS)
{
apr_hash_t *props;
SVN_ERR(svn_ra_get_dir2(ra_session, NULL, NULL, &props,
"", rev, 0 ,
pool));
dirent->has_props = (apr_hash_count(props) != 0);
}
dirent->created_rev = rev;
if (dirent_fields & (SVN_DIRENT_TIME | SVN_DIRENT_LAST_AUTHOR))
{
apr_hash_t *props;
svn_string_t *val;
SVN_ERR(svn_ra_rev_proplist(ra_session, rev, &props,
pool));
val = apr_hash_get(props, SVN_PROP_REVISION_DATE,
APR_HASH_KEY_STRING);
if (val)
SVN_ERR(svn_time_from_cstring(&dirent->time, val->data,
pool));
else
dirent->time = 0;
val = apr_hash_get(props, SVN_PROP_REVISION_AUTHOR,
APR_HASH_KEY_STRING);
dirent->last_author = val ? val->data : NULL;
}
}
}
else
dirent = NULL;
}
else if (err)
return err;
if (! dirent)
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
_("URL '%s' non-existent in that revision"),
url);
if (fetch_locks)
{
err = svn_ra_get_locks(ra_session, &locks, "", pool);
if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
{
svn_error_clear(err);
locks = NULL;
}
else if (err)
return err;
}
else
locks = NULL;
SVN_ERR(list_func(baton, "", dirent, locks
? (apr_hash_get(locks, fs_path,
APR_HASH_KEY_STRING))
: NULL, fs_path, pool));
if (dirent->kind == svn_node_dir
&& (depth == svn_depth_files
|| depth == svn_depth_immediates
|| depth == svn_depth_infinity))
SVN_ERR(get_dir_contents(dirent_fields, "", rev, ra_session, locks,
fs_path, depth, ctx, list_func, baton, pool));
return SVN_NO_ERROR;
}