1289177Speter/*
2289177Speter * config_pool.c :  pool of configuration objects
3289177Speter *
4289177Speter * ====================================================================
5289177Speter *    Licensed to the Apache Software Foundation (ASF) under one
6289177Speter *    or more contributor license agreements.  See the NOTICE file
7289177Speter *    distributed with this work for additional information
8289177Speter *    regarding copyright ownership.  The ASF licenses this file
9289177Speter *    to you under the Apache License, Version 2.0 (the
10289177Speter *    "License"); you may not use this file except in compliance
11289177Speter *    with the License.  You may obtain a copy of the License at
12289177Speter *
13289177Speter *      http://www.apache.org/licenses/LICENSE-2.0
14289177Speter *
15289177Speter *    Unless required by applicable law or agreed to in writing,
16289177Speter *    software distributed under the License is distributed on an
17289177Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18289177Speter *    KIND, either express or implied.  See the License for the
19289177Speter *    specific language governing permissions and limitations
20289177Speter *    under the License.
21289177Speter * ====================================================================
22289177Speter */
23289177Speter
24289177Speter
25289177Speter
26289177Speter
27289177Speter#include "svn_checksum.h"
28289177Speter#include "svn_path.h"
29289177Speter#include "svn_pools.h"
30289177Speter
31289177Speter#include "private/svn_subr_private.h"
32289177Speter#include "private/svn_repos_private.h"
33289177Speter
34289177Speter#include "svn_private_config.h"
35289177Speter
36362181Sdim#include "config_file.h"
37289177Speter
38289177Speter
39289177Speter/* Return a memory buffer structure allocated in POOL and containing the
40289177Speter * data from CHECKSUM.
41289177Speter */
42289177Speterstatic svn_membuf_t *
43289177Speterchecksum_as_key(svn_checksum_t *checksum,
44289177Speter                apr_pool_t *pool)
45289177Speter{
46289177Speter  svn_membuf_t *result = apr_pcalloc(pool, sizeof(*result));
47289177Speter  apr_size_t size = svn_checksum_size(checksum);
48289177Speter
49289177Speter  svn_membuf__create(result, size, pool);
50289177Speter  result->size = size; /* exact length is required! */
51289177Speter  memcpy(result->data, checksum->digest, size);
52289177Speter
53289177Speter  return result;
54289177Speter}
55289177Speter
56362181Sdim/* Set *CFG to the configuration serialized in STREAM and cache it in
57362181Sdim * CONFIG_POOL under CHECKSUM.  The configuration will only be parsed if
58362181Sdim * we can't find it the CONFIG_POOL already.
59289177Speter *
60289177Speter * RESULT_POOL determines the lifetime of the returned reference and
61289177Speter * SCRATCH_POOL is being used for temporary allocations.
62289177Speter */
63289177Speterstatic svn_error_t *
64362181Sdimfind_config(svn_config_t **cfg,
65362181Sdim            svn_repos__config_pool_t *config_pool,
66362181Sdim            svn_stream_t *stream,
67362181Sdim            svn_checksum_t *checksum,
68362181Sdim            apr_pool_t *result_pool,
69362181Sdim            apr_pool_t *scratch_pool)
70289177Speter{
71362181Sdim  /* First, attempt the cache lookup. */
72362181Sdim  svn_membuf_t *key = checksum_as_key(checksum, scratch_pool);
73362181Sdim  SVN_ERR(svn_object_pool__lookup((void **)cfg, config_pool, key,
74362181Sdim                                  result_pool));
75289177Speter
76362181Sdim  /* Not found? => parse and cache */
77289177Speter  if (!*cfg)
78289177Speter    {
79362181Sdim      svn_config_t *config;
80289177Speter
81362181Sdim      /* create a pool for the new config object and parse the data into it */
82362181Sdim      apr_pool_t *cfg_pool = svn_object_pool__new_item_pool(config_pool);
83362181Sdim      SVN_ERR(svn_config_parse(&config, stream, FALSE, FALSE, cfg_pool));
84289177Speter
85362181Sdim      /* switch config data to r/o mode to guarantee thread-safe access */
86362181Sdim      svn_config__set_read_only(config, cfg_pool);
87289177Speter
88362181Sdim      /* add config in pool, handle loads races and return the right config */
89362181Sdim      SVN_ERR(svn_object_pool__insert((void **)cfg, config_pool, key,
90362181Sdim                                      config, cfg_pool, result_pool));
91289177Speter    }
92289177Speter
93289177Speter  return SVN_NO_ERROR;
94289177Speter}
95289177Speter
96289177Speter/* API implementation */
97289177Speter
98289177Spetersvn_error_t *
99289177Spetersvn_repos__config_pool_create(svn_repos__config_pool_t **config_pool,
100289177Speter                              svn_boolean_t thread_safe,
101289177Speter                              apr_pool_t *pool)
102289177Speter{
103362181Sdim  return svn_error_trace(svn_object_pool__create(config_pool,
104362181Sdim                                                 thread_safe, pool));
105289177Speter}
106289177Speter
107289177Spetersvn_error_t *
108289177Spetersvn_repos__config_pool_get(svn_config_t **cfg,
109289177Speter                           svn_repos__config_pool_t *config_pool,
110289177Speter                           const char *path,
111289177Speter                           svn_boolean_t must_exist,
112289177Speter                           svn_repos_t *preferred_repos,
113289177Speter                           apr_pool_t *pool)
114289177Speter{
115289177Speter  svn_error_t *err = SVN_NO_ERROR;
116289177Speter  apr_pool_t *scratch_pool = svn_pool_create(pool);
117362181Sdim  config_access_t *access = svn_repos__create_config_access(preferred_repos,
118362181Sdim                                                            scratch_pool);
119362181Sdim  svn_stream_t *stream;
120362181Sdim  svn_checksum_t *checksum;
121289177Speter
122362181Sdim  *cfg = NULL;
123362181Sdim  err = svn_repos__get_config(&stream, &checksum, access, path, must_exist,
124362181Sdim                              scratch_pool);
125362181Sdim  if (!err)
126362181Sdim    err = svn_error_quick_wrapf(find_config(cfg, config_pool, stream,
127362181Sdim                                            checksum, pool, scratch_pool),
128362181Sdim                                "Error while parsing config file: '%s':",
129362181Sdim                                path);
130289177Speter
131362181Sdim  /* Let the standard implementation handle all the difficult cases.
132362181Sdim   * Note that for in-repo configs, there are no further special cases to
133362181Sdim   * check for and deal with. */
134362181Sdim  if (!*cfg && !svn_path_is_url(path))
135289177Speter    {
136362181Sdim      svn_error_clear(err);
137362181Sdim      err = svn_config_read3(cfg, path, must_exist, FALSE, FALSE, pool);
138289177Speter    }
139289177Speter
140362181Sdim  svn_repos__destroy_config_access(access);
141289177Speter  svn_pool_destroy(scratch_pool);
142289177Speter
143362181Sdim  /* we need to duplicate the root structure as it contains temp. buffers */
144362181Sdim  if (*cfg)
145362181Sdim    *cfg = svn_config__shallow_copy(*cfg, pool);
146362181Sdim
147362181Sdim  return svn_error_trace(err);
148289177Speter}
149