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 * ====================================================================
22 #include <apr_general.h>
23 #include <apr_pools.h>
24 #include <apr_file_io.h>
25 #include <apr_thread_mutex.h>
28 #include "svn_delta.h"
29 #include "svn_version.h"
30 #include "svn_pools.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. */
49 check_already_open(svn_fs_t
*fs
)
52 return svn_error_create(SVN_ERR_FS_ALREADY_OPEN
, 0,
53 _("Filesystem object already open"));
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
;
66 fs_fs_shared_data_t
*ffsd
;
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
84 key
= apr_pstrcat(pool
, SVN_FSFS_SHARED_USERDATA_PREFIX
, ffd
->uuid
,
86 status
= apr_pool_userdata_get(&val
, key
, common_pool
);
88 return svn_error_wrap_apr(status
, _("Can't fetch FSFS shared data"));
93 ffsd
= apr_pcalloc(common_pool
, sizeof(*ffsd
));
94 ffsd
->common_pool
= common_pool
;
97 /* POSIX fcntl locks are per-process, so we need a mutex for
98 intra-process synchronization when grabbing the repository write
100 status
= apr_thread_mutex_create(&ffsd
->fs_write_lock
,
101 APR_THREAD_MUTEX_DEFAULT
, common_pool
);
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
);
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
);
118 return svn_error_wrap_apr(status
,
119 _("Can't create FSFS txn-current mutex"));
122 key
= apr_pstrdup(common_pool
, key
);
123 status
= apr_pool_userdata_set(ffsd
, key
, NULL
, common_pool
);
125 return svn_error_wrap_apr(status
, _("Can't store FSFS shared data"));
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. */
139 fs_set_errcall(svn_fs_t
*fs
,
140 void (*db_errcall_fcn
)(const char *errpfx
, char *msg
))
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
,
156 svn_fs_fs__revision_root
,
157 svn_fs_fs__begin_txn
,
159 svn_fs_fs__purge_txn
,
160 svn_fs_fs__list_transactions
,
163 svn_fs_fs__generate_lock_token
,
166 svn_fs_fs__get_locks
,
171 /* Creating a new filesystem. */
173 /* Set up vtable and fsap_data fields in FS. */
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
;
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
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. */
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. */
227 fs_open_for_recovery(svn_fs_t
*fs
,
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
),
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. */
257 fs_hotcopy(const char *src_path
,
258 const char *dest_path
,
259 svn_boolean_t clean_logs
,
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. */
271 fs_logfiles(apr_array_header_t
**logfiles
,
273 svn_boolean_t only_unused
,
276 /* A no-op for FSFS. */
277 *logfiles
= apr_array_make(pool
, 0, sizeof(const char *));
286 /* Delete the filesystem located at path PATH. Perform any temporary
287 allocations in POOL. */
289 fs_delete_fs(const char *path
,
292 /* Remove everything. */
293 return svn_io_remove_dir2(path
, FALSE
, NULL
, NULL
, pool
);
296 static const svn_version_t
*
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
= {
316 fs_open_for_recovery
,
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
},
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
;