commit.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,333 行 · 第 1/4 页

C
1,333
字号
/*
 * commit.c :  routines for committing changes to the server
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */



#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_uuid.h>
#include <apr_portable.h>

#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#include <apr_want.h>

#if APR_HAVE_STDLIB
#include <stdlib.h>     /* for free() */
#endif
#include <assert.h>

#include <ne_socket.h>
#include <ne_request.h>
#include <ne_props.h>
#include <ne_basic.h>

#include "svn_pools.h"
#include "svn_error.h"
#include "svn_delta.h"
#include "svn_io.h"
#include "svn_ra.h"
#include "svn_path.h"
#include "svn_xml.h"
#include "svn_dav.h"
#include "svn_base64.h"

#include "svn_private_config.h"

#include "ra_dav.h"


/*
** resource_t: identify the relevant pieces of a resource on the server
**
** REVISION is the resource's revision, or SVN_INVALID_REVNUM if it is
** new or is the HEAD.
**
** URL refers to the public/viewable/original resource.
** VSN_URL refers to the version resource that we stored locally
** WR_URL refers to a working resource for this resource
**
** Note that VSN_URL is NULL if this resource has just been added, and
** WR_URL can be NULL if the resource has not (yet) been checked out.
**
** LOCAL_PATH is relative to the root of the commit. It will be used
** for the get_func, push_func, and close_func callbacks.
*/
typedef struct
{
  svn_revnum_t revision;
  const char *url;
  const char *vsn_url;
  const char *wr_url;
  const char *local_path;
  apr_pool_t *pool; /* pool in which this resource is allocated. */

} resource_t;

typedef struct
{
  svn_ra_session_t *ras;
  const char *activity_url;

  apr_hash_t *valid_targets;

  svn_ra_get_wc_prop_func_t get_func;
  svn_ra_push_wc_prop_func_t push_func;
  void *cb_baton;

  svn_boolean_t disable_merge_response;

  /* The (potential) author of this commit. */
  const char *user;

  /* Log message for the commit. */
  const char *log_msg;

  /* The commit callback and baton */
  svn_commit_callback_t callback;
  void *callback_baton;
} commit_ctx_t;

typedef struct
{
  apr_file_t *tmpfile;
  svn_stringbuf_t *fname;
  const char *base_checksum;    /* hex md5 of base text; may be null */
} put_baton_t;

typedef struct
{
  commit_ctx_t *cc;
  resource_t *rsrc;
  apr_hash_t *prop_changes; /* name/values pairs of new/changed properties. */
  apr_array_header_t *prop_deletes; /* names of properties to delete. */
  svn_boolean_t created; /* set if this is an add rather than an update */
  apr_pool_t *pool; /* the pool from open_foo() / add_foo() */
  put_baton_t *put_baton;  /* baton for this file's PUT request */
} resource_baton_t;

/* this property will be fetched from the server when we don't find it
   cached in the WC property store. */
static const ne_propname fetch_props[] =
{
  { "DAV:", "checked-in" },
  { NULL }
};

static const ne_propname log_message_prop = { SVN_DAV_PROP_NS_SVN, "log" };

/* perform a deep copy of BASE into POOL, and return the result. */
static resource_t * dup_resource(resource_t *base, apr_pool_t *pool)
{
  resource_t *rsrc = apr_pcalloc(pool, sizeof(*rsrc));
  rsrc->pool = pool;
  rsrc->revision = base->revision;
  rsrc->url = base->url ?
    apr_pstrdup(pool, base->url) : NULL;
  rsrc->vsn_url = base->vsn_url ?
    apr_pstrdup(pool, base->vsn_url) : NULL;
  rsrc->wr_url = base->wr_url ?
    apr_pstrdup(pool, base->wr_url) : NULL;
  rsrc->local_path = base->local_path ? 
    apr_pstrdup(pool, base->local_path) : NULL;
  return rsrc;
}

static svn_error_t * simple_request(svn_ra_session_t *ras, 
                                    const char *method,
                                    const char *url, 
                                    int *code,
                                    apr_hash_t *extra_headers,
                                    int okay_1, 
                                    int okay_2, 
                                    apr_pool_t *pool)
{
  ne_request *req;

  /* create/prep the request */
  req = ne_request_create(ras->sess, method, url);
  if (req == NULL)
    {
      return svn_error_createf(SVN_ERR_RA_DAV_CREATING_REQUEST, NULL,
                               _("Could not create a request (%s '%s')"),
                               method, url);
    }

  /* add any extra headers passed in by caller. */
  if (extra_headers != NULL)
    {
      apr_hash_index_t *hi;
      for (hi = apr_hash_first(pool, extra_headers);
           hi; hi = apr_hash_next(hi))
        {
          const void *key;
          void *val;
          apr_hash_this(hi, &key, NULL, &val);
          ne_add_request_header(req, (const char *) key, (const char *) val); 
        }
    }

  /* run the request and get the resulting status code (and svn_error_t) */
  SVN_ERR( svn_ra_dav__request_dispatch(code, req, ras->sess,
                                        method, url, okay_1, okay_2,
                                        pool) );

  return SVN_NO_ERROR;
}


