~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_fs_fs/rev_file.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* rev_file.c --- revision file and index access functions
 
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 "rev_file.h"
 
24
#include "fs_fs.h"
 
25
#include "index.h"
 
26
#include "low_level.h"
 
27
#include "util.h"
 
28
 
 
29
#include "../libsvn_fs/fs-loader.h"
 
30
 
 
31
#include "private/svn_io_private.h"
 
32
#include "svn_private_config.h"
 
33
 
 
34
/* Initialize the *FILE structure for REVISION in filesystem FS.  Set its
 
35
 * pool member to the provided POOL. */
 
36
static void
 
37
init_revision_file(svn_fs_fs__revision_file_t *file,
 
38
                   svn_fs_t *fs,
 
39
                   svn_revnum_t revision,
 
40
                   apr_pool_t *pool)
 
41
{
 
42
  fs_fs_data_t *ffd = fs->fsap_data;
 
43
 
 
44
  file->is_packed = svn_fs_fs__is_packed_rev(fs, revision);
 
45
  file->start_revision = svn_fs_fs__packed_base_rev(fs, revision);
 
46
 
 
47
  file->file = NULL;
 
48
  file->stream = NULL;
 
49
  file->p2l_stream = NULL;
 
50
  file->l2p_stream = NULL;
 
51
  file->block_size = ffd->block_size;
 
52
  file->l2p_offset = -1;
 
53
  file->l2p_checksum = NULL;
 
54
  file->p2l_offset = -1;
 
55
  file->p2l_checksum = NULL;
 
56
  file->footer_offset = -1;
 
57
  file->pool = pool;
 
58
}
 
59
 
 
60
/* Baton type for set_read_only() */
 
61
typedef struct set_read_only_baton_t
 
62
{
 
63
  /* File to set to read-only. */
 
64
  const char *file_path;
 
65
 
 
66
  /* Scratch pool sufficient life time.
 
67
   * Ideally the pool that we registered the cleanup on. */
 
68
  apr_pool_t *pool;
 
69
} set_read_only_baton_t;
 
70
 
 
71
/* APR pool cleanup callback taking a set_read_only_baton_t baton and then
 
72
 * (trying to) set the specified file to r/o mode. */
 
73
static apr_status_t
 
74
set_read_only(void *baton)
 
75
{
 
76
  set_read_only_baton_t *ro_baton = baton;
 
77
  apr_status_t status = APR_SUCCESS;
 
78
  svn_error_t *err;
 
79
 
 
80
  err = svn_io_set_file_read_only(ro_baton->file_path, TRUE, ro_baton->pool);
 
81
  if (err)
 
82
    {
 
83
      status = err->apr_err;
 
84
      svn_error_clear(err);
 
85
    }
 
86
 
 
87
  return status;
 
88
}
 
89
 
 
90
/* If the file at PATH is read-only, attempt to make it writable.  The
 
91
 * original state will be restored with RESULT_POOL gets cleaned up.
 
92
 * SCRATCH_POOL is for temporary allocations. */
 
93
static svn_error_t *
 
94
auto_make_writable(const char *path,
 
95
                   apr_pool_t *result_pool,
 
96
                   apr_pool_t *scratch_pool)
 
97
{
 
98
  svn_boolean_t is_read_only;
 
99
  apr_finfo_t finfo;
 
100
 
 
101
  SVN_ERR(svn_io_stat(&finfo, path, SVN__APR_FINFO_READONLY, scratch_pool));
 
102
  SVN_ERR(svn_io__is_finfo_read_only(&is_read_only, &finfo, scratch_pool));
 
103
 
 
104
  if (is_read_only)
 
105
    {
 
106
      /* Tell the pool to restore the r/o state upon cleanup
 
107
         (assuming the file will still exist, failing silently otherwise). */
 
108
      set_read_only_baton_t *baton = apr_pcalloc(result_pool,
 
109
                                                  sizeof(*baton));
 
110
      baton->pool = result_pool;
 
111
      baton->file_path = apr_pstrdup(result_pool, path);
 
112
      apr_pool_cleanup_register(result_pool, baton,
 
113
                                set_read_only, apr_pool_cleanup_null);
 
114
 
 
115
      /* Finally, allow write access (undoing it has already been scheduled
 
116
         and is idempotent). */
 
117
      SVN_ERR(svn_io_set_file_read_write(path, FALSE, scratch_pool));
 
118
    }
 
119
 
 
120
  return SVN_NO_ERROR;
 
121
}
 
