Exemplo n.º 1
0
static svn_error_t *
compare_changes(apr_hash_t *ideals,
                apr_hash_t *changes,
                svn_test_opts_t *opts,
                const char *txn_id,
                apr_pool_t *pool)
{
  apr_hash_index_t *hi;

  for (hi = apr_hash_first(pool, ideals); hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      svn_fs_path_change_t *ideal_change, *change;
      const char *path;

      /* KEY will be the path, VAL the change. */
      apr_hash_this(hi, &key, NULL, &val);
      path = (const char *) key;
      ideal_change = val;

      /* Now get the change that refers to PATH in the actual
         changes hash. */
      change = apr_hash_get(changes, path, APR_HASH_KEY_STRING);
      if (! change)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL,
           "missing expected change for path '%s' in txn_id '%s'",
           path, txn_id);

      /* Verify that the NODE-REV-ID matches. */
      if (svn_fs_compare_ids(change->node_rev_id,
                             ideal_change->node_rev_id))
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL,
           "node revision ids differ in change for key '%s'", txn_id);

      /* Verify that the change KIND matches. */
      if (change->change_kind != ideal_change->change_kind)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL,
           "change kinds differ in change for key '%s'", txn_id);

      /* Verify that the change TEXT-MOD bit matches. */
      if (change->text_mod != ideal_change->text_mod)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL,
           "change text-mod bits differ in change for key '%s'", txn_id);

      /* Verify that the change PROP-MOD bit matches. */
      if (change->prop_mod != ideal_change->prop_mod)
        return svn_error_createf
          (SVN_ERR_TEST_FAILED, NULL,
           "change prop-mod bits differ in change for key '%s'", txn_id);
    }

  return SVN_NO_ERROR;
}
Exemplo n.º 2
0
/* The caller wants to modify REVISION of FSPATH. Is that allowed?  */
static svn_error_t *
can_modify(svn_fs_root_t *txn_root,
           const char *fspath,
           svn_revnum_t revision,
           apr_pool_t *scratch_pool)
{
    svn_revnum_t created_rev;

    /* Out-of-dateness check:  compare the created-rev of the node
       in the txn against the created-rev of FSPATH.  */
    SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath,
                                    scratch_pool));

    /* Uncommitted nodes (eg. a descendent of a copy/move/rotate destination)
       have no (committed) revision number. Let the caller go ahead and
       modify these nodes.

       Note: strictly speaking, they might be performing an "illegal" edit
       in certain cases, but let's just assume they're Good Little Boys.

       If CREATED_REV is invalid, that means it's already mutable in the
       txn, which means it has already passed this out-of-dateness check.
       (Usually, this happens when looking at a parent directory of an
       already-modified node)  */
    if (!SVN_IS_VALID_REVNUM(created_rev))
        return SVN_NO_ERROR;

    /* If the node is immutable (has a revision), then the caller should
       have supplied a valid revision number [that they expect to change].
       The checks further below will determine the out-of-dateness of the
       specified revision.  */
    /* ### ugh. descendents of copy/move/rotate destinations carry along
       ### their original immutable state and (thus) a valid CREATED_REV.
       ### but they are logically uncommitted, so the caller will pass
       ### SVN_INVALID_REVNUM. (technically, the caller could provide
       ### ORIGINAL_REV, but that is semantically incorrect for the Ev2
       ### API).
       ###
       ### for now, we will assume the caller knows what they are doing
       ### and an invalid revision implies such a descendent. in the
       ### future, we could examine the ancestor chain looking for a
       ### copy/move/rotate-here node and allow the modification (and the
       ### converse: if no such ancestor, the caller must specify the
       ### correct/intended revision to modify).
    */
#if 1
    if (!SVN_IS_VALID_REVNUM(revision))
        return SVN_NO_ERROR;
#else
    if (!SVN_IS_VALID_REVNUM(revision))
        /* ### use a custom error code?  */
        return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
                                 _("Revision for modifying '%s' is required"),
                                 fspath);
#endif

    if (revision < created_rev)
    {
        /* We asked to change a node that is *older* than what we found
           in the transaction. The client is out of date.  */
        return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL,
                                 _("'%s' is out of date; try updating"),
                                 fspath);
    }

    if (revision > created_rev)
    {
        /* We asked to change a node that is *newer* than what we found
           in the transaction. Given that the transaction was based off
           of 'youngest', then either:
           - the caller asked to modify a future node
           - the caller has committed more revisions since this txn
           was constructed, and is asking to modify a node in one
           of those new revisions.
           In either case, the node may not have changed in those new
           revisions; use the node's ID to determine this case.  */
        const svn_fs_id_t *txn_noderev_id;
        svn_fs_root_t *rev_root;
        const svn_fs_id_t *new_noderev_id;

        /* The ID of the node that we would be modifying in the txn  */
        SVN_ERR(svn_fs_node_id(&txn_noderev_id, txn_root, fspath,
                               scratch_pool));

        /* Get the ID from the future/new revision.  */
        SVN_ERR(svn_fs_revision_root(&rev_root, svn_fs_root_fs(txn_root),
                                     revision, scratch_pool));
        SVN_ERR(svn_fs_node_id(&new_noderev_id, rev_root, fspath,
                               scratch_pool));
        svn_fs_close_root(rev_root);

        /* Has the target node changed in the future?  */
        if (svn_fs_compare_ids(txn_noderev_id, new_noderev_id) != 0)
        {
            /* Restarting the commit will base the txn on the future/new
               revision, allowing the modification at REVISION.  */
            /* ### use a custom error code  */
            return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
                                     _("'%s' has been modified since the "
                                       "commit began (restart the commit)"),
                                     fspath);
        }
    }

    return SVN_NO_ERROR;
}