In the command-line client, forbid
[svn.git] / subversion / libsvn_fs_fs / fs.c
blob8d93243dd17b007021e682c623b8d99b5eb983dc
1 /* fs.c --- creating, opening and closing filesystems
3 * ====================================================================
4 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
6 * This software is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at http://subversion.tigris.org/license-1.html.
9 * If newer versions of this license are posted there, you may use a
10 * newer version instead, at your option.
12 * This software consists of voluntary contributions made by many
13 * individuals. For exact contribution history, see the revision
14 * history and logs, available at http://subversion.tigris.org/.
15 * ====================================================================
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
22 #include <apr_general.h>
23 #include <apr_pools.h>
24 #include <apr_file_io.h>
25 #include <apr_thread_mutex.h>
27 #include "svn_fs.h"
28 #include "svn_delta.h"
29 #include "svn_version.h"
30 #include "svn_pools.h"
31 #include "fs.h"
32 #include "err.h"
33 #include "fs_fs.h"
34 #include "tree.h"
35 #include "lock.h"
36 #include "svn_private_config.h"
38 #include "../libsvn_fs/fs-loader.h"
40 /* A prefix for the pool userdata variables used to hold
41 per-filesystem shared data. See fs_serialized_init. */
42 #define SVN_FSFS_SHARED_USERDATA_PREFIX "svn-fsfs-shared-"
46 /* If filesystem FS is already open, then return an
47 SVN_ERR_FS_ALREADY_OPEN error. Otherwise, return zero. */
48 static svn_error_t *
49 check_already_open(svn_fs_t *fs)
51 if (fs->fsap_data)
52 return svn_error_create(SVN_ERR_FS_ALREADY_OPEN, 0,
53 _("Filesystem object already open"));
54 else
55 return SVN_NO_ERROR;
60 static svn_error_t *
61 fs_serialized_init(svn_fs_t *fs, apr_pool_t *common_pool, apr_pool_t *pool)
63 fs_fs_data_t *ffd = fs->fsap_data;
64 const char *key;
65 void *val;
66 fs_fs_shared_data_t *ffsd;
67 apr_status_t status;
69 /* Note that we are allocating a small amount of long-lived data for
70 each separate repository opened during the lifetime of the
71 svn_fs_initialize pool. It's unlikely that anyone will notice
72 the modest expenditure; the alternative is to allocate each structure
73 in a subpool, add a reference-count, and add a serialized deconstructor
74 to the FS vtable. That's more machinery than it's worth.
76 Using the uuid to obtain the lock creates a corner case if a
77 caller uses svn_fs_set_uuid on the repository in a process where
78 other threads might be using the same repository through another
79 FS object. The only real-world consumer of svn_fs_set_uuid is
80 "svnadmin load", so this is a low-priority problem, and we don't
81 know of a better way of associating such data with the
82 repository. */
84 key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX, ffd->uuid,
85 (char *) NULL);
86 status = apr_pool_userdata_get(&val, key, common_pool);
87 if (status)
88 return svn_error_wrap_apr(status, _("Can't fetch FSFS shared data"));
89 ffsd = val;
91 if (!ffsd)
93 ffsd = apr_pcalloc(common_pool, sizeof(*ffsd));
94 ffsd->common_pool = common_pool;
96 #if APR_HAS_THREADS
97 /* POSIX fcntl locks are per-process, so we need a mutex for
98 intra-process synchronization when grabbing the repository write
99 lock. */
100 status = apr_thread_mutex_create(&ffsd->fs_write_lock,
101 APR_THREAD_MUTEX_DEFAULT, common_pool);
102 if (status)
103 return svn_error_wrap_apr(status,
104 _("Can't create FSFS write-lock mutex"));
106 /* We also need a mutex for synchronising access to the active
107 transaction list and free transaction pointer. */
108 status = apr_thread_mutex_create(&ffsd->txn_list_lock,
109 APR_THREAD_MUTEX_DEFAULT, common_pool);
110 if (status)
111 return svn_error_wrap_apr(status,
112 _("Can't create FSFS txn list mutex"));
114 /* ... not to mention locking the transaction-current file. */
115 status = apr_thread_mutex_create(&ffsd->txn_current_lock,
116 APR_THREAD_MUTEX_DEFAULT, common_pool);
117 if (status)
118 return svn_error_wrap_apr(status,
119 _("Can't create FSFS txn-current mutex"));
120 #endif
122 key = apr_pstrdup(common_pool, key);
123 status = apr_pool_userdata_set(ffsd, key, NULL, common_pool);
124 if (status)
125 return svn_error_wrap_apr(status, _("Can't store FSFS shared data"));
128 ffd->shared = ffsd;
130 return SVN_NO_ERROR;
135 /* This function is provided for Subversion 1.0.x compatibility. It
136 has no effect for fsfs backed Subversion filesystems. It conforms
137 to the fs_library_vtable_t.bdb_set_errcall() API. */
138 static svn_error_t *
139 fs_set_errcall(svn_fs_t *fs,
140 void (*db_errcall_fcn)(const char *errpfx, char *msg))
143 return SVN_NO_ERROR;
148 /* The vtable associated with a specific open filesystem. */
149 static fs_vtable_t fs_vtable = {
150 svn_fs_fs__youngest_rev,
151 svn_fs_fs__revision_prop,
152 svn_fs_fs__revision_proplist,
153 svn_fs_fs__change_rev_prop,
154 svn_fs_fs__get_uuid,
155 svn_fs_fs__set_uuid,
156 svn_fs_fs__revision_root,
157 svn_fs_fs__begin_txn,
158 svn_fs_fs__open_txn,
159 svn_fs_fs__purge_txn,
160 svn_fs_fs__list_transactions,
161 svn_fs_fs__deltify,
162 svn_fs_fs__lock,
163 svn_fs_fs__generate_lock_token,
164 svn_fs_fs__unlock,
165 svn_fs_fs__get_lock,
166 svn_fs_fs__get_locks,
167 fs_set_errcall
171 /* Creating a new filesystem. */
173 /* Set up vtable and fsap_data fields in FS. */
174 static void
175 initialize_fs_struct(svn_fs_t *fs)
177 fs_fs_data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
178 fs->vtable = &fs_vtable;
179 fs->fsap_data = ffd;
181 ffd->rev_root_id_cache_pool = svn_pool_create(fs->pool);
182 ffd->rev_root_id_cache = apr_hash_make(ffd->rev_root_id_cache_pool);
184 ffd->rev_node_cache = apr_hash_make(fs->pool);
185 ffd->rev_node_list.prev = &ffd->rev_node_list;
186 ffd->rev_node_list.next = &ffd->rev_node_list;
189 /* This implements the fs_library_vtable_t.create() API. Create a new
190 fsfs-backed Subversion filesystem at path PATH and link it into
191 *FS. Perform temporary allocations in POOL, and fs-global allocations
192 in COMMON_POOL. */
193 static svn_error_t *
194 fs_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
195 apr_pool_t *common_pool)
197 SVN_ERR(check_already_open(fs));
199 initialize_fs_struct(fs);
201 SVN_ERR(svn_fs_fs__create(fs, path, pool));
202 return fs_serialized_init(fs, common_pool, pool);
207 /* Gaining access to an existing filesystem. */
209 /* This implements the fs_library_vtable_t.open() API. Open an FSFS
210 Subversion filesystem located at PATH, set *FS to point to the
211 correct vtable for the filesystem. Use POOL for any temporary
212 allocations, and COMMON_POOL for fs-global allocations. */
213 static svn_error_t *
214 fs_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
215 apr_pool_t *common_pool)
217 initialize_fs_struct(fs);
219 SVN_ERR(svn_fs_fs__open(fs, path, pool));
220 return fs_serialized_init(fs, common_pool, pool);
225 /* This implements the fs_library_vtable_t.open_for_recovery() API. */
226 static svn_error_t *
227 fs_open_for_recovery(svn_fs_t *fs,
228 const char *path,
229 apr_pool_t *pool, apr_pool_t *common_pool)
231 /* Recovery for FSFS is currently limited to recreating the current
232 file from the latest revision. */
234 /* The only thing we have to watch out for is that the current file
235 might not exist. So we'll try to create it here unconditionally,
236 and just ignore any errors that might indicate that it's already
237 present. (We'll need it to exist later anyway as a source for the
238 new file's permissions). */
240 /* Use a partly-filled fs pointer first to create current. This will fail
241 if current already exists, but we don't care about that. */
242 fs->path = apr_pstrdup(fs->pool, path);
243 svn_error_clear(svn_io_file_create(svn_fs_fs__path_current(fs, pool),
244 "0 1 1\n", pool));
246 /* Now open the filesystem properly by calling the vtable method directly. */
247 return fs_open(fs, path, pool, common_pool);
252 /* This implements the fs_library_vtable_t.hotcopy() API. Copy a
253 possibly live Subversion filesystem from SRC_PATH to DEST_PATH.
254 The CLEAN_LOGS argument is ignored and included for Subversion
255 1.0.x compatibility. Perform all temporary allocations in POOL. */
256 static svn_error_t *
257 fs_hotcopy(const char *src_path,
258 const char *dest_path,
259 svn_boolean_t clean_logs,
260 apr_pool_t *pool)
262 return svn_fs_fs__hotcopy(src_path, dest_path, pool);
267 /* This function is included for Subversion 1.0.x compatibility. It
268 has no effect for fsfs backed Subversion filesystems. It conforms
269 to the fs_library_vtable_t.bdb_logfiles() API. */
270 static svn_error_t *
271 fs_logfiles(apr_array_header_t **logfiles,
272 const char *path,
273 svn_boolean_t only_unused,
274 apr_pool_t *pool)
276 /* A no-op for FSFS. */
277 *logfiles = apr_array_make(pool, 0, sizeof(const char *));
279 return SVN_NO_ERROR;
286 /* Delete the filesystem located at path PATH. Perform any temporary
287 allocations in POOL. */
288 static svn_error_t *
289 fs_delete_fs(const char *path,
290 apr_pool_t *pool)
292 /* Remove everything. */
293 return svn_io_remove_dir2(path, FALSE, NULL, NULL, pool);
296 static const svn_version_t *
297 fs_version(void)
299 SVN_VERSION_BODY;
302 static const char *
303 fs_get_description(void)
305 return _("Module for working with a plain file (FSFS) repository.");
310 /* Base FS library vtable, used by the FS loader library. */
312 static fs_library_vtable_t library_vtable = {
313 fs_version,
314 fs_create,
315 fs_open,
316 fs_open_for_recovery,
317 fs_delete_fs,
318 fs_hotcopy,
319 fs_get_description,
320 svn_fs_fs__recover,
321 fs_logfiles
324 svn_error_t *
325 svn_fs_fs__init(const svn_version_t *loader_version,
326 fs_library_vtable_t **vtable, apr_pool_t* common_pool)
328 static const svn_version_checklist_t checklist[] =
330 { "svn_subr", svn_subr_version },
331 { "svn_delta", svn_delta_version },
332 { NULL, NULL }
335 /* Simplified version check to make sure we can safely use the
336 VTABLE parameter. The FS loader does a more exhaustive check. */
337 if (loader_version->major != SVN_VER_MAJOR)
338 return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
339 _("Unsupported FS loader version (%d) for fsfs"),
340 loader_version->major);
341 SVN_ERR(svn_ver_check_list(fs_version(), checklist));
343 *vtable = &library_vtable;
344 return SVN_NO_ERROR;