1/* checksum-reps-table.c : operations on the `checksum-reps' table
2 *
3 * ====================================================================
4 *    Licensed to the Apache Software Foundation (ASF) under one
5 *    or more contributor license agreements.  See the NOTICE file
6 *    distributed with this work for additional information
7 *    regarding copyright ownership.  The ASF licenses this file
8 *    to you under the Apache License, Version 2.0 (the
9 *    "License"); you may not use this file except in compliance
10 *    with the License.  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 *    Unless required by applicable law or agreed to in writing,
15 *    software distributed under the License is distributed on an
16 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 *    KIND, either express or implied.  See the License for the
18 *    specific language governing permissions and limitations
19 *    under the License.
20 * ====================================================================
21 */
22
23#include <apr_strings.h>
24
25#include "bdb_compat.h"
26#include "../fs.h"
27#include "../err.h"
28#include "../key-gen.h"
29#include "dbt.h"
30#include "../trail.h"
31#include "bdb-err.h"
32#include "../../libsvn_fs/fs-loader.h"
33#include "checksum-reps-table.h"
34
35#include "svn_private_config.h"
36
37
38int svn_fs_bdb__open_checksum_reps_table(DB **checksum_reps_p,
39                                         DB_ENV *env,
40                                         svn_boolean_t create)
41{
42  const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0);
43  DB *checksum_reps;
44  int error;
45
46  BDB_ERR(svn_fs_bdb__check_version());
47  BDB_ERR(db_create(&checksum_reps, env, 0));
48  error = (checksum_reps->open)(SVN_BDB_OPEN_PARAMS(checksum_reps, NULL),
49                                "checksum-reps", 0, DB_BTREE,
50                                open_flags, 0666);
51
52  /* Create the checksum-reps table if it doesn't exist. */
53  if (error == ENOENT && (! create))
54    {
55      BDB_ERR(checksum_reps->close(checksum_reps, 0));
56      return svn_fs_bdb__open_checksum_reps_table(checksum_reps_p, env, TRUE);
57    }
58
59  /* Create the initial `next-key' table entry.  */
60  if (create)
61    {
62      DBT key, value;
63      BDB_ERR(checksum_reps->put(checksum_reps, 0,
64                                 svn_fs_base__str_to_dbt(&key, NEXT_KEY_KEY),
65                                 svn_fs_base__str_to_dbt(&value, "0"), 0));
66    }
67
68  BDB_ERR(error);
69
70  *checksum_reps_p = checksum_reps;
71  return 0;
72}
73
74svn_error_t *svn_fs_bdb__get_checksum_rep(const char **rep_key,
75                                          svn_fs_t *fs,
76                                          svn_checksum_t *checksum,
77                                          trail_t *trail,
78                                          apr_pool_t *pool)
79{
80  base_fs_data_t *bfd = fs->fsap_data;
81  DBT key, value;
82  int db_err;
83
84  /* We only allow SHA1 checksums in this table. */
85  if (checksum->kind != svn_checksum_sha1)
86    return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL,
87                            _("Only SHA1 checksums can be used as keys in the "
88                              "checksum-reps table.\n"));
89
90  svn_fs_base__trail_debug(trail, "checksum-reps", "get");
91  db_err = bfd->checksum_reps->get(bfd->checksum_reps, trail->db_txn,
92                                   svn_fs_base__checksum_to_dbt(&key, checksum),
93                                   svn_fs_base__result_dbt(&value), 0);
94  svn_fs_base__track_dbt(&value, pool);
95
96  if (db_err == DB_NOTFOUND)
97    return svn_fs_base__err_no_such_checksum_rep(fs, checksum);
98
99  *rep_key = apr_pstrmemdup(pool, value.data, value.size);
100  return SVN_NO_ERROR;
101}
102
103svn_error_t *svn_fs_bdb__set_checksum_rep(svn_fs_t *fs,
104                                          svn_checksum_t *checksum,
105                                          const char *rep_key,
106                                          trail_t *trail,
107                                          apr_pool_t *pool)
108{
109  base_fs_data_t *bfd = fs->fsap_data;
110  DBT key, value;
111  int db_err;
112
113  /* We only allow SHA1 checksums in this table. */
114  if (checksum->kind != svn_checksum_sha1)
115    return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL,
116                            _("Only SHA1 checksums can be used as keys in the "
117                              "checksum-reps table.\n"));
118
119  /* Create a key from our CHECKSUM. */
120  svn_fs_base__checksum_to_dbt(&key, checksum);
121
122  /* Check to see if we already have a mapping for CHECKSUM.  If so,
123     and the value is the same one we were about to write, that's
124     cool -- just do nothing.  If, however, the value is *different*,
125     that's a red flag!  */
126  svn_fs_base__trail_debug(trail, "checksum-reps", "get");
127  db_err = bfd->checksum_reps->get(bfd->checksum_reps, trail->db_txn,
128                                   &key, svn_fs_base__result_dbt(&value), 0);
129  svn_fs_base__track_dbt(&value, pool);
130  if (db_err != DB_NOTFOUND)
131    {
132      const char *sum_str = svn_checksum_to_cstring_display(checksum, pool);
133      return svn_error_createf
134        (SVN_ERR_FS_ALREADY_EXISTS, NULL,
135         _("Representation key for checksum '%s' exists in filesystem '%s'."),
136         sum_str, fs->path);
137    }
138
139  /* Create a value from our REP_KEY, and add this record to the table. */
140  svn_fs_base__str_to_dbt(&value, rep_key);
141  svn_fs_base__trail_debug(trail, "checksum-reps", "put");
142  SVN_ERR(BDB_WRAP(fs, N_("storing checksum-reps record"),
143                   bfd->checksum_reps->put(bfd->checksum_reps, trail->db_txn,
144                                           &key, &value, 0)));
145  return SVN_NO_ERROR;
146}
147
148svn_error_t *svn_fs_bdb__delete_checksum_rep(svn_fs_t *fs,
149                                             svn_checksum_t *checksum,
150                                             trail_t *trail,
151                                             apr_pool_t *pool)
152{
153  base_fs_data_t *bfd = fs->fsap_data;
154  DBT key;
155
156  /* We only allow SHA1 checksums in this table. */
157  if (checksum->kind != svn_checksum_sha1)
158    return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL,
159                            _("Only SHA1 checksums can be used as keys in the "
160                              "checksum-reps table.\n"));
161
162  svn_fs_base__checksum_to_dbt(&key, checksum);
163  svn_fs_base__trail_debug(trail, "checksum-reps", "del");
164  SVN_ERR(BDB_WRAP(fs, N_("deleting entry from 'checksum-reps' table"),
165                   bfd->checksum_reps->del(bfd->checksum_reps,
166                                           trail->db_txn, &key, 0)));
167  return SVN_NO_ERROR;
168}
169
170svn_error_t *svn_fs_bdb__reserve_rep_reuse_id(const char **id_p,
171                                              svn_fs_t *fs,
172                                              trail_t *trail,
173                                              apr_pool_t *pool)
174{
175  base_fs_data_t *bfd = fs->fsap_data;
176  DBT query, result;
177  apr_size_t len;
178  char next_key[MAX_KEY_SIZE];
179  int db_err;
180
181  svn_fs_base__str_to_dbt(&query, NEXT_KEY_KEY);
182
183  /* Get the current value associated with the `next-key' key in the
184     `checksum-reps' table.  */
185  svn_fs_base__trail_debug(trail, "checksum-reps", "get");
186  SVN_ERR(BDB_WRAP(fs, N_("allocating new representation reuse ID "
187                         "(getting 'next-key')"),
188                   bfd->checksum_reps->get(bfd->checksum_reps, trail->db_txn,
189                                           &query,
190                                           svn_fs_base__result_dbt(&result),
191                                           0)));
192  svn_fs_base__track_dbt(&result, pool);
193
194  /* Set our return value. */
195  *id_p = apr_pstrmemdup(pool, result.data, result.size);
196
197  /* Bump to future key. */
198  len = result.size;
199  svn_fs_base__next_key(result.data, &len, next_key);
200  svn_fs_base__trail_debug(trail, "checksum_reps", "put");
201  db_err = bfd->checksum_reps->put(bfd->checksum_reps, trail->db_txn,
202                                   svn_fs_base__str_to_dbt(&query,
203                                                           NEXT_KEY_KEY),
204                                   svn_fs_base__str_to_dbt(&result, next_key),
205                                   0);
206
207  return BDB_WRAP(fs, N_("bumping next representation reuse ID"), db_err);
208}
209