⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 repos.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 5 页
字号:
                                        const char *root_path,
                                        const char *label,
                                        int use_checked_in,
                                        dav_resource **resource)
{
  const char *fs_path;
  const char *repo_name;
  const char *xslt_uri;
  const char *fs_parent_path;
  dav_resource_combined *comb;
  dav_svn_repos *repos;
  const char *cleaned_uri;
  const char *repos_name;
  const char *relative;
  const char *repos_path;
  const char *repos_key;
  const char *version_name;
  svn_error_t *serr;
  dav_error *err;
  int had_slash;

  repo_name = dav_svn_get_repo_name(r);
  xslt_uri = dav_svn_get_xslt_uri(r);

  /* This does all the work of interpreting/splitting the request uri. */
  err = dav_svn_split_uri (r, r->uri, root_path,
                           &cleaned_uri, &had_slash, 
                           &repos_name, &relative, &repos_path);
  if (err)
    return err;

  /* The path that we will eventually try to open as an svn
     repository.  Normally defined by the SVNPath directive. */
  fs_path = dav_svn_get_fs_path(r);

  /* If the SVNParentPath directive was used instead... */
  fs_parent_path = dav_svn_get_fs_parent_path(r);
  if (fs_parent_path != NULL)
    {      
      /* ...then the URL to the repository is actually one implicit
         component longer... */
      root_path = svn_path_join(root_path, repos_name, r->pool);
      /* ...and we need to specify exactly what repository to open. */
      fs_path = svn_path_join(fs_parent_path, repos_name, r->pool);
    }

  /* Start building and filling a 'combination' object. */
  comb = apr_pcalloc(r->pool, sizeof(*comb));
  comb->res.info = &comb->priv;
  comb->res.hooks = &dav_svn_hooks_repos;
  comb->res.pool = r->pool;
  comb->res.uri = cleaned_uri;

  /* Original request, off which to generate subrequests later. */
  comb->priv.r = r;

  /* ### ugly hack to carry over Content-Type data to the open_stream, which
     ### does not have access to the request headers. */
  {
    const char *ct = apr_table_get(r->headers_in, "content-type");

    comb->priv.is_svndiff =
      ct != NULL
      && strcmp(ct, SVN_SVNDIFF_MIME_TYPE) == 0;
  }

  /* ### and another hack for computing diffs to send to the client */
  comb->priv.delta_base = apr_table_get(r->headers_in,
                                        SVN_DAV_DELTA_BASE_HEADER);

  /* Gather any options requested by an svn client. */
  comb->priv.svn_client_options = apr_table_get(r->headers_in,
                                                SVN_DAV_OPTIONS_HEADER);

  /* See if the client sent a custom 'version name' request header. */
  version_name = apr_table_get(r->headers_in, SVN_DAV_VERSION_NAME_HEADER);
  comb->priv.version_name 
    = version_name ? SVN_STR_TO_REV(version_name): SVN_INVALID_REVNUM;

  /* Remember checksums, if any. */
  comb->priv.base_checksum =
    apr_table_get (r->headers_in, SVN_DAV_BASE_FULLTEXT_MD5_HEADER);
  comb->priv.result_checksum =
    apr_table_get (r->headers_in, SVN_DAV_RESULT_FULLTEXT_MD5_HEADER);

  /* "relative" is part of the "uri" string, so it has the proper
     lifetime to store here. */
  /* ### that comment no longer applies. we're creating a string with its
     ### own lifetime now. so WHY are we using a string? hmm... */
  comb->priv.uri_path = svn_stringbuf_create(relative, r->pool);

  /* initialize this until we put something real here */
  comb->priv.root.rev = SVN_INVALID_REVNUM;

  /* create the repository structure and stash it away */
  repos = apr_pcalloc(r->pool, sizeof(*repos));
  repos->pool = r->pool;

  comb->priv.repos = repos;

  /* We are assuming the root_path will live at least as long as this
     resource. Considering that it typically comes from the per-dir
     config in mod_dav, this is valid for now. */
  repos->root_path = svn_path_uri_encode(root_path, r->pool);

  /* where is the SVN FS for this resource? */
  repos->fs_path = fs_path;

  /* A name for the repository */
  repos->repo_name = repo_name;

  /* An XSL transformation */
  repos->xslt_uri = xslt_uri;

  /* Is autoversioning active in this repos? */
  repos->autoversioning = dav_svn_get_autoversioning_flag(r);

  /* Remember various bits for later URL construction */
  repos->base_url = ap_construct_url(r->pool, "", r);
  repos->special_uri = dav_svn_get_special_uri(r);

  /* Remember who is making this request */
  repos->username = r->user;

  /* Retrieve/cache open repository */
  repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, NULL);
  apr_pool_userdata_get((void **)&repos->repos, repos_key, r->connection->pool);
  if (repos->repos == NULL)
    {
      serr = svn_repos_open(&(repos->repos), fs_path, r->connection->pool);
      if (serr != NULL)
        {
          /* The error returned by svn_repos_open might contain the
             actual path to the failed repository.  We don't want to
             leak that path back to the client, because that would be
             a security risk, but we do want to log the real error on
             the server side. */
          const char *new_msg = "Could not open the requested SVN filesystem";
          svn_error_t *sanitized_error = svn_error_create(serr->apr_err,
                                                          NULL, new_msg);

          ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
                        "%s", serr->message);

          /* Return a slightly less informative error to dav. */
          svn_error_clear(serr);
          return dav_svn_convert_err (sanitized_error,
                                      HTTP_INTERNAL_SERVER_ERROR,
                                      apr_psprintf(r->pool, new_msg),
                                      r->pool);
        }

      /* Cache the open repos for the next request on this connection */
      apr_pool_userdata_set(repos->repos, repos_key,
                            NULL, r->connection->pool);
    }

  /* cache the filesystem object */
  repos->fs = svn_repos_fs (repos->repos);

  /* capture warnings during cleanup of the FS */
  svn_fs_set_warning_func(repos->fs, log_warning, r);

  /* Figure out the type of the resource. Note that we have a PARSE step
     which is separate from a PREP step. This is because the PARSE can
     map multiple URLs to the same resource type. The PREP operates on
     the type of the resource. */

  /* skip over the leading "/" in the relative URI */
  if (dav_svn_parse_uri(comb, relative + 1, label, use_checked_in))
    goto malformed_URI;