122
 
 
123
/* Core implementation of svn_fs_fs__open_pack_or_rev_file working on an
 
124
 * existing, initialized FILE structure.  If WRITABLE is TRUE, give write
 
125
 * access to the file - temporarily resetting the r/o state if necessary.
 
126
 */
 
127
static svn_error_t *
 
128
open_pack_or_rev_file(svn_fs_fs__revision_file_t *file,
 
129
                      svn_fs_t *fs,
 
130
                      svn_revnum_t rev,
 
131
                      svn_boolean_t writable,
 
132
                      apr_pool_t *result_pool,
 
133
                      apr_pool_t *scratch_pool)
 
134
{
 
135
  fs_fs_data_t *ffd = fs->fsap_data;
 
136
  svn_error_t *err;
 
137
  svn_boolean_t retry = FALSE;
 
138
 
 
139
  do
 
140
    {
 
141
      const char *path = svn_fs_fs__path_rev_absolute(fs, rev, scratch_pool);
 
142
      apr_file_t *apr_file;
 
143
      apr_int32_t flags = writable
 
144
                        ? APR_READ | APR_WRITE | APR_BUFFERED
 
145
                        : APR_READ | APR_BUFFERED;
 
146
 
 
147
      /* We may have to *temporarily* enable write access. */
 
148
      err = writable ? auto_make_writable(path, result_pool, scratch_pool)
 
149
                     : SVN_NO_ERROR;
 
150
 
 
151
      /* open the revision file in buffered r/o or r/w mode */
 
152
      if (!err)
 
153
        err = svn_io_file_open(&apr_file, path, flags, APR_OS_DEFAULT,
 
154
                               result_pool);
 
155
 
 
156
      if (!err)
 
157
        {
 
158
          file->file = apr_file;
 
159
          file->stream = svn_stream_from_aprfile2(apr_file, TRUE,
 
160
                                                  result_pool);
 
161
          file->is_packed = svn_fs_fs__is_packed_rev(fs, rev);
 
162
 
 
163
          return SVN_NO_ERROR;
 
164
        }
 
165
 
 
166
      if (err && APR_STATUS_IS_ENOENT(err->apr_err))
 
167
        {
 
168
          if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
 
169
            {
 
170
              /* Could not open the file. This may happen if the
 
171
               * file once existed but got packed later. */
 
172
              svn_error_clear(err);
 
173
 
 
174
              /* if that was our 2nd attempt, leave it at that. */
 
175
              if (retry)
 
176
                return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
 
177
                                         _("No such revision %ld"), rev);
 
178
 
 
179
              /* We failed for the first time. Refresh cache & retry. */
 
180
              SVN_ERR(svn_fs_fs__update_min_unpacked_rev(fs, scratch_pool));
 
181
              file->start_revision = svn_fs_fs__packed_base_rev(fs, rev);
 
182
 
 
183
              retry = TRUE;
 
184
            }
 
185
          else
 
186
            {
 
187
              svn_error_clear(err);
 
188
              return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
 
189
                                       _("No such revision %ld"), rev);
 
190
            }
 
191
        }
 
192
      else
 
193
        {
 
194
          retry = FALSE;
 
195
        }
 
196
    }
 
197
  while (retry);
 
198
 
 
199
  return svn_error_trace(err);
 
200
}
 
201
 
 
202
svn_error_t *
 
203
svn_fs_fs__open_pack_or_rev_file(svn_fs_fs__revision_file_t **file,
 
204
                                 svn_fs_t *fs,
 
205
                                 svn_revnum_t rev,
 
206
                                 apr_pool_t *result_pool,
 
207
                                 apr_pool_t *scratch_pool)
 
208
{
 
209
  *file = apr_palloc(result_pool, sizeof(**file));
 
210
  init_revision_file(*file, fs, rev, result_pool);
 
211
 
 
212
  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, FALSE,
 
213
                                               result_pool, scratch_pool));
 
214
}
 
215
 
 
216
svn_error_t *
 
