220
227
apr_pool_t *pool)
222
229
reporter_baton_t *rbaton = reporter_baton;
223
const char *fs_path = NULL;
224
230
const char *repos_url = rbaton->sess->repos_url;
231
const char *relpath = svn_uri_skip_ancestor(repos_url, url, pool);
226
if (!svn_uri__is_ancestor(repos_url, url))
227
235
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
229
237
"is not the same repository as\n"
230
238
"'%s'"), url, rbaton->sess->repos_url);
232
/* Skip the repos_url, but keep the last '/' to create an fspath */
233
fs_path = svn_uri_skip_ancestor(repos_url, url, pool);
234
if (fs_path[0] == '\0')
240
/* Convert the relpath to an fspath */
241
if (relpath[0] == '\0')
237
fs_path = apr_pstrcat(pool, "/", fs_path, (char *)NULL);
244
fs_path = apr_pstrcat(pool, "/", relpath, (char *)NULL);
239
246
return svn_repos_link_path3(rbaton->report_baton, path, fs_path, revision,
240
247
depth, start_empty, lock_token, pool);
291
310
/* Get the HEAD revision if one is not supplied. */
292
311
if (! SVN_IS_VALID_REVNUM(revision))
293
SVN_ERR(svn_fs_youngest_rev(&revision, sess->fs, pool));
312
SVN_ERR(svn_fs_youngest_rev(&revision, sess->fs, scratch_pool));
295
314
/* If OTHER_URL was provided, validate it and convert it into a
296
315
regular filesystem path. */
299
318
const char *other_relpath
300
= svn_uri_skip_ancestor(sess->repos_url, other_url, pool);
319
= svn_uri_skip_ancestor(sess->repos_url, other_url, scratch_pool);
302
321
/* Sanity check: the other_url better be in the same repository as
303
322
the original session url! */
308
327
"is not the same repository as\n"
309
328
"'%s'"), other_url, sess->repos_url);
311
other_fs_path = apr_pstrcat(pool, "/", other_relpath, (char *)NULL);
330
other_fs_path = apr_pstrcat(scratch_pool, "/", other_relpath,
314
334
/* Pass back our reporter */
315
335
*reporter = &ra_local_reporter;
317
SVN_ERR(get_username(session, pool));
337
SVN_ERR(get_username(session, scratch_pool));
319
339
if (sess->callbacks)
320
340
SVN_ERR(svn_delta_get_cancellation_editor(sess->callbacks->cancel_func,
371
394
BATON is 'struct deltify_etc_baton *'. */
372
395
static svn_error_t *
373
396
deltify_etc(const svn_commit_info_t *commit_info,
374
void *baton, apr_pool_t *pool)
398
apr_pool_t *scratch_pool)
376
struct deltify_etc_baton *db = baton;
400
struct deltify_etc_baton *deb = baton;
377
401
svn_error_t *err1 = SVN_NO_ERROR;
378
402
svn_error_t *err2;
379
apr_hash_index_t *hi;
380
apr_pool_t *iterpool;
382
404
/* Invoke the original callback first, in case someone's waiting to
383
405
know the revision number so they can go off and annotate an
384
406
issue or something. */
386
err1 = db->callback(commit_info, db->callback_baton, pool);
408
err1 = deb->commit_cb(commit_info, deb->commit_baton, scratch_pool);
388
410
/* Maybe unlock the paths. */
411
if (deb->lock_tokens)
391
iterpool = svn_pool_create(db->pool);
392
for (hi = apr_hash_first(db->pool, db->lock_tokens); hi;
413
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
414
apr_hash_index_t *hi;
416
for (hi = apr_hash_first(scratch_pool, deb->lock_tokens); hi;
393
417
hi = apr_hash_next(hi))
395
const void *rel_path;
397
const char *abs_path, *token;
419
const void *relpath = svn__apr_hash_index_key(hi);
420
const char *token = svn__apr_hash_index_val(hi);
399
423
svn_pool_clear(iterpool);
400
apr_hash_this(hi, &rel_path, NULL, &val);
402
abs_path = svn_fspath__join(db->fs_path, rel_path, iterpool);
425
fspath = svn_fspath__join(deb->fspath_base, relpath, iterpool);
403
427
/* We may get errors here if the lock was broken or stolen
404
428
after the commit succeeded. This is fine and should be
406
svn_error_clear(svn_repos_fs_unlock(db->repos, abs_path, token,
430
svn_error_clear(svn_repos_fs_unlock(deb->repos, fspath, token,
407
431
FALSE, iterpool));
409
434
svn_pool_destroy(iterpool);
412
437
/* But, deltification shouldn't be stopped just because someone's
413
438
random callback failed, so proceed unconditionally on to
414
439
deltification. */
415
err2 = svn_fs_deltify_revision(db->fs, commit_info->revision, db->pool);
417
/* It's more interesting if the original callback failed, so let
418
that one dominate. */
440
err2 = svn_fs_deltify_revision(deb->fs, commit_info->revision, scratch_pool);
442
return svn_error_compose_create(err1, err2);
446
/* If LOCK_TOKENS is not NULL, then copy all tokens into the access context
447
of FS. The tokens' paths will be prepended with FSPATH_BASE.
449
ACCESS_POOL must match (or exceed) the lifetime of the access context
450
that was associated with FS. Typically, this is the session pool.
452
Temporary allocations are made in SCRATCH_POOL. */
454
apply_lock_tokens(svn_fs_t *fs,
455
const char *fspath_base,
456
apr_hash_t *lock_tokens,
457
apr_pool_t *access_pool,
458
apr_pool_t *scratch_pool)
421
svn_error_clear(err2);
462
svn_fs_access_t *access_ctx;
464
SVN_ERR(svn_fs_get_access(&access_ctx, fs));
466
/* If there is no access context, the filesystem will scream if a
470
apr_hash_index_t *hi;
472
/* Note: we have no use for an iterpool here since the data
473
within the loop is copied into ACCESS_POOL. */
475
for (hi = apr_hash_first(scratch_pool, lock_tokens); hi;
476
hi = apr_hash_next(hi))
478
const void *relpath = svn__apr_hash_index_key(hi);
479
const char *token = svn__apr_hash_index_val(hi);
482
/* The path needs to live as long as ACCESS_CTX. */
483
fspath = svn_fspath__join(fspath_base, relpath, access_pool);
485
/* The token must live as long as ACCESS_CTX. */
486
token = apr_pstrdup(access_pool, token);
488
SVN_ERR(svn_fs_access_add_lock_token2(access_ctx, fspath,
428
498
/*----------------------------------------------------------------*/
430
500
/*** The RA vtable routines ***/
672
740
apr_pool_t *pool)
674
742
svn_ra_local__session_baton_t *sess = session->priv;
675
struct deltify_etc_baton *db = apr_palloc(pool, sizeof(*db));
676
apr_hash_index_t *hi;
677
svn_fs_access_t *fs_access;
743
struct deltify_etc_baton *deb = apr_palloc(pool, sizeof(*deb));
680
db->repos = sess->repos;
681
db->fs_path = sess->fs_path->data;
745
/* Prepare the baton for deltify_etc() */
747
deb->repos = sess->repos;
748
deb->fspath_base = sess->fs_path->data;
682
749
if (! keep_locks)
683
db->lock_tokens = lock_tokens;
750
deb->lock_tokens = lock_tokens;
685
db->lock_tokens = NULL;
687
db->callback = callback;
688
db->callback_baton = callback_baton;
752
deb->lock_tokens = NULL;
753
deb->commit_cb = callback;
754
deb->commit_baton = callback_baton;
690
756
SVN_ERR(get_username(session, pool));
692
758
/* If there are lock tokens to add, do so. */
695
SVN_ERR(svn_fs_get_access(&fs_access, sess->fs));
697
/* If there is no access context, the filesystem will scream if a
701
for (hi = apr_hash_first(pool, lock_tokens); hi;
702
hi = apr_hash_next(hi))
705
const char *abs_path, *token;
708
apr_hash_this(hi, &key, NULL, &val);
709
abs_path = svn_fspath__join(sess->fs_path->data, key, pool);
711
SVN_ERR(svn_fs_access_add_lock_token2(fs_access,
759
SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
760
session->pool, pool));
717
762
/* Copy the revprops table so we can add the username. */
718
763
revprop_table = apr_hash_copy(pool, revprop_table);
719
apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING,
720
svn_string_create(sess->username, pool));
764
svn_hash_sets(revprop_table, SVN_PROP_REVISION_AUTHOR,
765
svn_string_create(sess->username, pool));
766
svn_hash_sets(revprop_table, SVN_PROP_TXN_CLIENT_COMPAT_VERSION,
767
svn_string_create(SVN_VER_NUMBER, pool));
722
769
/* Get the repos commit-editor */
723
770
return svn_repos_get_commit_editor5
724
771
(editor, edit_baton, sess->repos, NULL,
725
772
svn_path_uri_decode(sess->repos_url, pool), sess->fs_path->data,
726
revprop_table, deltify_etc, db, NULL, NULL, pool);
773
revprop_table, deltify_etc, deb, NULL, NULL, pool);
887
939
static svn_error_t *
888
cancellation_log_receiver(void *baton,
889
svn_log_entry_t *log_entry,
940
log_receiver_wrapper(void *baton,
941
svn_log_entry_t *log_entry,
892
944
struct log_baton *b = baton;
893
945
svn_ra_local__session_baton_t *sess = b->sess;
895
SVN_ERR((sess->callbacks->cancel_func)(sess->callback_baton));
947
if (sess->callbacks->cancel_func)
948
SVN_ERR((sess->callbacks->cancel_func)(sess->callback_baton));
950
/* For consistency with the other RA layers, replace an empty
951
changed-paths hash with a NULL one.
953
### Should this be done by svn_ra_get_log2() instead, then? */
954
if ((log_entry->changed_paths2)
955
&& (apr_hash_count(log_entry->changed_paths2) == 0))
957
log_entry->changed_paths = NULL;
958
log_entry->changed_paths2 = NULL;
897
961
return b->real_cb(b->real_baton, log_entry, pool);
998
1057
static svn_error_t *
999
1058
get_node_props(apr_hash_t **props,
1059
apr_array_header_t **inherited_props,
1000
1060
svn_ra_local__session_baton_t *sess,
1001
1061
svn_fs_root_t *root,
1002
1062
const char *path,
1063
apr_pool_t *result_pool,
1064
apr_pool_t *scratch_pool)
1005
1066
svn_revnum_t cmt_rev;
1006
1067
const char *cmt_date, *cmt_author;
1008
1069
/* Create a hash with props attached to the fs node. */
1009
SVN_ERR(svn_fs_node_proplist(props, root, path, pool));
1072
SVN_ERR(svn_fs_node_proplist(props, root, path, result_pool));
1075
/* Get inherited properties if requested. */
1076
if (inherited_props)
1078
SVN_ERR(svn_repos_fs_get_inherited_props(inherited_props, root, path,
1080
result_pool, scratch_pool));
1011
1083
/* Now add some non-tweakable metadata to the hash as well... */
1013
/* The so-called 'entryprops' with info about CR & friends. */
1014
SVN_ERR(svn_repos_get_committed_info(&cmt_rev, &cmt_date,
1015
&cmt_author, root, path, pool));
1017
apr_hash_set(*props,
1018
SVN_PROP_ENTRY_COMMITTED_REV,
1019
APR_HASH_KEY_STRING,
1020
svn_string_createf(pool, "%ld", cmt_rev));
1021
apr_hash_set(*props,
1022
SVN_PROP_ENTRY_COMMITTED_DATE,
1023
APR_HASH_KEY_STRING,
1024
cmt_date ? svn_string_create(cmt_date, pool) : NULL);
1025
apr_hash_set(*props,
1026
SVN_PROP_ENTRY_LAST_AUTHOR,
1027
APR_HASH_KEY_STRING,
1028
cmt_author ? svn_string_create(cmt_author, pool) : NULL);
1029
apr_hash_set(*props,
1030
SVN_PROP_ENTRY_UUID,
1031
APR_HASH_KEY_STRING,
1032
svn_string_create(sess->uuid, pool));
1034
/* We have no 'wcprops' in ra_local, but might someday. */
1087
/* The so-called 'entryprops' with info about CR & friends. */
1088
SVN_ERR(svn_repos_get_committed_info(&cmt_rev, &cmt_date,
1089
&cmt_author, root, path,
1092
svn_hash_sets(*props, SVN_PROP_ENTRY_COMMITTED_REV,
1093
svn_string_createf(result_pool, "%ld", cmt_rev));
1094
svn_hash_sets(*props, SVN_PROP_ENTRY_COMMITTED_DATE, cmt_date ?
1095
svn_string_create(cmt_date, result_pool) :NULL);
1096
svn_hash_sets(*props, SVN_PROP_ENTRY_LAST_AUTHOR, cmt_author ?
1097
svn_string_create(cmt_author, result_pool) :NULL);
1098
svn_hash_sets(*props, SVN_PROP_ENTRY_UUID,
1099
svn_string_create(sess->uuid, result_pool));
1101
/* We have no 'wcprops' in ra_local, but might someday. */
1036
1104
return SVN_NO_ERROR;
1491
1563
return SVN_NO_ERROR;
1566
static svn_error_t *
1567
svn_ra_local__get_inherited_props(svn_ra_session_t *session,
1568
apr_array_header_t **iprops,
1570
svn_revnum_t revision,
1571
apr_pool_t *result_pool,
1572
apr_pool_t *scratch_pool)
1574
svn_fs_root_t *root;
1575
svn_revnum_t youngest_rev;
1576
svn_ra_local__session_baton_t *sess = session->priv;
1577
const char *abs_path = svn_fspath__join(sess->fs_path->data, path,
1579
svn_node_kind_t node_kind;
1581
/* Open the revision's root. */
1582
if (! SVN_IS_VALID_REVNUM(revision))
1584
SVN_ERR(svn_fs_youngest_rev(&youngest_rev, sess->fs, scratch_pool));
1585
SVN_ERR(svn_fs_revision_root(&root, sess->fs, youngest_rev,
1590
SVN_ERR(svn_fs_revision_root(&root, sess->fs, revision, scratch_pool));
1593
SVN_ERR(svn_fs_check_path(&node_kind, root, abs_path, scratch_pool));
1594
if (node_kind == svn_node_none)
1596
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
1597
_("'%s' path not found"), abs_path);
1600
return svn_error_trace(get_node_props(NULL, iprops, sess, root, abs_path,
1601
result_pool, scratch_pool));
1604
static svn_error_t *
1605
svn_ra_local__register_editor_shim_callbacks(svn_ra_session_t *session,
1606
svn_delta_shim_callbacks_t *callbacks)
1608
/* This is currenly a no-op, since we don't provide our own editor, just
1609
use the one the libsvn_repos hands back to us. */
1610
return SVN_NO_ERROR;
1614
static svn_error_t *
1615
svn_ra_local__get_commit_ev2(svn_editor_t **editor,
1616
svn_ra_session_t *session,
1617
apr_hash_t *revprops,
1618
svn_commit_callback2_t commit_cb,
1620
apr_hash_t *lock_tokens,
1621
svn_boolean_t keep_locks,
1622
svn_ra__provide_base_cb_t provide_base_cb,
1623
svn_ra__provide_props_cb_t provide_props_cb,
1624
svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
1626
svn_cancel_func_t cancel_func,
1628
apr_pool_t *result_pool,
1629
apr_pool_t *scratch_pool)
1631
svn_ra_local__session_baton_t *sess = session->priv;
1632
struct deltify_etc_baton *deb = apr_palloc(result_pool, sizeof(*deb));
1634
/* NOTE: the RA callbacks are ignored. We pass everything directly to
1635
the REPOS editor. */
1637
/* Prepare the baton for deltify_etc() */
1639
deb->repos = sess->repos;
1640
deb->fspath_base = sess->fs_path->data;
1642
deb->lock_tokens = lock_tokens;
1644
deb->lock_tokens = NULL;
1645
deb->commit_cb = commit_cb;
1646
deb->commit_baton = commit_baton;
1648
/* Ensure there is a username (and an FS access context) associated with
1649
the session and its FS handle. */
1650
SVN_ERR(get_username(session, scratch_pool));
1652
/* If there are lock tokens to add, do so. */
1653
SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
1654
session->pool, scratch_pool));
1656
/* Copy the REVPROPS and insert the author/username. */
1657
revprops = apr_hash_copy(scratch_pool, revprops);
1658
svn_hash_sets(revprops, SVN_PROP_REVISION_AUTHOR,
1659
svn_string_create(sess->username, scratch_pool));
1661
return svn_error_trace(svn_repos__get_commit_ev2(
1662
editor, sess->repos, NULL /* authz */,
1663
NULL /* authz_repos_name */, NULL /* authz_user */,
1665
deltify_etc, deb, cancel_func, cancel_baton,
1666
result_pool, scratch_pool));
1494
1669
/*----------------------------------------------------------------*/
1496
1671
static const svn_version_t *