#ifdef SVN_DEBUG
  if (comb->res.type == DAV_RESOURCE_TYPE_UNKNOWN)
    {
      /* Unknown URI. Return NULL to indicate "no resource" */
      DBG0("DESIGN FAILURE: should not be UNKNOWN at this point");
      *resource = NULL;
      return NULL;
    }
#endif

  /* prepare the resource for operation */
  if ((err = dav_svn_prep_resource(comb)) != NULL)
    return err;

  /* a GET request for a REGULAR collection resource MUST have a trailing
     slash. Redirect to include one if it does not. */
  if (comb->res.collection && comb->res.type == DAV_RESOURCE_TYPE_REGULAR
      && !had_slash && r->method_number == M_GET)
    {
      /* note that we drop r->args. we don't deal with them anyways */
      const char *new_path = apr_pstrcat(r->pool,
                                         ap_escape_uri(r->pool, r->uri),
                                         "/",
                                         NULL);
      apr_table_setn(r->headers_out, "Location",
                     ap_construct_url(r->pool, new_path, r));
      return dav_new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
                           "Requests for a collection must have a "
                           "trailing slash on the URI.");
    }

  *resource = &comb->res;
  return NULL;

 malformed_URI:
  /* A malformed URI error occurs when a URI indicates the "special" area,
     yet it has an improper construction. Generally, this is because some
     doofus typed it in manually or has a buggy client. */
  /* ### pick something other than HTTP_INTERNAL_SERVER_ERROR */
  /* ### are SVN_ERR_APMOD codes within the right numeric space? */
  return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
                       SVN_ERR_APMOD_MALFORMED_URI,
                       "The URI indicated a resource within Subversion's "
                       "special resource area, but does not exist. This is "
                       "generally caused by a problem in the client "
                       "software.");
}

