Example #1
0
static svn_error_t *
open_root(void *edit_baton,
          svn_revnum_t base_revision,
          apr_pool_t *pool,
          void **root_baton)
{
  struct dir_baton *dirb;
  struct edit_baton *eb = edit_baton;
  svn_revnum_t youngest;

  /* Ignore BASE_REVISION.  We always build our transaction against
     HEAD.  However, we will keep it in our dir baton for out of
     dateness checks.  */
  SVN_ERR(svn_fs_youngest_rev(&youngest, eb->fs, eb->pool));

  if (base_revision > youngest)
    return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
                             _("No such revision %ld (HEAD is %ld)"),
                             base_revision, youngest);

  /* Unless we've been instructed to use a specific transaction, we'll
     make our own. */
  if (eb->txn_owner)
    {
      SVN_ERR(svn_repos_fs_begin_txn_for_commit2(&(eb->txn),
                                                 eb->repos,
                                                 youngest,
                                                 eb->revprop_table,
                                                 eb->pool));
    }
  else /* Even if we aren't the owner of the transaction, we might
          have been instructed to set some properties. */
    {
      apr_array_header_t *props = svn_prop_hash_to_array(eb->revprop_table,
                                                         pool);
      SVN_ERR(svn_repos_fs_change_txn_props(eb->txn, props, pool));
    }
  SVN_ERR(svn_fs_txn_name(&(eb->txn_name), eb->txn, eb->pool));
  SVN_ERR(svn_fs_txn_root(&(eb->txn_root), eb->txn, eb->pool));

  /* Create a root dir baton.  The `base_path' field is an -absolute-
     path in the filesystem, upon which all further editor paths are
     based. */
  dirb = apr_pcalloc(pool, sizeof(*dirb));
  dirb->edit_baton = edit_baton;
  dirb->parent = NULL;
  dirb->pool = pool;
  dirb->was_copied = FALSE;
  dirb->path = apr_pstrdup(pool, eb->base_path);
  dirb->base_rev = base_revision;

  *root_baton = dirb;
  return SVN_NO_ERROR;
}
Example #2
0
dav_error *
dav_svn__create_txn(dav_svn_repos *repos,
                    const char **ptxn_name,
                    apr_hash_t *revprops,
                    apr_pool_t *pool)
{
  svn_revnum_t rev;
  svn_fs_txn_t *txn;
  svn_error_t *serr;

  if (! revprops)
    {
      revprops = apr_hash_make(pool);
    }

  if (repos->username)
    {
      svn_hash_sets(revprops,
                    SVN_PROP_REVISION_AUTHOR,
                    svn_string_create(repos->username, pool));
    }

  serr = dav_svn__get_youngest_rev(&rev, repos, pool);
  if (serr != NULL)
    {
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not determine youngest revision",
                                  repos->pool);
    }

  serr = svn_repos_fs_begin_txn_for_commit2(&txn, repos->repos, rev,
                                            revprops, repos->pool);
  if (serr != NULL)
    {
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not begin a transaction",
                                  repos->pool);
    }

  serr = svn_fs_txn_name(ptxn_name, txn, pool);
  if (serr != NULL)
    {
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not fetch transaction name",
                                  repos->pool);
    }

  return NULL;
}
Example #3
0
svn_error_t *
svn_repos_fs_begin_txn_for_commit(svn_fs_txn_t **txn_p,
                                  svn_repos_t *repos,
                                  svn_revnum_t rev,
                                  const char *author,
                                  const char *log_msg,
                                  apr_pool_t *pool)
{
    apr_hash_t *revprop_table = apr_hash_make(pool);
    if (author)
        svn_hash_sets(revprop_table, SVN_PROP_REVISION_AUTHOR,
                      svn_string_create(author, pool));
    if (log_msg)
        svn_hash_sets(revprop_table, SVN_PROP_REVISION_LOG,
                      svn_string_create(log_msg, pool));
    return svn_repos_fs_begin_txn_for_commit2(txn_p, repos, rev, revprop_table,
            pool);
}
/*
** Append the specified lock(s) to the set of locks on this resource.
**
** If "make_indirect" is true (non-zero), then the specified lock(s)
** should be converted to an indirect lock (if it is a direct lock)
** before appending. Note that the conversion to an indirect lock does
** not alter the passed-in lock -- the change is internal the
** append_locks function.
**
** Multiple locks are specified using the lock->next links.
*/
static dav_error *
append_locks(dav_lockdb *lockdb,
             const dav_resource *resource,
             int make_indirect,
             const dav_lock *lock)
{
  dav_lockdb_private *info = lockdb->info;
  svn_lock_t *slock;
  svn_error_t *serr;
  dav_error *derr;

  /* If the resource's fs path is unreadable, we don't allow a lock to
     be created on it. */
  if (! dav_svn__allow_read_resource(resource, SVN_INVALID_REVNUM,
                                     resource->pool))
    return dav_svn__new_error(resource->pool, HTTP_FORBIDDEN,
                              DAV_ERR_LOCK_SAVE_LOCK,
                              "Path is not accessible.");

  if (lock->next)
    return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST,
                              DAV_ERR_LOCK_SAVE_LOCK,
                              "Tried to attach multiple locks to a resource.");

  /* RFC2518bis (section 7.4) doesn't require us to support
     'lock-null' resources at all.  Instead, it asks that we treat
     'LOCK nonexistentURL' as a PUT (followed by a LOCK) of a 0-byte file.  */
  if (! resource->exists)
    {
      svn_revnum_t rev, new_rev;
      svn_fs_txn_t *txn;
      svn_fs_root_t *txn_root;
      const char *conflict_msg;
      dav_svn_repos *repos = resource->info->repos;
      apr_hash_t *revprop_table = apr_hash_make(resource->pool);
      apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR,
                   APR_HASH_KEY_STRING, svn_string_create(repos->username,
                                                          resource->pool));

      if (resource->info->repos->is_svn_client)
        return dav_svn__new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED,
                                  DAV_ERR_LOCK_SAVE_LOCK,
                                  "Subversion clients may not lock "
                                  "nonexistent paths.");

      else if (! resource->info->repos->autoversioning)
        return dav_svn__new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED,
                                  DAV_ERR_LOCK_SAVE_LOCK,
                                  "Attempted to lock non-existent path; "
                                  "turn on autoversioning first.");

      /* Commit a 0-byte file: */

      if ((serr = svn_fs_youngest_rev(&rev, repos->fs, resource->pool)))
        return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                    "Could not determine youngest revision",
                                    resource->pool);

      if ((serr = svn_repos_fs_begin_txn_for_commit2(&txn, repos->repos, rev,
                                                     revprop_table,
                                                     resource->pool)))
        return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                    "Could not begin a transaction",
                                    resource->pool);

      if ((serr = svn_fs_txn_root(&txn_root, txn, resource->pool)))
        return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                    "Could not begin a transaction",
                                    resource->pool);

      if ((serr = svn_fs_make_file(txn_root, resource->info->repos_path,
                                   resource->pool)))
        return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                    "Could not create empty file.",
                                    resource->pool);

      if ((serr = dav_svn__attach_auto_revprops(txn,
                                                resource->info->repos_path,
                                                resource->pool)))
        return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                    "Could not create empty file.",
                                    resource->pool);

      serr = svn_repos_fs_commit_txn(&conflict_msg, repos->repos,
                                     &new_rev, txn, resource->pool);
      if (SVN_IS_VALID_REVNUM(new_rev))
        {
          /* ### Log an error in post commit FS processing? */
          svn_error_clear(serr);
        }
      else
        {
          svn_error_clear(svn_fs_abort_txn(txn, resource->pool));
          if (serr)
            return dav_svn__convert_err(serr, HTTP_CONFLICT,
                                        apr_psprintf(resource->pool,
                                                     "Conflict when "
                                                     "committing '%s'.",
                                                     conflict_msg),
                                        resource->pool);
          else
            return dav_svn__new_error(resource->pool,
                                      HTTP_INTERNAL_SERVER_ERROR,
                                      0,
                                      "Commit failed but there was no error "
                                      "provided.");
        }
    }

  /* Convert the dav_lock into an svn_lock_t. */
  derr = dav_lock_to_svn_lock(&slock, lock, resource->info->repos_path,
                              info, resource->info->repos->is_svn_client,
                              resource->pool);
  if (derr)
    return derr;

  /* Now use the svn_lock_t to actually perform the lock. */
  serr = svn_repos_fs_lock(&slock,
                           resource->info->repos->repos,
                           slock->path,
                           slock->token,
                           slock->comment,
                           slock->is_dav_comment,
                           slock->expiration_date,
                           info->working_revnum,
                           info->lock_steal,
                           resource->pool);

  if (serr && serr->apr_err == SVN_ERR_FS_NO_USER)
    {
      svn_error_clear(serr);
      return dav_svn__new_error(resource->pool, HTTP_UNAUTHORIZED,
                                DAV_ERR_LOCK_SAVE_LOCK,
                                "Anonymous lock creation is not allowed.");
    }
  else if (serr)
    return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                "Failed to create new lock.",
                                resource->pool);


  /* A standard webdav LOCK response doesn't include any information
     about the creation date.  We send it in a custom header, so that
     svn clients can fill in svn_lock_t->creation_date.  A generic DAV
     client should just ignore the header. */
  apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER,
                 svn_time_to_cstring(slock->creation_date, resource->pool));

  /* A standard webdav LOCK response doesn't include any information
     about the owner of the lock.  ('DAV:owner' has nothing to do with
     authorization, it's just a comment that we map to
     svn_lock_t->comment.)  We send the owner in a custom header, so
     that svn clients can fill in svn_lock_t->owner.  A generic DAV
     client should just ignore the header. */
  apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER,
                 slock->owner);

  /* Log the locking as a 'high-level' action. */
  dav_svn__operational_log(resource->info,
                           svn_log__lock_one_path(slock->path, info->lock_steal,
                                                  resource->info->r->pool));

  return 0;
}