static svn_error_t * delete_activity(void *edit_baton,
                                     apr_pool_t *pool)
{
  commit_ctx_t *cc = edit_baton;
  return simple_request(cc->ras, "DELETE", cc->activity_url, NULL,
                        NULL, 204 /* No Content */, 404 /* Not Found */, pool);
}


/* Get the version resource URL for RSRC, storing it in
   RSRC->vsn_url.  Use POOL for all temporary allocations. */
static svn_error_t * get_version_url(commit_ctx_t *cc,
                                     resource_t *rsrc,
                                     svn_boolean_t force,
                                     apr_pool_t *pool)
{
  svn_ra_dav_resource_t *propres;
  const char *url;
  const svn_string_t *url_str;

  if (!force && cc->get_func != NULL)
    {
      const svn_string_t *vsn_url_value;

      SVN_ERR( (*cc->get_func)(cc->cb_baton,
                               rsrc->local_path,
                               SVN_RA_DAV__LP_VSN_URL,
                               &vsn_url_value,
                               pool) );
      if (vsn_url_value != NULL)
        {
          rsrc->vsn_url = apr_pstrdup (rsrc->pool, vsn_url_value->data);
          return SVN_NO_ERROR;
        }

      /* whoops. it wasn't there. go grab it from the server. */
    }

  if (rsrc->revision == SVN_INVALID_REVNUM)
    {
      /* We aren't trying to get a specific version -- use the HEAD. We
         fetch the version URL from the public URL. */
      url = rsrc->url;
    }
  else
    {
      svn_string_t bc_url;
      svn_string_t bc_relative;

      /* The version URL comes from a resource in the Baseline Collection. */
      SVN_ERR( svn_ra_dav__get_baseline_info(NULL,
                                             &bc_url, &bc_relative, NULL,
                                             cc->ras->sess,
                                             rsrc->url,
                                             rsrc->revision,
                                             pool));

      url = svn_path_url_add_component(bc_url.data, bc_relative.data, pool);
    }

  /* Get the DAV:checked-in property, which contains the URL of the
     Version Resource */
  SVN_ERR( svn_ra_dav__get_props_resource(&propres, cc->ras->sess, url,
                                          NULL, fetch_props, pool) );
  url_str = apr_hash_get(propres->propset,
                         SVN_RA_DAV__PROP_CHECKED_IN,
                         APR_HASH_KEY_STRING);
  if (url_str == NULL)
    {
      /* ### need a proper SVN_ERR here */
      return svn_error_create(APR_EGENERAL, NULL,
                              "Could not fetch the Version Resource URL "
                              "(needed during an import or when it is "
                              "missing from the local, cached props)");
    }

  /* ensure we get the proper lifetime for this URL since it is going into
     a resource object. */
  rsrc->vsn_url = apr_pstrdup(rsrc->pool, url_str->data);

  if (cc->push_func != NULL)
    {
      /* Now we can store the new version-url. */
      SVN_ERR( (*cc->push_func)(cc->cb_baton,
                                rsrc->local_path,
                                SVN_RA_DAV__LP_VSN_URL,
                                url_str,
                                pool) );
    }

  return SVN_NO_ERROR;
}

/* When FORCE is true, then we force a query to the server, ignoring any
   cached property. */
static svn_error_t * get_activity_collection(commit_ctx_t *cc,
                                             const svn_string_t **collection,
                                             svn_boolean_t force,
                                             apr_pool_t *pool)
{
  if (!force && cc->get_func != NULL)
    {
      /* with a get_func, we can just ask for the activity URL from the
         property store. */

      /* get the URL where we should create activities */
      SVN_ERR( (*cc->get_func)(cc->cb_baton,
                               "",
                               SVN_RA_DAV__LP_ACTIVITY_COLL,
                               collection,
                               pool) );

      if (*collection != NULL)
        {
          /* the property was there. return it. */
          return SVN_NO_ERROR;
        }

      /* property not found for some reason. get it from the server. */
    }

  /* use our utility function to fetch the activity URL */
  SVN_ERR( svn_ra_dav__get_activity_collection(collection,
                                               cc->ras,
                                               cc->ras->root.path,
                                               pool) );

  if (cc->push_func != NULL)
    {
      /* save the (new) activity collection URL into the directory */
      SVN_ERR( (*cc->push_func)(cc->cb_baton,
                               "",
                               SVN_RA_DAV__LP_ACTIVITY_COLL,
                               *collection,
                               pool) );
    }

  return SVN_NO_ERROR;
}

static svn_error_t * create_activity(commit_ctx_t *cc,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?