static dav_error * dav_svn_get_parent_resource(const dav_resource *resource,
                                               dav_resource **parent_resource)
{
  svn_stringbuf_t *path = resource->info->uri_path;

  /* the root of the repository has no parent */
  if (path->len == 1 && *path->data == '/')
    {
      *parent_resource = NULL;
      return NULL;
    }

  switch (resource->type)
    {
    case DAV_RESOURCE_TYPE_WORKING:
    case DAV_RESOURCE_TYPE_REGULAR:
      /* The "/" occurring within the URL of working resources is part of
         its identifier; it does not establish parent resource relationships.
         All working resources have the same parent, which is:
         http://host.name/path2repos/$svn/wrk/
      */
      *parent_resource =
        dav_svn_create_private_resource(resource,
                                        DAV_SVN_RESTYPE_WRK_COLLECTION);
      break;

    case DAV_RESOURCE_TYPE_ACTIVITY:
      *parent_resource =
        dav_svn_create_private_resource(resource,
                                        DAV_SVN_RESTYPE_ACT_COLLECTION);
      break;

    default:
      /* ### needs more work. need parents for other resource types
         ###
         ### return an error so we can easily identify the cases where
         ### we've called this function unexpectedly. */
      return dav_new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
                           apr_psprintf(resource->pool,
                                        "get_parent_resource was called for "
                                        "%s (type %d)",
                                        resource->uri, resource->type));
      break;
    }

  return NULL;
}

/* does RES2 live in the same repository as RES1? */
static int is_our_resource(const dav_resource *res1,
                           const dav_resource *res2)
{
  if (res1->hooks != res2->hooks
      || strcmp(res1->info->repos->fs_path, res2->info->repos->fs_path) != 0)
    {
      /* a different provider, or a different FS repository */
      return 0;
    }

  /* coalesce the repository */
  if (res1->info->repos != res2->info->repos)
    {      
      /* ### might be nice to have a pool which we can clear to toss
         ### out the old, redundant repos/fs.  */

      /* have res2 point to res1's filesystem */
      res2->info->repos = res1->info->repos;

      /* res2's fs_root object is now invalid.  regenerate it using
         the now-shared filesystem. */
      if (res2->info->root.txn_name)
        {
          /* reopen the txn by name */
          svn_error_clear (svn_fs_open_txn(&(res2->info->root.txn),
                                           res2->info->repos->fs,
                                           res2->info->root.txn_name,
                                           res2->info->repos->pool));

          /* regenerate the txn "root" object */
          svn_error_clear (svn_fs_txn_root(&(res2->info->root.root),
                                           res2->info->root.txn,
                                           res2->info->repos->pool));
        }
      else if (res2->info->root.rev)
        {
          /* default:  regenerate the revision "root" object */
          svn_error_clear (svn_fs_revision_root(&(res2->info->root.root),
                                                res2->info->repos->fs,
                                                res2->info->root.rev,
                                                res2->info->repos->pool));
        }
    }

  return 1;
}

static int dav_svn_is_same_resource(const dav_resource *res1,
                                    const dav_resource *res2)
{
  if (!is_our_resource(res1, res2))
    return 0;

  /* ### what if the same resource were reached via two URIs? */

  return svn_stringbuf_compare(res1->info->uri_path, res2->info->uri_path);
}

static int dav_svn_is_parent_resource(const dav_resource *res1,
                                      const dav_resource *res2)
{
  apr_size_t len1 = strlen(res1->info->uri_path->data);
  apr_size_t len2;

  if (!is_our_resource(res1, res2))
    return 0;

  /* ### what if a resource were reached via two URIs? we ought to define
     ### parent/child relations for resources independent of URIs.
     ### i.e. define a "canonical" location for each resource, then return
     ### the parent based on that location. */

  /* res2 is one of our resources, we can use its ->info ptr */
  len2 = strlen(res2->info->uri_path->data);

  return (len2 > len1
          && memcmp(res1->info->uri_path->data, res2->info->uri_path->data,
                    len1) == 0
          && res2->info->uri_path->data[len1] == '/');
}


dav_error * dav_svn_resource_kind (request_rec *r,
                                   const char *uri,
                                   const char *root_path,
                                   svn_node_kind_t *kind)
{
  dav_error *derr;
  svn_error_t *serr;
  dav_resource *resource;
  svn_revnum_t base_rev;
  svn_fs_root_t *base_rev_root;
  char *saved_uri;

  /* Temporarily insert the uri that the user actually wants us to
     convert into a resource.  Typically, this is already r->uri, so
     this is usually a no-op.  But sometimes the caller may pass in
     the Destination: header uri.

     ### WHAT WE REALLY WANT here is to refactor dav_svn_get_resource,
     so that some alternate interface actually allows us to specify
     the URI to process, i.e. not always process r->uri.
  */
  saved_uri = r->uri;

⌨️ 快捷键说明

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