diff options
| author | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 | 
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 | 
| commit | 3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch) | |
| tree | 7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_repos/commit.c | |
| parent | a55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff) | |
Diffstat (limited to 'subversion/libsvn_repos/commit.c')
| -rw-r--r-- | subversion/libsvn_repos/commit.c | 140 | 
1 files changed, 93 insertions, 47 deletions
diff --git a/subversion/libsvn_repos/commit.c b/subversion/libsvn_repos/commit.c index 1190acc29fc5..6ce4cc6f7ffd 100644 --- a/subversion/libsvn_repos/commit.c +++ b/subversion/libsvn_repos/commit.c @@ -124,6 +124,7 @@ struct dir_baton    svn_revnum_t base_rev;        /* the revision I'm based on  */    svn_boolean_t was_copied; /* was this directory added with history? */    apr_pool_t *pool; /* my personal pool, in which I am allocated. */ +  svn_boolean_t checked_write; /* TRUE after successfull write check */  }; @@ -131,6 +132,7 @@ struct file_baton  {    struct edit_baton *edit_baton;    const char *path; /* the -absolute- path to this file in the fs */ +  svn_boolean_t checked_write; /* TRUE after successfull write check */  }; @@ -171,6 +173,30 @@ out_of_date(const char *path, svn_node_kind_t kind)                             path);  } +/* Perform an out of date check for base_rev against created rev, +   and a sanity check of base_rev. */ +static svn_error_t * +check_out_of_date(struct edit_baton *eb, +                  const char *path, +                  svn_node_kind_t kind, +                  svn_revnum_t base_rev, +                  svn_revnum_t created_rev) +{ +  if (base_rev < created_rev) +    { +      return out_of_date(path, kind); +    } +  else if (base_rev > created_rev) +    { +      if (base_rev > svn_fs_txn_base_revision(eb->txn)) +        return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,  +                                 _("No such revision %ld"), +                                 base_rev); +    } + +  return SVN_NO_ERROR; +} +  static svn_error_t *  invoke_commit_cb(svn_commit_callback2_t commit_cb, @@ -184,15 +210,16 @@ invoke_commit_cb(svn_commit_callback2_t commit_cb,    /* const */ svn_string_t *date;    /* const */ svn_string_t *author;    svn_commit_info_t *commit_info; +  apr_hash_t *revprops;    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)); +  SVN_ERR(svn_fs_revision_proplist2(&revprops, fs, revision, +                                    TRUE, scratch_pool, scratch_pool)); + +  date = svn_hash_gets(revprops, SVN_PROP_REVISION_DATE); +  author = svn_hash_gets(revprops, SVN_PROP_REVISION_AUTHOR);    commit_info = svn_create_commit_info(scratch_pool); @@ -298,7 +325,6 @@ add_file_or_directory(const char *path,        const char *fs_path;        svn_fs_root_t *copy_root;        svn_node_kind_t kind; -      size_t repos_url_len;        svn_repos_authz_access_t required;        /* Copy requires recursive write access to the destination path @@ -320,14 +346,12 @@ add_file_or_directory(const char *path,        /* For now, require that the url come from the same repository           that this commit is operating on. */        copy_path = svn_path_uri_decode(copy_path, subpool); -      repos_url_len = strlen(eb->repos_url_decoded); -      if (strncmp(copy_path, eb->repos_url_decoded, repos_url_len) != 0) +      fs_path = svn_cstring_skip_prefix(copy_path, eb->repos_url_decoded); +      if (!fs_path)          return svn_error_createf            (SVN_ERR_FS_GENERAL, NULL,             _("Source url '%s' is from different repository"), copy_path); -      fs_path = apr_pstrdup(subpool, copy_path + repos_url_len); -        /* Now use the "fs_path" as an absolute path within the           repository to make the copy from. */        SVN_ERR(svn_fs_revision_root(©_root, eb->fs, @@ -364,14 +388,18 @@ add_file_or_directory(const char *path,    /* Build a new child baton. */    if (is_dir)      { -      *return_baton = make_dir_baton(eb, pb, full_path, was_copied, -                                     SVN_INVALID_REVNUM, pool); +      struct dir_baton *new_db = make_dir_baton(eb, pb, full_path, was_copied, +                                                SVN_INVALID_REVNUM, pool); + +      new_db->checked_write = TRUE; /* Just created */ +      *return_baton = new_db;      }    else      {        struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));        new_fb->edit_baton = eb;        new_fb->path = full_path; +      new_fb->checked_write = TRUE; /* Just created */        *return_baton = new_fb;      } @@ -392,9 +420,9 @@ open_root(void *edit_baton,    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.  */ +  /* We always build our transaction against HEAD.  However, we will +     sanity-check BASE_REVISION and 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) @@ -448,7 +476,6 @@ delete_entry(const char *path,    struct dir_baton *parent = parent_baton;    struct edit_baton *eb = parent->edit_baton;    svn_node_kind_t kind; -  svn_revnum_t cr_rev;    svn_repos_authz_access_t required = svn_authz_write;    const char *full_path; @@ -473,14 +500,18 @@ delete_entry(const char *path,    /* Now, make sure we're deleting the node we *think* we're       deleting, else return an out-of-dateness error. */ -  SVN_ERR(svn_fs_node_created_rev(&cr_rev, eb->txn_root, full_path, pool)); -  if (SVN_IS_VALID_REVNUM(revision) && (revision < cr_rev)) -    return svn_error_trace(out_of_date(full_path, kind)); +  if (SVN_IS_VALID_REVNUM(revision)) +    { +      svn_revnum_t cr_rev; + +      SVN_ERR(svn_fs_node_created_rev(&cr_rev, eb->txn_root, full_path, pool)); +      SVN_ERR(check_out_of_date(eb, full_path, kind, revision, cr_rev)); +    }    /* This routine is a mindless wrapper.  We call svn_fs_delete()       because that will delete files and recursively delete       directories.  */ -  return svn_fs_delete(eb->txn_root, full_path, pool); +  return svn_error_trace(svn_fs_delete(eb->txn_root, full_path, pool));  } @@ -535,18 +566,23 @@ apply_textdelta(void *file_baton,                  void **handler_baton)  {    struct file_baton *fb = file_baton; +  struct edit_baton *eb = fb->edit_baton; -  /* Check for write authorization. */ -  SVN_ERR(check_authz(fb->edit_baton, fb->path, -                      fb->edit_baton->txn_root, -                      svn_authz_write, pool)); +  if (!fb->checked_write) +    { +      /* Check for write authorization. */ +      SVN_ERR(check_authz(eb, fb->path, eb->txn_root, +                          svn_authz_write, pool)); +      fb->checked_write = TRUE; +    } -  return svn_fs_apply_textdelta(handler, handler_baton, -                                fb->edit_baton->txn_root, -                                fb->path, -                                base_checksum, -                                NULL, -                                pool); +  return svn_error_trace( +          svn_fs_apply_textdelta(handler, handler_baton, +                                 eb->txn_root, +                                 fb->path, +                                 base_checksum, +                                 NULL, +                                 pool));  } @@ -590,8 +626,9 @@ open_file(const char *path,    /* If the node our caller has is an older revision number than the       one in our transaction, return an out-of-dateness error. */ -  if (SVN_IS_VALID_REVNUM(base_revision) && (base_revision < cr_rev)) -    return svn_error_trace(out_of_date(full_path, svn_node_file)); +  if (SVN_IS_VALID_REVNUM(base_revision)) +    SVN_ERR(check_out_of_date(eb, full_path, svn_node_file, +                              base_revision, cr_rev));    /* Build a new file baton */    new_fb = apr_pcalloc(pool, sizeof(*new_fb)); @@ -616,9 +653,13 @@ change_file_prop(void *file_baton,    struct file_baton *fb = file_baton;    struct edit_baton *eb = fb->edit_baton; -  /* Check for write authorization. */ -  SVN_ERR(check_authz(eb, fb->path, eb->txn_root, -                      svn_authz_write, pool)); +  if (!fb->checked_write) +    { +      /* Check for write authorization. */ +      SVN_ERR(check_authz(eb, fb->path, eb->txn_root, +                          svn_authz_write, pool)); +      fb->checked_write = TRUE; +    }    return svn_repos_fs_change_node_prop(eb->txn_root, fb->path,                                         name, value, pool); @@ -663,19 +704,24 @@ change_dir_prop(void *dir_baton,    struct edit_baton *eb = db->edit_baton;    /* Check for write authorization. */ -  SVN_ERR(check_authz(eb, db->path, eb->txn_root, -                      svn_authz_write, pool)); - -  if (SVN_IS_VALID_REVNUM(db->base_rev)) +  if (!db->checked_write)      { -      /* Subversion rule:  propchanges can only happen on a directory -         which is up-to-date. */ -      svn_revnum_t created_rev; -      SVN_ERR(svn_fs_node_created_rev(&created_rev, -                                      eb->txn_root, db->path, pool)); - -      if (db->base_rev < created_rev) -        return svn_error_trace(out_of_date(db->path, svn_node_dir)); +      SVN_ERR(check_authz(eb, db->path, eb->txn_root, +                          svn_authz_write, pool)); + +      if (SVN_IS_VALID_REVNUM(db->base_rev)) +        { +          /* Subversion rule:  propchanges can only happen on a directory +             which is up-to-date. */ +          svn_revnum_t created_rev; +          SVN_ERR(svn_fs_node_created_rev(&created_rev, +                                          eb->txn_root, db->path, pool)); + +          SVN_ERR(check_out_of_date(eb, db->path, svn_node_dir, +                                    db->base_rev, created_rev)); +        } + +      db->checked_write = TRUE; /* Skip on further prop changes */      }    return svn_repos_fs_change_node_prop(eb->txn_root, db->path,  | 
