Пример #1
0
static svn_error_t *
invoke_commit_cb(svn_commit_callback2_t commit_cb,
                 void *commit_baton,
                 svn_fs_t *fs,
                 svn_revnum_t revision,
                 const char *post_commit_errstr,
                 apr_pool_t *scratch_pool)
{
  /* FS interface returns non-const values.  */
  /* const */ svn_string_t *date;
  /* const */ svn_string_t *author;
  svn_commit_info_t *commit_info;

  if (commit_cb == NULL)
    return SVN_NO_ERROR;

  SVN_ERR(svn_fs_revision_prop(&date, fs, revision, SVN_PROP_REVISION_DATE,
                               scratch_pool));
  SVN_ERR(svn_fs_revision_prop(&author, fs, revision,
                               SVN_PROP_REVISION_AUTHOR,
                               scratch_pool));

  commit_info = svn_create_commit_info(scratch_pool);

  /* fill up the svn_commit_info structure */
  commit_info->revision = revision;
  commit_info->date = date ? date->data : NULL;
  commit_info->author = author ? author->data : NULL;
  commit_info->post_commit_err = post_commit_errstr;
  /* commit_info->repos_root is not set by the repos layer, only by RA layers */

  return svn_error_trace(commit_cb(commit_info, commit_baton, scratch_pool));
}
Пример #2
0
svn_error_t *
svn_repos_fs_revision_prop(svn_string_t **value_p,
                           svn_repos_t *repos,
                           svn_revnum_t rev,
                           const char *propname,
                           svn_repos_authz_func_t authz_read_func,
                           void *authz_read_baton,
                           apr_pool_t *pool)
{
  svn_repos_revision_access_level_t readability;

  SVN_ERR(svn_repos_check_revision_access(&readability, repos, rev,
                                          authz_read_func, authz_read_baton,
                                          pool));

  if (readability == svn_repos_revision_access_none)
    {
      /* Property?  What property? */
      *value_p = NULL;
    }
  else if (readability == svn_repos_revision_access_partial)
    {
      /* Only svn:author and svn:date are fetchable. */
      if ((strncmp(propname, SVN_PROP_REVISION_AUTHOR,
                   strlen(SVN_PROP_REVISION_AUTHOR)) != 0)
          && (strncmp(propname, SVN_PROP_REVISION_DATE,
                      strlen(SVN_PROP_REVISION_DATE)) != 0))
        *value_p = NULL;

      else
        SVN_ERR(svn_fs_revision_prop(value_p, repos->fs,
                                     rev, propname, pool));
    }
  else /* wholly readable revision */
    {
      SVN_ERR(svn_fs_revision_prop(value_p, repos->fs, rev, propname, pool));
    }

  return SVN_NO_ERROR;
}
Пример #3
0
svn_error_t *
svn_repos_fs_change_rev_prop3(svn_repos_t *repos,
                              svn_revnum_t rev,
                              const char *author,
                              const char *name,
                              const svn_string_t *new_value,
                              svn_boolean_t use_pre_revprop_change_hook,
                              svn_boolean_t use_post_revprop_change_hook,
                              svn_repos_authz_func_t authz_read_func,
                              void *authz_read_baton,
                              apr_pool_t *pool)
{
  svn_string_t *old_value;
  svn_repos_revision_access_level_t readability;
  char action;

  SVN_ERR(svn_repos_check_revision_access(&readability, repos, rev,
                                          authz_read_func, authz_read_baton,
                                          pool));

  if (readability == svn_repos_revision_access_full)
    {
      SVN_ERR(validate_prop(name, new_value, pool));
      SVN_ERR(svn_fs_revision_prop(&old_value, repos->fs, rev, name, pool));

      if (! new_value)
        action = 'D';
      else if (! old_value)
        action = 'A';
      else
        action = 'M';

      if (use_pre_revprop_change_hook)
        SVN_ERR(svn_repos__hooks_pre_revprop_change(repos, rev, author, name,
                                                    new_value, action, pool));

      SVN_ERR(svn_fs_change_rev_prop(repos->fs, rev, name, new_value, pool));

      if (use_post_revprop_change_hook)
        SVN_ERR(svn_repos__hooks_post_revprop_change(repos, rev, author,  name,
                                                     old_value, action, pool));
    }
  else  /* rev is either unreadable or only partially readable */
    {
      return svn_error_createf
        (SVN_ERR_AUTHZ_UNREADABLE, NULL,
         _("Write denied:  not authorized to read all of revision %ld"), rev);
    }

  return SVN_NO_ERROR;
}
Пример #4
0
static svn_error_t *
get_set_revprop_packed_fs(const svn_test_opts_t *opts,
                          apr_pool_t *pool)
{
  svn_fs_t *fs;
  svn_fs_txn_t *txn;
  svn_fs_root_t *txn_root;
  const char *conflict;
  svn_revnum_t after_rev;
  svn_string_t *prop_value;
  apr_pool_t *subpool;

  /* 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 the packed FS and open it. */
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
  SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));

  subpool = svn_pool_create(pool);
  /* Do a commit to trigger packing. */
  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, "iota", "new-iota",  subpool));
  SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
  svn_pool_clear(subpool);

  /* Pack the repository. */
  SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool));

  /* Try to get revprop for revision 0. */
  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR,
                               pool));

  /* Try to change revprop for revision 0. */
  SVN_ERR(svn_fs_change_rev_prop(fs, 0, SVN_PROP_REVISION_AUTHOR,
                                 svn_string_create("tweaked-author", pool),
                                 pool));

  return SVN_NO_ERROR;
}
Пример #5
0
dav_error *
dav_svn__merge_response(ap_filter_t *output,
                        const dav_svn_repos *repos,
                        svn_revnum_t new_rev,
                        char *post_commit_err,
                        apr_xml_elem *prop_elem,
                        svn_boolean_t disable_merge_response,
                        apr_pool_t *pool)
{
  apr_bucket_brigade *bb;
  svn_fs_root_t *root;
  svn_error_t *serr;
  const char *vcc;
  const char *rev;
  svn_string_t *creationdate, *creator_displayname;
  const char *post_commit_err_elem = NULL,
             *post_commit_header_info = NULL;

  serr = svn_fs_revision_root(&root, repos->fs, new_rev, pool);
  if (serr != NULL)
    {
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "Could not open the FS root for the "
                                  "revision just committed.",
                                  repos->pool);
    }

  bb = apr_brigade_create(pool, output->c->bucket_alloc);

  /* prep some strings */

  /* the HREF for the baseline is actually the VCC */
  vcc = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_VCC, SVN_IGNORED_REVNUM,
                           NULL, 0 /* add_href */, pool);

  /* the version-name of the baseline is the revision number */
  rev = apr_psprintf(pool, "%ld", new_rev);

  /* get the post-commit hook stderr, if any */
  if (post_commit_err)
    {
      post_commit_header_info = apr_psprintf(pool,
                                             " xmlns:S=\"%s\"",
                                             SVN_XML_NAMESPACE);
      post_commit_err_elem = apr_psprintf(pool,
                                          "<S:post-commit-err>%s"
                                          "</S:post-commit-err>",
                                          post_commit_err);
    }
  else
    {
      post_commit_header_info = "" ;
      post_commit_err_elem = "" ;
    }


  /* get the creationdate and creator-displayname of the new revision, too. */
  serr = svn_fs_revision_prop(&creationdate, repos->fs, new_rev,
                              SVN_PROP_REVISION_DATE, pool);
  if (serr != NULL)
    {
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "Could not get date of newest revision",
                                  repos->pool);
    }
  serr = svn_fs_revision_prop(&creator_displayname, repos->fs, new_rev,
                              SVN_PROP_REVISION_AUTHOR, pool);
  if (serr != NULL)
    {
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "Could not get author of newest revision",
                                  repos->pool);
    }


  (void) ap_fputstrs(output, bb,
                     DAV_XML_HEADER DEBUG_CR
                     "<D:merge-response xmlns:D=\"DAV:\"",
                     post_commit_header_info,
                     ">" DEBUG_CR
                     "<D:updated-set>" DEBUG_CR

                     /* generate a response for the new baseline */
                     "<D:response>" DEBUG_CR
                     "<D:href>",
                     apr_xml_quote_string(pool, vcc, 1),
                     "</D:href>" DEBUG_CR
                     "<D:propstat><D:prop>" DEBUG_CR
                     /* ### this is wrong. it's a VCC, not a baseline. but
                        ### we need to tell the client to look at *this*
                        ### resource for the version-name. */
                     "<D:resourcetype><D:baseline/></D:resourcetype>" DEBUG_CR,
                     post_commit_err_elem, DEBUG_CR
                     "<D:version-name>", rev, "</D:version-name>" DEBUG_CR,
                     NULL);
  if (creationdate)
    {
      (void) ap_fputstrs(output, bb,
                         "<D:creationdate>",
                         apr_xml_quote_string(pool, creationdate->data, 1),
                         "</D:creationdate>" DEBUG_CR,
                         NULL);
    }
  if (creator_displayname)
    {
      (void) ap_fputstrs(output, bb,
                         "<D:creator-displayname>",
                         apr_xml_quote_string(pool,
                                              creator_displayname->data, 1),
                         "</D:creator-displayname>" DEBUG_CR,
                         NULL);
    }
  (void) ap_fputstrs(output, bb,
                     "</D:prop>" DEBUG_CR
                     "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
                     "</D:propstat>" DEBUG_CR
                     "</D:response>" DEBUG_CR,

                     NULL);

  /* ONLY have dir_delta drive the editor if the caller asked us to
     generate a full MERGE response.  svn clients can ask us to
     suppress this walk by sending specific request headers. */
  if (! disable_merge_response)
    {
      /* Now we need to generate responses for all the resources which
         changed.  This is done through a delta of the two roots.

         Note that a directory is not marked when open_dir is seen
         (since it typically is used just for changing members in that
         directory); instead, we want for a property change (the only
         reason the client would need to fetch a new directory).

         ### we probably should say something about the dirs, so that
         ### we can pass back the new version URL */

      /* and go make me proud, boy! */
      serr = do_resources(repos, root, new_rev, output, bb, pool);
      if (serr != NULL)
        {
          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                      "Error constructing resource list.",
                                      repos->pool);
        }
    }

  /* wrap up the merge response */
  (void) ap_fputs(output, bb,
                  "</D:updated-set>" DEBUG_CR
                  "</D:merge-response>" DEBUG_CR);

  /* send whatever is left in the brigade */
  (void) ap_pass_brigade(output, bb);

  return SVN_NO_ERROR;
}
Пример #6
0
static svn_error_t *
close_edit(void *edit_baton,
           apr_pool_t *pool)
{
  struct edit_baton *eb = edit_baton;
  svn_revnum_t new_revision = SVN_INVALID_REVNUM;
  svn_error_t *err;
  const char *conflict;
  const char *post_commit_err = NULL;

  /* If no transaction has been created (ie. if open_root wasn't
     called before close_edit), abort the operation here with an
     error. */
  if (! eb->txn)
    return svn_error_create(SVN_ERR_REPOS_BAD_ARGS, NULL,
                            "No valid transaction supplied to close_edit");

  /* Commit. */
  err = svn_repos_fs_commit_txn(&conflict, eb->repos,
                                &new_revision, eb->txn, pool);

  if (SVN_IS_VALID_REVNUM(new_revision))
    {
      if (err)
        {
          /* If the error was in post-commit, then the commit itself
             succeeded.  In which case, save the post-commit warning
             (to be reported back to the client, who will probably
             display it as a warning) and clear the error. */
          post_commit_err = svn_repos__post_commit_error_str(err, pool);
          svn_error_clear(err);
          err = SVN_NO_ERROR;
        }
    }
  else
    {
      /* ### todo: we should check whether it really was a conflict,
         and return the conflict info if so? */

      /* If the commit failed, it's *probably* due to a conflict --
         that is, the txn being out-of-date.  The filesystem gives us
         the ability to continue diddling the transaction and try
         again; but let's face it: that's not how the cvs or svn works
         from a user interface standpoint.  Thus we don't make use of
         this fs feature (for now, at least.)

         So, in a nutshell: svn commits are an all-or-nothing deal.
         Each commit creates a new fs txn which either succeeds or is
         aborted completely.  No second chances;  the user simply
         needs to update and commit again  :) */

      eb->txn_aborted = TRUE;

      return svn_error_trace(
                svn_error_compose_create(err,
                                         svn_fs_abort_txn(eb->txn, pool)));
    }

  /* Pass new revision information to the caller's callback. */
  {
    svn_string_t *date, *author;
    svn_commit_info_t *commit_info;

    /* Even if there was a post-commit hook failure, it's more serious
       if one of the calls here fails, so we explicitly check for errors
       here, while saving the possible post-commit error for later. */

    err = svn_fs_revision_prop(&date, svn_repos_fs(eb->repos),
                                new_revision, SVN_PROP_REVISION_DATE,
                                pool);
    if (! err)
      {
        err = svn_fs_revision_prop(&author, svn_repos_fs(eb->repos),
                                   new_revision, SVN_PROP_REVISION_AUTHOR,
                                   pool);
      }

    if ((! err) && eb->commit_callback)
      {
        commit_info = svn_create_commit_info(pool);

        /* fill up the svn_commit_info structure */
        commit_info->revision = new_revision;
        commit_info->date = date ? date->data : NULL;
        commit_info->author = author ? author->data : NULL;
        commit_info->post_commit_err = post_commit_err;
        err = (*eb->commit_callback)(commit_info,
                                     eb->commit_callback_baton,
                                     pool);
      }
  }

  return svn_error_trace(err);
}
Пример #7
0
svn_error_t *
svn_repos_fs_change_rev_prop4(svn_repos_t *repos,
                              svn_revnum_t rev,
                              const char *author,
                              const char *name,
                              const svn_string_t *const *old_value_p,
                              const svn_string_t *new_value,
                              svn_boolean_t use_pre_revprop_change_hook,
                              svn_boolean_t use_post_revprop_change_hook,
                              svn_repos_authz_func_t authz_read_func,
                              void *authz_read_baton,
                              apr_pool_t *pool)
{
    svn_repos_revision_access_level_t readability;

    SVN_ERR(svn_repos_check_revision_access(&readability, repos, rev,
                                            authz_read_func, authz_read_baton,
                                            pool));

    if (readability == svn_repos_revision_access_full)
    {
        const svn_string_t *old_value;
        char action;
        apr_hash_t *hooks_env;

        SVN_ERR(svn_repos__validate_prop(name, new_value, pool));

        /* Fetch OLD_VALUE for svn_fs_change_rev_prop2(). */
        if (old_value_p)
        {
            old_value = *old_value_p;
        }
        else
        {
            /* Get OLD_VALUE anyway, in order for ACTION and OLD_VALUE arguments
             * to the hooks to be accurate. */
            svn_string_t *old_value2;

            SVN_ERR(svn_fs_revision_prop(&old_value2, repos->fs, rev, name, pool));
            old_value = old_value2;
        }

        /* Prepare ACTION. */
        if (! new_value)
            action = 'D';
        else if (! old_value)
            action = 'A';
        else
            action = 'M';

        /* Parse the hooks-env file (if any, and if to be used). */
        if (use_pre_revprop_change_hook || use_post_revprop_change_hook)
            SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
                                               pool, pool));

        /* ### currently not passing the old_value to hooks */
        if (use_pre_revprop_change_hook)
            SVN_ERR(svn_repos__hooks_pre_revprop_change(repos, hooks_env, rev,
                    author, name, new_value,
                    action, pool));

        SVN_ERR(svn_fs_change_rev_prop2(repos->fs, rev, name,
                                        &old_value, new_value, pool));

        if (use_post_revprop_change_hook)
            SVN_ERR(svn_repos__hooks_post_revprop_change(repos, hooks_env, rev,
                    author, name, old_value,
                    action, pool));
    }
    else  /* rev is either unreadable or only partially readable */
    {
        return svn_error_createf
               (SVN_ERR_AUTHZ_UNREADABLE, NULL,
                _("Write denied:  not authorized to read all of revision %ld"), rev);
    }

    return SVN_NO_ERROR;
}