217
svn_fs_fs__open_pack_or_rev_file_writable(svn_fs_fs__revision_file_t** file,
 
218
                                          svn_fs_t* fs,
 
219
                                          svn_revnum_t rev,
 
220
                                          apr_pool_t* result_pool,
 
221
                                          apr_pool_t *scratch_pool)
 
222
{
 
223
  *file = apr_palloc(result_pool, sizeof(**file));
 
224
  init_revision_file(*file, fs, rev, result_pool);
 
225
 
 
226
  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, TRUE,
 
227
                                               result_pool, scratch_pool));
 
228
}
 
229
 
 
230
svn_error_t *
 
231
svn_fs_fs__auto_read_footer(svn_fs_fs__revision_file_t *file)
 
232
{
 
233
  if (file->l2p_offset == -1)
 
234
    {
 
235
      apr_off_t filesize = 0;
 
236
      unsigned char footer_length;
 
237
      svn_stringbuf_t *footer;
 
238
 
 
239
      /* Determine file size. */
 
240
      SVN_ERR(svn_io_file_seek(file->file, APR_END, &filesize, file->pool));
 
241
 
 
242
      /* Read last byte (containing the length of the footer). */
 
243
      SVN_ERR(svn_io_file_aligned_seek(file->file, file->block_size, NULL,
 
244
                                       filesize - 1, file->pool));
 
245
      SVN_ERR(svn_io_file_read_full2(file->file, &footer_length,
 
246
                                     sizeof(footer_length), NULL, NULL,
 
247
                                     file->pool));
 
248
 
 
249
      /* Read footer. */
 
250
      footer = svn_stringbuf_create_ensure(footer_length, file->pool);
 
251
      SVN_ERR(svn_io_file_aligned_seek(file->file, file->block_size, NULL,
 
252
                                       filesize - 1 - footer_length,
 
253
                                       file->pool));
 
254
      SVN_ERR(svn_io_file_read_full2(file->file, footer->data, footer_length,
 
255
                                     &footer->len, NULL, file->pool));
 
256
      footer->data[footer->len] = '\0';
 
257
 
 
258
      /* Extract index locations. */
 
259
      SVN_ERR(svn_fs_fs__parse_footer(&file->l2p_offset, &file->l2p_checksum,
 
260
                                      &file->p2l_offset, &file->p2l_checksum,
 
261
                                      footer, file->start_revision,
 
262
                                      file->pool));
 
263
      file->footer_offset = filesize - footer_length - 1;
 
264
    }
 
265
 
 
266
  return SVN_NO_ERROR;
 
267
}
 
268
 
 
269
svn_error_t *
 
270
svn_fs_fs__open_proto_rev_file(svn_fs_fs__revision_file_t **file,
 
271
                               svn_fs_t *fs,
 
272
                               const svn_fs_fs__id_part_t *txn_id,
 
273
                               apr_pool_t* result_pool,
 
274
                               apr_pool_t *scratch_pool)
 
275
{
 
276
  apr_file_t *apr_file;
 
277
  SVN_ERR(svn_io_file_open(&apr_file,
 
278
                           svn_fs_fs__path_txn_proto_rev(fs, txn_id,
 
279
                                                         scratch_pool),
 
280
                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
 
281
                           result_pool));
 
282
 
 
283
  *file = apr_pcalloc(result_pool, sizeof(**file));
 
284
  (*file)->file = apr_file;
 
285
  (*file)->is_packed = FALSE;
 
286
  (*file)->start_revision = SVN_INVALID_REVNUM;
 
287
  (*file)->stream = svn_stream_from_aprfile2(apr_file, TRUE, result_pool);
 
288
 
 
289
  return SVN_NO_ERROR;
 
290
}
 
291
 
 
292
svn_error_t *
 
293
svn_fs_fs__close_revision_file(svn_fs_fs__revision_file_t *file)
 
294
{
 
295
  if (file->stream)
 
296
    SVN_ERR(svn_stream_close(file->stream));
 
297
  if (file->file)
 
298
    SVN_ERR(svn_io_file_close(file->file, file->pool));
 
299
 
 
300
  file->file = NULL;
 
301
  file->stream = NULL;
 
302
  file->l2p_stream = NULL;
 
303
  file->p2l_stream = NULL;
 
304
 
 
305
  return SVN_NO_ERROR;
 
306
}