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

« back to all changes in this revision

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