1251881Speter/*
2251881Speter * fs_loader.c:  Front-end to the various FS back ends
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter#include <string.h>
26251881Speter#include <apr.h>
27251881Speter#include <apr_hash.h>
28251881Speter#include <apr_md5.h>
29251881Speter#include <apr_thread_mutex.h>
30251881Speter#include <apr_uuid.h>
31251881Speter#include <apr_strings.h>
32251881Speter
33251881Speter#include "svn_hash.h"
34251881Speter#include "svn_ctype.h"
35251881Speter#include "svn_types.h"
36251881Speter#include "svn_dso.h"
37251881Speter#include "svn_version.h"
38251881Speter#include "svn_fs.h"
39251881Speter#include "svn_path.h"
40251881Speter#include "svn_xml.h"
41251881Speter#include "svn_pools.h"
42251881Speter#include "svn_string.h"
43251881Speter#include "svn_private_config.h"
44251881Speter
45251881Speter#include "private/svn_fs_private.h"
46251881Speter#include "private/svn_fs_util.h"
47251881Speter#include "private/svn_utf_private.h"
48251881Speter#include "private/svn_mutex.h"
49251881Speter#include "private/svn_subr_private.h"
50251881Speter
51251881Speter#include "fs-loader.h"
52251881Speter
53251881Speter/* This is defined by configure on platforms which use configure, but
54251881Speter   we need to define a fallback for Windows. */
55251881Speter#ifndef DEFAULT_FS_TYPE
56251881Speter#define DEFAULT_FS_TYPE "fsfs"
57251881Speter#endif
58251881Speter
59251881Speter#define FS_TYPE_FILENAME "fs-type"
60251881Speter
61251881Speter/* A pool common to all FS objects.  See the documentation on the
62251881Speter   open/create functions in fs-loader.h and for svn_fs_initialize(). */
63251881Speterstatic apr_pool_t *common_pool;
64251881Spetersvn_mutex__t *common_pool_lock;
65251881Speter
66251881Speter
67251881Speter/* --- Utility functions for the loader --- */
68251881Speter
69251881Speterstruct fs_type_defn {
70251881Speter  const char *fs_type;
71251881Speter  const char *fsap_name;
72251881Speter  fs_init_func_t initfunc;
73251881Speter  struct fs_type_defn *next;
74251881Speter};
75251881Speter
76251881Speterstatic struct fs_type_defn base_defn =
77251881Speter  {
78251881Speter    SVN_FS_TYPE_BDB, "base",
79251881Speter#ifdef SVN_LIBSVN_FS_LINKS_FS_BASE
80251881Speter    svn_fs_base__init,
81251881Speter#else
82251881Speter    NULL,
83251881Speter#endif
84262253Speter    NULL /* End of static list: this needs to be reset to NULL if the
85262253Speter            common_pool used when setting it has been cleared. */
86251881Speter  };
87251881Speter
88251881Speterstatic struct fs_type_defn fsfs_defn =
89251881Speter  {
90251881Speter    SVN_FS_TYPE_FSFS, "fs",
91251881Speter#ifdef SVN_LIBSVN_FS_LINKS_FS_FS
92251881Speter    svn_fs_fs__init,
93251881Speter#else
94251881Speter    NULL,
95251881Speter#endif
96251881Speter    &base_defn
97251881Speter  };
98251881Speter
99251881Speterstatic struct fs_type_defn *fs_modules = &fsfs_defn;
100251881Speter
101251881Speter
102251881Speterstatic svn_error_t *
103251881Speterload_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
104251881Speter{
105251881Speter  *initfunc = NULL;
106251881Speter
107251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO
108251881Speter  {
109251881Speter    apr_dso_handle_t *dso;
110251881Speter    apr_dso_handle_sym_t symbol;
111251881Speter    const char *libname;
112251881Speter    const char *funcname;
113251881Speter    apr_status_t status;
114251881Speter    const char *p;
115251881Speter
116251881Speter    /* Demand a simple alphanumeric name so that the generated DSO
117251881Speter       name is sensible. */
118251881Speter    for (p = name; *p; ++p)
119251881Speter      if (!svn_ctype_isalnum(*p))
120251881Speter        return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
121251881Speter                                 _("Invalid name for FS type '%s'"),
122251881Speter                                 name);
123251881Speter
124251881Speter    libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.%d",
125251881Speter                           name, SVN_VER_MAJOR, SVN_SOVERSION);
126251881Speter    funcname = apr_psprintf(pool, "svn_fs_%s__init", name);
127251881Speter
128251881Speter    /* Find/load the specified library.  If we get an error, assume
129251881Speter       the library doesn't exist.  The library will be unloaded when
130251881Speter       pool is destroyed. */
131251881Speter    SVN_ERR(svn_dso_load(&dso, libname));
132251881Speter    if (! dso)
133251881Speter      return SVN_NO_ERROR;
134251881Speter
135251881Speter    /* find the initialization routine */
136251881Speter    status = apr_dso_sym(&symbol, dso, funcname);
137251881Speter    if (status)
138251881Speter      return svn_error_wrap_apr(status, _("'%s' does not define '%s()'"),
139251881Speter                                libname, funcname);
140251881Speter
141251881Speter    *initfunc = (fs_init_func_t) symbol;
142251881Speter  }
143251881Speter#endif /* APR_HAS_DSO */
144251881Speter
145251881Speter  return SVN_NO_ERROR;
146251881Speter}
147251881Speter
148251881Speter/* Fetch a library vtable by a pointer into the library definitions array. */
149251881Speterstatic svn_error_t *
150251881Speterget_library_vtable_direct(fs_library_vtable_t **vtable,
151251881Speter                          const struct fs_type_defn *fst,
152251881Speter                          apr_pool_t *pool)
153251881Speter{
154251881Speter  fs_init_func_t initfunc = NULL;
155251881Speter  const svn_version_t *my_version = svn_fs_version();
156251881Speter  const svn_version_t *fs_version;
157251881Speter
158251881Speter  initfunc = fst->initfunc;
159251881Speter  if (! initfunc)
160251881Speter    SVN_ERR(load_module(&initfunc, fst->fsap_name, pool));
161251881Speter
162251881Speter  if (! initfunc)
163251881Speter    return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
164251881Speter                             _("Failed to load module for FS type '%s'"),
165251881Speter                             fst->fs_type);
166251881Speter
167251881Speter  {
168251881Speter    /* Per our API compatibility rules, we cannot ensure that
169251881Speter       svn_fs_initialize is called by the application.  If not, we
170251881Speter       cannot create the common pool and lock in a thread-safe fashion,
171251881Speter       nor can we clean up the common pool if libsvn_fs is dynamically
172251881Speter       unloaded.  This function makes a best effort by creating the
173251881Speter       common pool as a child of the global pool; the window of failure
174251881Speter       due to thread collision is small. */
175251881Speter    if (!common_pool)
176251881Speter      SVN_ERR(svn_fs_initialize(NULL));
177251881Speter
178251881Speter    /* Invoke the FS module's initfunc function with the common
179251881Speter       pool protected by a lock. */
180251881Speter    SVN_MUTEX__WITH_LOCK(common_pool_lock,
181251881Speter                         initfunc(my_version, vtable, common_pool));
182251881Speter  }
183251881Speter  fs_version = (*vtable)->get_version();
184251881Speter  if (!svn_ver_equal(my_version, fs_version))
185251881Speter    return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL,
186251881Speter                             _("Mismatched FS module version for '%s':"
187251881Speter                               " found %d.%d.%d%s,"
188251881Speter                               " expected %d.%d.%d%s"),
189251881Speter                             fst->fs_type,
190251881Speter                             my_version->major, my_version->minor,
191251881Speter                             my_version->patch, my_version->tag,
192251881Speter                             fs_version->major, fs_version->minor,
193251881Speter                             fs_version->patch, fs_version->tag);
194251881Speter  return SVN_NO_ERROR;
195251881Speter}
196251881Speter
197251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO
198251881Speter/* Return *FST for the third party FS_TYPE */
199251881Speterstatic svn_error_t *
200251881Speterget_or_allocate_third(struct fs_type_defn **fst,
201251881Speter                      const char *fs_type)
202251881Speter{
203251881Speter  while (*fst)
204251881Speter    {
205251881Speter      if (strcmp(fs_type, (*fst)->fs_type) == 0)
206251881Speter        return SVN_NO_ERROR;
207251881Speter      fst = &(*fst)->next;
208251881Speter    }
209251881Speter
210251881Speter  *fst = apr_palloc(common_pool, sizeof(struct fs_type_defn));
211251881Speter  (*fst)->fs_type = apr_pstrdup(common_pool, fs_type);
212251881Speter  (*fst)->fsap_name = (*fst)->fs_type;
213251881Speter  (*fst)->initfunc = NULL;
214251881Speter  (*fst)->next = NULL;
215251881Speter
216251881Speter  return SVN_NO_ERROR;
217251881Speter}
218251881Speter#endif
219251881Speter
220251881Speter/* Fetch a library vtable by FS type. */
221251881Speterstatic svn_error_t *
222251881Speterget_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
223251881Speter                   apr_pool_t *pool)
224251881Speter{
225251881Speter  struct fs_type_defn **fst = &fs_modules;
226251881Speter  svn_boolean_t known = FALSE;
227251881Speter
228251881Speter  /* There are two FS module definitions known at compile time.  We
229251881Speter     want to check these without any locking overhead even when
230251881Speter     dynamic third party modules are enabled.  The third party modules
231251881Speter     cannot be checked until the lock is held.  */
232251881Speter  if (strcmp(fs_type, (*fst)->fs_type) == 0)
233251881Speter    known = TRUE;
234251881Speter  else
235251881Speter    {
236251881Speter      fst = &(*fst)->next;
237251881Speter      if (strcmp(fs_type, (*fst)->fs_type) == 0)
238251881Speter        known = TRUE;
239251881Speter    }
240251881Speter
241251881Speter#if defined(SVN_USE_DSO) && APR_HAS_DSO
242251881Speter  /* Third party FS modules that are unknown at compile time.
243251881Speter
244251881Speter     A third party FS is identified by the file fs-type containing a
245251881Speter     third party name, say "foo".  The loader will load the DSO with
246251881Speter     the name "libsvn_fs_foo" and use the entry point with the name
247251881Speter     "svn_fs_foo__init".
248251881Speter
249251881Speter     Note: the BDB and FSFS modules don't follow this naming scheme
250251881Speter     and this allows them to be used to test the third party loader.
251251881Speter     Change the content of fs-type to "base" in a BDB filesystem or to
252251881Speter     "fs" in an FSFS filesystem and they will be loaded as third party
253251881Speter     modules. */
254251881Speter  if (!known)
255251881Speter    {
256251881Speter      fst = &(*fst)->next;
257251881Speter      if (!common_pool)  /* Best-effort init, see get_library_vtable_direct. */
258251881Speter        SVN_ERR(svn_fs_initialize(NULL));
259251881Speter      SVN_MUTEX__WITH_LOCK(common_pool_lock,
260251881Speter                           get_or_allocate_third(fst, fs_type));
261251881Speter      known = TRUE;
262251881Speter    }
263251881Speter#endif
264251881Speter  if (!known)
265251881Speter    return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
266251881Speter                             _("Unknown FS type '%s'"), fs_type);
267251881Speter  return get_library_vtable_direct(vtable, *fst, pool);
268251881Speter}
269251881Speter
270251881Spetersvn_error_t *
271251881Spetersvn_fs_type(const char **fs_type, const char *path, apr_pool_t *pool)
272251881Speter{
273251881Speter  const char *filename;
274251881Speter  char buf[128];
275251881Speter  svn_error_t *err;
276251881Speter  apr_file_t *file;
277251881Speter  apr_size_t len;
278251881Speter
279251881Speter  /* Read the fsap-name file to get the FSAP name, or assume the (old)
280251881Speter     default.  For old repositories I suppose we could check some
281251881Speter     other file, DB_CONFIG or strings say, but for now just check the
282251881Speter     directory exists. */
283251881Speter  filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool);
284251881Speter  err = svn_io_file_open(&file, filename, APR_READ|APR_BUFFERED, 0, pool);
285251881Speter  if (err && APR_STATUS_IS_ENOENT(err->apr_err))
286251881Speter    {
287251881Speter      svn_node_kind_t kind;
288251881Speter      svn_error_t *err2 = svn_io_check_path(path, &kind, pool);
289251881Speter      if (err2)
290251881Speter        {
291251881Speter          svn_error_clear(err2);
292251881Speter          return err;
293251881Speter        }
294251881Speter      if (kind == svn_node_dir)
295251881Speter        {
296251881Speter          svn_error_clear(err);
297251881Speter          *fs_type = SVN_FS_TYPE_BDB;
298251881Speter          return SVN_NO_ERROR;
299251881Speter        }
300251881Speter      return err;
301251881Speter    }
302251881Speter  else if (err)
303251881Speter    return err;
304251881Speter
305251881Speter  len = sizeof(buf);
306251881Speter  SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
307251881Speter  SVN_ERR(svn_io_file_close(file, pool));
308251881Speter  *fs_type = apr_pstrdup(pool, buf);
309251881Speter
310251881Speter  return SVN_NO_ERROR;
311251881Speter}
312251881Speter
313251881Speter/* Fetch the library vtable for an existing FS. */
314251881Speterstatic svn_error_t *
315251881Speterfs_library_vtable(fs_library_vtable_t **vtable, const char *path,
316251881Speter                  apr_pool_t *pool)
317251881Speter{
318251881Speter  const char *fs_type;
319251881Speter
320251881Speter  SVN_ERR(svn_fs_type(&fs_type, path, pool));
321251881Speter
322251881Speter  /* Fetch the library vtable by name, now that we've chosen one. */
323251881Speter  return svn_error_trace(get_library_vtable(vtable, fs_type, pool));
324251881Speter}
325251881Speter
326251881Speterstatic svn_error_t *
327251881Speterwrite_fs_type(const char *path, const char *fs_type, apr_pool_t *pool)
328251881Speter{
329251881Speter  const char *filename;
330251881Speter  apr_file_t *file;
331251881Speter
332251881Speter  filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool);
333251881Speter  SVN_ERR(svn_io_file_open(&file, filename,
334251881Speter                           APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED,
335251881Speter                           APR_OS_DEFAULT, pool));
336251881Speter  SVN_ERR(svn_io_file_write_full(file, fs_type, strlen(fs_type), NULL,
337251881Speter                                 pool));
338251881Speter  SVN_ERR(svn_io_file_write_full(file, "\n", 1, NULL, pool));
339251881Speter  return svn_error_trace(svn_io_file_close(file, pool));
340251881Speter}
341251881Speter
342251881Speter
343251881Speter/* --- Functions for operating on filesystems by pathname --- */
344251881Speter
345251881Speterstatic apr_status_t uninit(void *data)
346251881Speter{
347251881Speter  common_pool = NULL;
348251881Speter  return APR_SUCCESS;
349251881Speter}
350251881Speter
351251881Spetersvn_error_t *
352251881Spetersvn_fs_initialize(apr_pool_t *pool)
353251881Speter{
354251881Speter  /* Protect against multiple calls. */
355251881Speter  if (common_pool)
356251881Speter    return SVN_NO_ERROR;
357251881Speter
358251881Speter  common_pool = svn_pool_create(pool);
359262253Speter  base_defn.next = NULL;
360251881Speter  SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
361251881Speter
362251881Speter  /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO
363251881Speter     ### (via libsvn_ra_local say) since the global common_pool will live
364251881Speter     ### longer than the DSO, which gets unloaded when the pool used to
365251881Speter     ### load it is cleared, and so when the handler runs it will refer to
366251881Speter     ### a function that no longer exists.  libsvn_ra_local attempts to
367251881Speter     ### work around this by explicitly calling svn_fs_initialize. */
368251881Speter  apr_pool_cleanup_register(common_pool, NULL, uninit, apr_pool_cleanup_null);
369251881Speter  return SVN_NO_ERROR;
370251881Speter}
371251881Speter
372251881Speter/* A default warning handling function.  */
373251881Speterstatic void
374251881Speterdefault_warning_func(void *baton, svn_error_t *err)
375251881Speter{
376251881Speter  /* The one unforgiveable sin is to fail silently.  Dumping to stderr
377251881Speter     or /dev/tty is not acceptable default behavior for server
378251881Speter     processes, since those may both be equivalent to /dev/null.  */
379251881Speter  SVN_ERR_MALFUNCTION_NO_RETURN();
380251881Speter}
381251881Speter
382251881Spetersvn_error_t *
383251881Spetersvn_fs__path_valid(const char *path, apr_pool_t *pool)
384251881Speter{
385251881Speter  /* UTF-8 encoded string without NULs. */
386251881Speter  if (! svn_utf__cstring_is_valid(path))
387251881Speter    {
388251881Speter      return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
389251881Speter                               _("Path '%s' is not in UTF-8"), path);
390251881Speter    }
391251881Speter
392251881Speter  /* No "." or ".." elements. */
393251881Speter  if (svn_path_is_backpath_present(path)
394251881Speter      || svn_path_is_dotpath_present(path))
395251881Speter    {
396251881Speter      return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
397251881Speter                               _("Path '%s' contains '.' or '..' element"),
398251881Speter                               path);
399251881Speter    }
400251881Speter
401251881Speter  /* That's good enough. */
402251881Speter  return SVN_NO_ERROR;
403251881Speter}
404251881Speter
405251881Speter/* Allocate svn_fs_t structure. */
406251881Speterstatic svn_fs_t *
407251881Speterfs_new(apr_hash_t *fs_config, apr_pool_t *pool)
408251881Speter{
409251881Speter  svn_fs_t *fs = apr_palloc(pool, sizeof(*fs));
410251881Speter  fs->pool = pool;
411251881Speter  fs->path = NULL;
412251881Speter  fs->warning = default_warning_func;
413251881Speter  fs->warning_baton = NULL;
414251881Speter  fs->config = fs_config;
415251881Speter  fs->access_ctx = NULL;
416251881Speter  fs->vtable = NULL;
417251881Speter  fs->fsap_data = NULL;
418251881Speter  fs->uuid = NULL;
419251881Speter  return fs;
420251881Speter}
421251881Speter
422251881Spetersvn_fs_t *
423251881Spetersvn_fs_new(apr_hash_t *fs_config, apr_pool_t *pool)
424251881Speter{
425251881Speter  return fs_new(fs_config, pool);
426251881Speter}
427251881Speter
428251881Spetervoid
429251881Spetersvn_fs_set_warning_func(svn_fs_t *fs, svn_fs_warning_callback_t warning,
430251881Speter                        void *warning_baton)
431251881Speter{
432251881Speter  fs->warning = warning;
433251881Speter  fs->warning_baton = warning_baton;
434251881Speter}
435251881Speter
436251881Spetersvn_error_t *
437251881Spetersvn_fs_create(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
438251881Speter              apr_pool_t *pool)
439251881Speter{
440251881Speter  fs_library_vtable_t *vtable;
441251881Speter
442251881Speter  const char *fs_type = svn_hash__get_cstring(fs_config,
443251881Speter                                              SVN_FS_CONFIG_FS_TYPE,
444251881Speter                                              DEFAULT_FS_TYPE);
445251881Speter  SVN_ERR(get_library_vtable(&vtable, fs_type, pool));
446251881Speter
447251881Speter  /* Create the FS directory and write out the fsap-name file. */
448251881Speter  SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, pool));
449251881Speter  SVN_ERR(write_fs_type(path, fs_type, pool));
450251881Speter
451251881Speter  /* Perform the actual creation. */
452251881Speter  *fs_p = fs_new(fs_config, pool);
453251881Speter
454251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
455251881Speter                       vtable->create(*fs_p, path, pool, common_pool));
456251881Speter  SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
457251881Speter
458251881Speter  return SVN_NO_ERROR;
459251881Speter}
460251881Speter
461251881Spetersvn_error_t *
462251881Spetersvn_fs_open(svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
463251881Speter            apr_pool_t *pool)
464251881Speter{
465251881Speter  fs_library_vtable_t *vtable;
466251881Speter
467251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
468251881Speter  *fs_p = fs_new(fs_config, pool);
469251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
470251881Speter                       vtable->open_fs(*fs_p, path, pool, common_pool));
471251881Speter  SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
472251881Speter
473251881Speter  return SVN_NO_ERROR;
474251881Speter}
475251881Speter
476251881Spetersvn_error_t *
477251881Spetersvn_fs_upgrade(const char *path, apr_pool_t *pool)
478251881Speter{
479251881Speter  fs_library_vtable_t *vtable;
480251881Speter  svn_fs_t *fs;
481251881Speter
482251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
483251881Speter  fs = fs_new(NULL, pool);
484251881Speter
485251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
486251881Speter                       vtable->upgrade_fs(fs, path, pool, common_pool));
487251881Speter  return SVN_NO_ERROR;
488251881Speter}
489251881Speter
490251881Spetersvn_error_t *
491251881Spetersvn_fs_verify(const char *path,
492251881Speter              apr_hash_t *fs_config,
493251881Speter              svn_revnum_t start,
494251881Speter              svn_revnum_t end,
495251881Speter              svn_fs_progress_notify_func_t notify_func,
496251881Speter              void *notify_baton,
497251881Speter              svn_cancel_func_t cancel_func,
498251881Speter              void *cancel_baton,
499251881Speter              apr_pool_t *pool)
500251881Speter{
501251881Speter  fs_library_vtable_t *vtable;
502251881Speter  svn_fs_t *fs;
503251881Speter
504251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
505251881Speter  fs = fs_new(fs_config, pool);
506251881Speter
507251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
508251881Speter                       vtable->verify_fs(fs, path, start, end,
509251881Speter                                         notify_func, notify_baton,
510251881Speter                                         cancel_func, cancel_baton,
511251881Speter                                         pool, common_pool));
512251881Speter  return SVN_NO_ERROR;
513251881Speter}
514251881Speter
515251881Speterconst char *
516251881Spetersvn_fs_path(svn_fs_t *fs, apr_pool_t *pool)
517251881Speter{
518251881Speter  return apr_pstrdup(pool, fs->path);
519251881Speter}
520251881Speter
521251881Speterapr_hash_t *
522251881Spetersvn_fs_config(svn_fs_t *fs, apr_pool_t *pool)
523251881Speter{
524251881Speter  if (fs->config)
525251881Speter    return apr_hash_copy(pool, fs->config);
526251881Speter
527251881Speter  return NULL;
528251881Speter}
529251881Speter
530251881Spetersvn_error_t *
531251881Spetersvn_fs_delete_fs(const char *path, apr_pool_t *pool)
532251881Speter{
533251881Speter  fs_library_vtable_t *vtable;
534251881Speter
535251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
536251881Speter  return svn_error_trace(vtable->delete_fs(path, pool));
537251881Speter}
538251881Speter
539251881Spetersvn_error_t *
540251881Spetersvn_fs_hotcopy2(const char *src_path, const char *dst_path,
541251881Speter                svn_boolean_t clean, svn_boolean_t incremental,
542251881Speter                svn_cancel_func_t cancel_func, void *cancel_baton,
543251881Speter                apr_pool_t *scratch_pool)
544251881Speter{
545251881Speter  fs_library_vtable_t *vtable;
546251881Speter  const char *src_fs_type;
547251881Speter  svn_fs_t *src_fs;
548251881Speter  svn_fs_t *dst_fs;
549251881Speter  const char *dst_fs_type;
550251881Speter  svn_node_kind_t dst_kind;
551251881Speter
552251881Speter  if (strcmp(src_path, dst_path) == 0)
553251881Speter    return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
554251881Speter                             _("Hotcopy source and destination are equal"));
555251881Speter
556251881Speter  SVN_ERR(svn_fs_type(&src_fs_type, src_path, scratch_pool));
557251881Speter  SVN_ERR(get_library_vtable(&vtable, src_fs_type, scratch_pool));
558251881Speter  src_fs = fs_new(NULL, scratch_pool);
559251881Speter  dst_fs = fs_new(NULL, scratch_pool);
560251881Speter
561251881Speter  SVN_ERR(svn_io_check_path(dst_path, &dst_kind, scratch_pool));
562251881Speter  if (dst_kind == svn_node_file)
563251881Speter    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
564251881Speter                             _("'%s' already exists and is a file"),
565251881Speter                             svn_dirent_local_style(dst_path,
566251881Speter                                                    scratch_pool));
567251881Speter  if (dst_kind == svn_node_unknown)
568251881Speter    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
569251881Speter                             _("'%s' already exists and has an unknown "
570251881Speter                               "node kind"),
571251881Speter                             svn_dirent_local_style(dst_path,
572251881Speter                                                    scratch_pool));
573251881Speter  if (dst_kind == svn_node_dir)
574251881Speter    {
575251881Speter      svn_node_kind_t type_file_kind;
576251881Speter
577251881Speter      SVN_ERR(svn_io_check_path(svn_dirent_join(dst_path,
578251881Speter                                                FS_TYPE_FILENAME,
579251881Speter                                                scratch_pool),
580251881Speter                                &type_file_kind, scratch_pool));
581251881Speter      if (type_file_kind != svn_node_none)
582251881Speter        {
583251881Speter          SVN_ERR(svn_fs_type(&dst_fs_type, dst_path, scratch_pool));
584251881Speter          if (strcmp(src_fs_type, dst_fs_type) != 0)
585251881Speter            return svn_error_createf(
586251881Speter                     SVN_ERR_ILLEGAL_TARGET, NULL,
587251881Speter                     _("The filesystem type of the hotcopy source "
588251881Speter                       "('%s') does not match the filesystem "
589251881Speter                       "type of the hotcopy destination ('%s')"),
590251881Speter                     src_fs_type, dst_fs_type);
591251881Speter        }
592251881Speter    }
593251881Speter
594251881Speter  SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean,
595251881Speter                          incremental, cancel_func, cancel_baton,
596251881Speter                          scratch_pool));
597251881Speter  return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool));
598251881Speter}
599251881Speter
600251881Spetersvn_error_t *
601251881Spetersvn_fs_hotcopy(const char *src_path, const char *dest_path,
602251881Speter               svn_boolean_t clean, apr_pool_t *pool)
603251881Speter{
604251881Speter  return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean,
605251881Speter                                         FALSE, NULL, NULL, pool));
606251881Speter}
607251881Speter
608251881Spetersvn_error_t *
609251881Spetersvn_fs_pack(const char *path,
610251881Speter            svn_fs_pack_notify_t notify_func,
611251881Speter            void *notify_baton,
612251881Speter            svn_cancel_func_t cancel_func,
613251881Speter            void *cancel_baton,
614251881Speter            apr_pool_t *pool)
615251881Speter{
616251881Speter  fs_library_vtable_t *vtable;
617251881Speter  svn_fs_t *fs;
618251881Speter
619251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
620251881Speter  fs = fs_new(NULL, pool);
621251881Speter
622251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
623251881Speter                       vtable->pack_fs(fs, path, notify_func, notify_baton,
624251881Speter                                       cancel_func, cancel_baton, pool,
625251881Speter                                       common_pool));
626251881Speter  return SVN_NO_ERROR;
627251881Speter}
628251881Speter
629251881Spetersvn_error_t *
630251881Spetersvn_fs_recover(const char *path,
631251881Speter               svn_cancel_func_t cancel_func, void *cancel_baton,
632251881Speter               apr_pool_t *pool)
633251881Speter{
634251881Speter  fs_library_vtable_t *vtable;
635251881Speter  svn_fs_t *fs;
636251881Speter
637251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
638251881Speter  fs = fs_new(NULL, pool);
639251881Speter
640251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
641251881Speter                       vtable->open_fs_for_recovery(fs, path, pool,
642251881Speter                                                    common_pool));
643251881Speter  return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton,
644251881Speter                                         pool));
645251881Speter}
646251881Speter
647251881Spetersvn_error_t *
648251881Spetersvn_fs_verify_root(svn_fs_root_t *root,
649251881Speter                   apr_pool_t *scratch_pool)
650251881Speter{
651251881Speter  svn_fs_t *fs = root->fs;
652251881Speter  SVN_ERR(fs->vtable->verify_root(root, scratch_pool));
653251881Speter
654251881Speter  return SVN_NO_ERROR;
655251881Speter}
656251881Speter
657251881Spetersvn_error_t *
658251881Spetersvn_fs_freeze(svn_fs_t *fs,
659251881Speter              svn_fs_freeze_func_t freeze_func,
660251881Speter              void *freeze_baton,
661251881Speter              apr_pool_t *pool)
662251881Speter{
663251881Speter  SVN_ERR(fs->vtable->freeze(fs, freeze_func, freeze_baton, pool));
664251881Speter
665251881Speter  return SVN_NO_ERROR;
666251881Speter}
667251881Speter
668251881Speter
669251881Speter/* --- Berkeley-specific functions --- */
670251881Speter
671251881Spetersvn_error_t *
672251881Spetersvn_fs_create_berkeley(svn_fs_t *fs, const char *path)
673251881Speter{
674251881Speter  fs_library_vtable_t *vtable;
675251881Speter
676251881Speter  SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool));
677251881Speter
678251881Speter  /* Create the FS directory and write out the fsap-name file. */
679251881Speter  SVN_ERR(svn_io_dir_make_sgid(path, APR_OS_DEFAULT, fs->pool));
680251881Speter  SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool));
681251881Speter
682251881Speter  /* Perform the actual creation. */
683251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
684251881Speter                       vtable->create(fs, path, fs->pool, common_pool));
685251881Speter  SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
686251881Speter
687251881Speter  return SVN_NO_ERROR;
688251881Speter}
689251881Speter
690251881Spetersvn_error_t *
691251881Spetersvn_fs_open_berkeley(svn_fs_t *fs, const char *path)
692251881Speter{
693251881Speter  fs_library_vtable_t *vtable;
694251881Speter
695251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, fs->pool));
696251881Speter  SVN_MUTEX__WITH_LOCK(common_pool_lock,
697251881Speter                       vtable->open_fs(fs, path, fs->pool, common_pool));
698251881Speter  SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
699251881Speter
700251881Speter  return SVN_NO_ERROR;
701251881Speter}
702251881Speter
703251881Speterconst char *
704251881Spetersvn_fs_berkeley_path(svn_fs_t *fs, apr_pool_t *pool)
705251881Speter{
706251881Speter  return svn_fs_path(fs, pool);
707251881Speter}
708251881Speter
709251881Spetersvn_error_t *
710251881Spetersvn_fs_delete_berkeley(const char *path, apr_pool_t *pool)
711251881Speter{
712251881Speter  return svn_error_trace(svn_fs_delete_fs(path, pool));
713251881Speter}
714251881Speter
715251881Spetersvn_error_t *
716251881Spetersvn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path,
717251881Speter                        svn_boolean_t clean_logs, apr_pool_t *pool)
718251881Speter{
719251881Speter  return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean_logs,
720251881Speter                                         FALSE, NULL, NULL, pool));
721251881Speter}
722251881Speter
723251881Spetersvn_error_t *
724251881Spetersvn_fs_berkeley_recover(const char *path, apr_pool_t *pool)
725251881Speter{
726251881Speter  return svn_error_trace(svn_fs_recover(path, NULL, NULL, pool));
727251881Speter}
728251881Speter
729251881Spetersvn_error_t *
730251881Spetersvn_fs_set_berkeley_errcall(svn_fs_t *fs,
731251881Speter                            void (*handler)(const char *errpfx, char *msg))
732251881Speter{
733251881Speter  return svn_error_trace(fs->vtable->bdb_set_errcall(fs, handler));
734251881Speter}
735251881Speter
736251881Spetersvn_error_t *
737251881Spetersvn_fs_berkeley_logfiles(apr_array_header_t **logfiles,
738251881Speter                         const char *path,
739251881Speter                         svn_boolean_t only_unused,
740251881Speter                         apr_pool_t *pool)
741251881Speter{
742251881Speter  fs_library_vtable_t *vtable;
743251881Speter
744251881Speter  SVN_ERR(fs_library_vtable(&vtable, path, pool));
745251881Speter  return svn_error_trace(vtable->bdb_logfiles(logfiles, path, only_unused,
746251881Speter                                              pool));
747251881Speter}
748251881Speter
749251881Speter
750251881Speter/* --- Transaction functions --- */
751251881Speter
752251881Spetersvn_error_t *
753251881Spetersvn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
754251881Speter                  apr_uint32_t flags, apr_pool_t *pool)
755251881Speter{
756251881Speter  return svn_error_trace(fs->vtable->begin_txn(txn_p, fs, rev, flags, pool));
757251881Speter}
758251881Speter
759251881Speter
760251881Spetersvn_error_t *
761251881Spetersvn_fs_begin_txn(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
762251881Speter                 apr_pool_t *pool)
763251881Speter{
764251881Speter  return svn_error_trace(svn_fs_begin_txn2(txn_p, fs, rev, 0, pool));
765251881Speter}
766251881Speter
767251881Speter
768251881Spetersvn_error_t *
769251881Spetersvn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
770251881Speter                  svn_fs_txn_t *txn, apr_pool_t *pool)
771251881Speter{
772251881Speter  svn_error_t *err;
773251881Speter
774251881Speter  *new_rev = SVN_INVALID_REVNUM;
775251881Speter  if (conflict_p)
776251881Speter    *conflict_p = NULL;
777251881Speter
778251881Speter  err = txn->vtable->commit(conflict_p, new_rev, txn, pool);
779251881Speter
780251881Speter#ifdef SVN_DEBUG
781251881Speter  /* Check postconditions. */
782251881Speter  if (conflict_p)
783251881Speter    {
784251881Speter      SVN_ERR_ASSERT_E(! (SVN_IS_VALID_REVNUM(*new_rev) && *conflict_p != NULL),
785251881Speter                       err);
786251881Speter      SVN_ERR_ASSERT_E((*conflict_p != NULL)
787251881Speter                       == (err && err->apr_err == SVN_ERR_FS_CONFLICT),
788251881Speter                       err);
789251881Speter    }
790251881Speter#endif
791251881Speter
792251881Speter  SVN_ERR(err);
793251881Speter
794251881Speter#ifdef PACK_AFTER_EVERY_COMMIT
795251881Speter  {
796251881Speter    svn_fs_t *fs = txn->fs;
797251881Speter    const char *fs_path = svn_fs_path(fs, pool);
798251881Speter    err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
799251881Speter    if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
800251881Speter      /* Pre-1.6 filesystem. */
801251881Speter      svn_error_clear(err);
802251881Speter    else if (err)
803251881Speter      /* Real error. */
804251881Speter      return svn_error_trace(err);
805251881Speter  }
806251881Speter#endif
807251881Speter
808251881Speter  return SVN_NO_ERROR;
809251881Speter}
810251881Speter
811251881Speter
812251881Spetersvn_error_t *
813251881Spetersvn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool)
814251881Speter{
815251881Speter  return svn_error_trace(txn->vtable->abort(txn, pool));
816251881Speter}
817251881Speter
818251881Spetersvn_error_t *
819251881Spetersvn_fs_purge_txn(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
820251881Speter{
821251881Speter  return svn_error_trace(fs->vtable->purge_txn(fs, txn_id, pool));
822251881Speter}
823251881Speter
824251881Spetersvn_error_t *
825251881Spetersvn_fs_txn_name(const char **name_p, svn_fs_txn_t *txn, apr_pool_t *pool)
826251881Speter{
827251881Speter  *name_p = apr_pstrdup(pool, txn->id);
828251881Speter  return SVN_NO_ERROR;
829251881Speter}
830251881Speter
831251881Spetersvn_revnum_t
832251881Spetersvn_fs_txn_base_revision(svn_fs_txn_t *txn)
833251881Speter{
834251881Speter  return txn->base_rev;
835251881Speter}
836251881Speter
837251881Spetersvn_error_t *
838251881Spetersvn_fs_open_txn(svn_fs_txn_t **txn, svn_fs_t *fs, const char *name,
839251881Speter                apr_pool_t *pool)
840251881Speter{
841251881Speter  return svn_error_trace(fs->vtable->open_txn(txn, fs, name, pool));
842251881Speter}
843251881Speter
844251881Spetersvn_error_t *
845251881Spetersvn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs,
846251881Speter                         apr_pool_t *pool)
847251881Speter{
848251881Speter  return svn_error_trace(fs->vtable->list_transactions(names_p, fs, pool));
849251881Speter}
850251881Speter
851251881Spetersvn_error_t *
852251881Spetersvn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn,
853251881Speter                const char *propname, apr_pool_t *pool)
854251881Speter{
855251881Speter  return svn_error_trace(txn->vtable->get_prop(value_p, txn, propname, pool));
856251881Speter}
857251881Speter
858251881Spetersvn_error_t *
859251881Spetersvn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool)
860251881Speter{
861251881Speter  return svn_error_trace(txn->vtable->get_proplist(table_p, txn, pool));
862251881Speter}
863251881Speter
864251881Spetersvn_error_t *
865251881Spetersvn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name,
866251881Speter                       const svn_string_t *value, apr_pool_t *pool)
867251881Speter{
868251881Speter  return svn_error_trace(txn->vtable->change_prop(txn, name, value, pool));
869251881Speter}
870251881Speter
871251881Spetersvn_error_t *
872251881Spetersvn_fs_change_txn_props(svn_fs_txn_t *txn, const apr_array_header_t *props,
873251881Speter                        apr_pool_t *pool)
874251881Speter{
875251881Speter  return svn_error_trace(txn->vtable->change_props(txn, props, pool));
876251881Speter}
877251881Speter
878251881Speter
879251881Speter/* --- Root functions --- */
880251881Speter
881251881Spetersvn_error_t *
882251881Spetersvn_fs_revision_root(svn_fs_root_t **root_p, svn_fs_t *fs, svn_revnum_t rev,
883251881Speter                     apr_pool_t *pool)
884251881Speter{
885251881Speter  /* We create a subpool for each root object to allow us to implement
886251881Speter     svn_fs_close_root.  */
887251881Speter  apr_pool_t *subpool = svn_pool_create(pool);
888251881Speter  return svn_error_trace(fs->vtable->revision_root(root_p, fs, rev, subpool));
889251881Speter}
890251881Speter
891251881Spetersvn_error_t *
892251881Spetersvn_fs_txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn, apr_pool_t *pool)
893251881Speter{
894251881Speter  /* We create a subpool for each root object to allow us to implement
895251881Speter     svn_fs_close_root.  */
896251881Speter  apr_pool_t *subpool = svn_pool_create(pool);
897251881Speter  return svn_error_trace(txn->vtable->root(root_p, txn, subpool));
898251881Speter}
899251881Speter
900251881Spetervoid
901251881Spetersvn_fs_close_root(svn_fs_root_t *root)
902251881Speter{
903251881Speter  svn_pool_destroy(root->pool);
904251881Speter}
905251881Speter
906251881Spetersvn_fs_t *
907251881Spetersvn_fs_root_fs(svn_fs_root_t *root)
908251881Speter{
909251881Speter  return root->fs;
910251881Speter}
911251881Speter
912251881Spetersvn_boolean_t
913251881Spetersvn_fs_is_txn_root(svn_fs_root_t *root)
914251881Speter{
915251881Speter  return root->is_txn_root;
916251881Speter}
917251881Speter
918251881Spetersvn_boolean_t
919251881Spetersvn_fs_is_revision_root(svn_fs_root_t *root)
920251881Speter{
921251881Speter  return !root->is_txn_root;
922251881Speter}
923251881Speter
924251881Speterconst char *
925251881Spetersvn_fs_txn_root_name(svn_fs_root_t *root, apr_pool_t *pool)
926251881Speter{
927251881Speter  return root->is_txn_root ? apr_pstrdup(pool, root->txn) : NULL;
928251881Speter}
929251881Speter
930251881Spetersvn_revnum_t
931251881Spetersvn_fs_txn_root_base_revision(svn_fs_root_t *root)
932251881Speter{
933251881Speter  return root->is_txn_root ? root->rev : SVN_INVALID_REVNUM;
934251881Speter}
935251881Speter
936251881Spetersvn_revnum_t
937251881Spetersvn_fs_revision_root_revision(svn_fs_root_t *root)
938251881Speter{
939251881Speter  return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
940251881Speter}
941251881Speter
942251881Spetersvn_error_t *
943251881Spetersvn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
944251881Speter                      apr_pool_t *pool)
945251881Speter{
946251881Speter  return root->vtable->paths_changed(changed_paths_p, root, pool);
947251881Speter}
948251881Speter
949251881Spetersvn_error_t *
950251881Spetersvn_fs_paths_changed(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
951251881Speter                     apr_pool_t *pool)
952251881Speter{
953251881Speter  apr_hash_t *changed_paths_new_structs;
954251881Speter  apr_hash_index_t *hi;
955251881Speter
956251881Speter  SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
957251881Speter  *changed_paths_p = apr_hash_make(pool);
958251881Speter  for (hi = apr_hash_first(pool, changed_paths_new_structs);
959251881Speter       hi;
960251881Speter       hi = apr_hash_next(hi))
961251881Speter    {
962251881Speter      const void *vkey;
963251881Speter      apr_ssize_t klen;
964251881Speter      void *vval;
965251881Speter      svn_fs_path_change2_t *val;
966251881Speter      svn_fs_path_change_t *change;
967251881Speter      apr_hash_this(hi, &vkey, &klen, &vval);
968251881Speter      val = vval;
969251881Speter      change = apr_palloc(pool, sizeof(*change));
970251881Speter      change->node_rev_id = val->node_rev_id;
971251881Speter      change->change_kind = val->change_kind;
972251881Speter      change->text_mod = val->text_mod;
973251881Speter      change->prop_mod = val->prop_mod;
974251881Speter      apr_hash_set(*changed_paths_p, vkey, klen, change);
975251881Speter    }
976251881Speter  return SVN_NO_ERROR;
977251881Speter}
978251881Speter
979251881Spetersvn_error_t *
980251881Spetersvn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root,
981251881Speter                  const char *path, apr_pool_t *pool)
982251881Speter{
983251881Speter  return svn_error_trace(root->vtable->check_path(kind_p, root, path, pool));
984251881Speter}
985251881Speter
986251881Spetersvn_error_t *
987251881Spetersvn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
988251881Speter                    const char *path, apr_pool_t *pool)
989251881Speter{
990251881Speter  return svn_error_trace(root->vtable->node_history(history_p, root, path,
991251881Speter                                                    pool));
992251881Speter}
993251881Speter
994251881Spetersvn_error_t *
995251881Spetersvn_fs_is_dir(svn_boolean_t *is_dir, svn_fs_root_t *root, const char *path,
996251881Speter              apr_pool_t *pool)
997251881Speter{
998251881Speter  svn_node_kind_t kind;
999251881Speter
1000251881Speter  SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
1001251881Speter  *is_dir = (kind == svn_node_dir);
1002251881Speter  return SVN_NO_ERROR;
1003251881Speter}
1004251881Speter
1005251881Spetersvn_error_t *
1006251881Spetersvn_fs_is_file(svn_boolean_t *is_file, svn_fs_root_t *root, const char *path,
1007251881Speter               apr_pool_t *pool)
1008251881Speter{
1009251881Speter  svn_node_kind_t kind;
1010251881Speter
1011251881Speter  SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
1012251881Speter  *is_file = (kind == svn_node_file);
1013251881Speter  return SVN_NO_ERROR;
1014251881Speter}
1015251881Speter
1016251881Spetersvn_error_t *
1017251881Spetersvn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root,
1018251881Speter               const char *path, apr_pool_t *pool)
1019251881Speter{
1020251881Speter  return svn_error_trace(root->vtable->node_id(id_p, root, path, pool));
1021251881Speter}
1022251881Speter
1023251881Spetersvn_error_t *
1024251881Spetersvn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root,
1025251881Speter                        const char *path, apr_pool_t *pool)
1026251881Speter{
1027251881Speter  return svn_error_trace(root->vtable->node_created_rev(revision, root, path,
1028251881Speter                                                        pool));
1029251881Speter}
1030251881Speter
1031251881Spetersvn_error_t *
1032251881Spetersvn_fs_node_origin_rev(svn_revnum_t *revision, svn_fs_root_t *root,
1033251881Speter                       const char *path, apr_pool_t *pool)
1034251881Speter{
1035251881Speter  return svn_error_trace(root->vtable->node_origin_rev(revision, root, path,
1036251881Speter                                                       pool));
1037251881Speter}
1038251881Speter
1039251881Spetersvn_error_t *
1040251881Spetersvn_fs_node_created_path(const char **created_path, svn_fs_root_t *root,
1041251881Speter                         const char *path, apr_pool_t *pool)
1042251881Speter{
1043251881Speter  return svn_error_trace(root->vtable->node_created_path(created_path, root,
1044251881Speter                                                         path, pool));
1045251881Speter}
1046251881Speter
1047251881Spetersvn_error_t *
1048251881Spetersvn_fs_node_prop(svn_string_t **value_p, svn_fs_root_t *root,
1049251881Speter                 const char *path, const char *propname, apr_pool_t *pool)
1050251881Speter{
1051251881Speter  return svn_error_trace(root->vtable->node_prop(value_p, root, path,
1052251881Speter                                                 propname, pool));
1053251881Speter}
1054251881Speter
1055251881Spetersvn_error_t *
1056251881Spetersvn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
1057251881Speter                     const char *path, apr_pool_t *pool)
1058251881Speter{
1059251881Speter  return svn_error_trace(root->vtable->node_proplist(table_p, root, path,
1060251881Speter                                                     pool));
1061251881Speter}
1062251881Speter
1063251881Spetersvn_error_t *
1064251881Spetersvn_fs_change_node_prop(svn_fs_root_t *root, const char *path,
1065251881Speter                        const char *name, const svn_string_t *value,
1066251881Speter                        apr_pool_t *pool)
1067251881Speter{
1068251881Speter  return svn_error_trace(root->vtable->change_node_prop(root, path, name,
1069251881Speter                                                        value, pool));
1070251881Speter}
1071251881Speter
1072251881Spetersvn_error_t *
1073251881Spetersvn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
1074251881Speter                     const char *path1, svn_fs_root_t *root2,
1075251881Speter                     const char *path2, apr_pool_t *pool)
1076251881Speter{
1077251881Speter  return svn_error_trace(root1->vtable->props_changed(changed_p,
1078251881Speter                                                      root1, path1,
1079251881Speter                                                      root2, path2,
1080251881Speter                                                      pool));
1081251881Speter}
1082251881Speter
1083251881Spetersvn_error_t *
1084251881Spetersvn_fs_copied_from(svn_revnum_t *rev_p, const char **path_p,
1085251881Speter                   svn_fs_root_t *root, const char *path, apr_pool_t *pool)
1086251881Speter{
1087251881Speter  return svn_error_trace(root->vtable->copied_from(rev_p, path_p, root, path,
1088251881Speter                                                   pool));
1089251881Speter}
1090251881Speter
1091251881Spetersvn_error_t *
1092251881Spetersvn_fs_closest_copy(svn_fs_root_t **root_p, const char **path_p,
1093251881Speter                    svn_fs_root_t *root, const char *path, apr_pool_t *pool)
1094251881Speter{
1095251881Speter  return svn_error_trace(root->vtable->closest_copy(root_p, path_p,
1096251881Speter                                                    root, path, pool));
1097251881Speter}
1098251881Speter
1099251881Spetersvn_error_t *
1100251881Spetersvn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog,
1101251881Speter                      svn_fs_root_t *root,
1102251881Speter                      const apr_array_header_t *paths,
1103251881Speter                      svn_mergeinfo_inheritance_t inherit,
1104251881Speter                      svn_boolean_t include_descendants,
1105251881Speter                      svn_boolean_t adjust_inherited_mergeinfo,
1106251881Speter                      apr_pool_t *result_pool,
1107251881Speter                      apr_pool_t *scratch_pool)
1108251881Speter{
1109251881Speter  return svn_error_trace(root->vtable->get_mergeinfo(
1110251881Speter    catalog, root, paths, inherit, include_descendants,
1111251881Speter    adjust_inherited_mergeinfo, result_pool, scratch_pool));
1112251881Speter}
1113251881Speter
1114251881Spetersvn_error_t *
1115251881Spetersvn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
1116251881Speter                     svn_fs_root_t *root,
1117251881Speter                     const apr_array_header_t *paths,
1118251881Speter                     svn_mergeinfo_inheritance_t inherit,
1119251881Speter                     svn_boolean_t include_descendants,
1120251881Speter                     apr_pool_t *pool)
1121251881Speter{
1122251881Speter  return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
1123251881Speter                                                     inherit,
1124251881Speter                                                     include_descendants,
1125251881Speter                                                     TRUE, pool, pool));
1126251881Speter}
1127251881Speter
1128251881Spetersvn_error_t *
1129251881Spetersvn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root,
1130251881Speter             const char *source_path, svn_fs_root_t *target_root,
1131251881Speter             const char *target_path, svn_fs_root_t *ancestor_root,
1132251881Speter             const char *ancestor_path, apr_pool_t *pool)
1133251881Speter{
1134251881Speter  return svn_error_trace(target_root->vtable->merge(conflict_p,
1135251881Speter                                                    source_root, source_path,
1136251881Speter                                                    target_root, target_path,
1137251881Speter                                                    ancestor_root,
1138251881Speter                                                    ancestor_path, pool));
1139251881Speter}
1140251881Speter
1141251881Spetersvn_error_t *
1142251881Spetersvn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root,
1143251881Speter                   const char *path, apr_pool_t *pool)
1144251881Speter{
1145251881Speter  return svn_error_trace(root->vtable->dir_entries(entries_p, root, path,
1146251881Speter                                                   pool));
1147251881Speter}
1148251881Speter
1149251881Spetersvn_error_t *
1150251881Spetersvn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
1151251881Speter{
1152251881Speter  SVN_ERR(svn_fs__path_valid(path, pool));
1153251881Speter  return svn_error_trace(root->vtable->make_dir(root, path, pool));
1154251881Speter}
1155251881Speter
1156251881Spetersvn_error_t *
1157251881Spetersvn_fs_delete(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
1158251881Speter{
1159251881Speter  return svn_error_trace(root->vtable->delete_node(root, path, pool));
1160251881Speter}
1161251881Speter
1162251881Spetersvn_error_t *
1163251881Spetersvn_fs_copy(svn_fs_root_t *from_root, const char *from_path,
1164251881Speter            svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool)
1165251881Speter{
1166251881Speter  SVN_ERR(svn_fs__path_valid(to_path, pool));
1167251881Speter  return svn_error_trace(to_root->vtable->copy(from_root, from_path,
1168251881Speter                                               to_root, to_path, pool));
1169251881Speter}
1170251881Speter
1171251881Spetersvn_error_t *
1172251881Spetersvn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root,
1173251881Speter                     const char *path, apr_pool_t *pool)
1174251881Speter{
1175251881Speter  return svn_error_trace(to_root->vtable->revision_link(from_root, to_root,
1176251881Speter                                                        path, pool));
1177251881Speter}
1178251881Speter
1179251881Spetersvn_error_t *
1180251881Spetersvn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root,
1181251881Speter                   const char *path, apr_pool_t *pool)
1182251881Speter{
1183251881Speter  return svn_error_trace(root->vtable->file_length(length_p, root, path,
1184251881Speter                                                   pool));
1185251881Speter}
1186251881Speter
1187251881Spetersvn_error_t *
1188251881Spetersvn_fs_file_checksum(svn_checksum_t **checksum,
1189251881Speter                     svn_checksum_kind_t kind,
1190251881Speter                     svn_fs_root_t *root,
1191251881Speter                     const char *path,
1192251881Speter                     svn_boolean_t force,
1193251881Speter                     apr_pool_t *pool)
1194251881Speter{
1195251881Speter  SVN_ERR(root->vtable->file_checksum(checksum, kind, root, path, pool));
1196251881Speter
1197251881Speter  if (force && (*checksum == NULL || (*checksum)->kind != kind))
1198251881Speter    {
1199251881Speter      svn_stream_t *contents, *checksum_contents;
1200251881Speter
1201251881Speter      SVN_ERR(svn_fs_file_contents(&contents, root, path, pool));
1202251881Speter      checksum_contents = svn_stream_checksummed2(contents, checksum, NULL,
1203251881Speter                                                  kind, TRUE, pool);
1204251881Speter
1205251881Speter      /* This will force a read of any remaining data (which is all of it in
1206251881Speter         this case) and dump the checksum into checksum->digest. */
1207251881Speter      SVN_ERR(svn_stream_close(checksum_contents));
1208251881Speter    }
1209251881Speter
1210251881Speter  return SVN_NO_ERROR;
1211251881Speter}
1212251881Speter
1213251881Spetersvn_error_t *
1214251881Spetersvn_fs_file_md5_checksum(unsigned char digest[],
1215251881Speter                         svn_fs_root_t *root,
1216251881Speter                         const char *path,
1217251881Speter                         apr_pool_t *pool)
1218251881Speter{
1219251881Speter  svn_checksum_t *md5sum;
1220251881Speter
1221251881Speter  SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE,
1222251881Speter                               pool));
1223251881Speter  memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE);
1224251881Speter
1225251881Speter  return SVN_NO_ERROR;
1226251881Speter}
1227251881Speter
1228251881Spetersvn_error_t *
1229251881Spetersvn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root,
1230251881Speter                     const char *path, apr_pool_t *pool)
1231251881Speter{
1232251881Speter  return svn_error_trace(root->vtable->file_contents(contents, root, path,
1233251881Speter                                                     pool));
1234251881Speter}
1235251881Speter
1236251881Spetersvn_error_t *
1237251881Spetersvn_fs_try_process_file_contents(svn_boolean_t *success,
1238251881Speter                                 svn_fs_root_t *root,
1239251881Speter                                 const char *path,
1240251881Speter                                 svn_fs_process_contents_func_t processor,
1241251881Speter                                 void* baton,
1242251881Speter                                 apr_pool_t *pool)
1243251881Speter{
1244251881Speter  /* if the FS doesn't implement this function, report a "failed" attempt */
1245251881Speter  if (root->vtable->try_process_file_contents == NULL)
1246251881Speter    {
1247251881Speter      *success = FALSE;
1248251881Speter      return SVN_NO_ERROR;
1249251881Speter    }
1250251881Speter
1251251881Speter  return svn_error_trace(root->vtable->try_process_file_contents(
1252251881Speter                         success,
1253251881Speter                         root, path,
1254251881Speter                         processor, baton, pool));
1255251881Speter}
1256251881Speter
1257251881Spetersvn_error_t *
1258251881Spetersvn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
1259251881Speter{
1260251881Speter  SVN_ERR(svn_fs__path_valid(path, pool));
1261251881Speter  return svn_error_trace(root->vtable->make_file(root, path, pool));
1262251881Speter}
1263251881Speter
1264251881Spetersvn_error_t *
1265251881Spetersvn_fs_apply_textdelta(svn_txdelta_window_handler_t *contents_p,
1266251881Speter                       void **contents_baton_p, svn_fs_root_t *root,
1267251881Speter                       const char *path, const char *base_checksum,
1268251881Speter                       const char *result_checksum, apr_pool_t *pool)
1269251881Speter{
1270251881Speter  svn_checksum_t *base, *result;
1271251881Speter
1272251881Speter  /* TODO: If we ever rev this API, we should make the supplied checksums
1273251881Speter     svn_checksum_t structs. */
1274251881Speter  SVN_ERR(svn_checksum_parse_hex(&base, svn_checksum_md5, base_checksum,
1275251881Speter                                 pool));
1276251881Speter  SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum,
1277251881Speter                                 pool));
1278251881Speter
1279251881Speter  return svn_error_trace(root->vtable->apply_textdelta(contents_p,
1280251881Speter                                                       contents_baton_p,
1281251881Speter                                                       root,
1282251881Speter                                                       path,
1283251881Speter                                                       base,
1284251881Speter                                                       result,
1285251881Speter                                                       pool));
1286251881Speter}
1287251881Speter
1288251881Spetersvn_error_t *
1289251881Spetersvn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root,
1290251881Speter                  const char *path, const char *result_checksum,
1291251881Speter                  apr_pool_t *pool)
1292251881Speter{
1293251881Speter  svn_checksum_t *result;
1294251881Speter
1295251881Speter  /* TODO: If we ever rev this API, we should make the supplied checksum an
1296251881Speter     svn_checksum_t struct. */
1297251881Speter  SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum,
1298251881Speter                                 pool));
1299251881Speter
1300251881Speter  return svn_error_trace(root->vtable->apply_text(contents_p, root, path,
1301251881Speter                                                  result, pool));
1302251881Speter}
1303251881Speter
1304251881Spetersvn_error_t *
1305251881Spetersvn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
1306251881Speter                        const char *path1, svn_fs_root_t *root2,
1307251881Speter                        const char *path2, apr_pool_t *pool)
1308251881Speter{
1309251881Speter  return svn_error_trace(root1->vtable->contents_changed(changed_p,
1310251881Speter                                                         root1, path1,
1311251881Speter                                                         root2, path2,
1312251881Speter                                                         pool));
1313251881Speter}
1314251881Speter
1315251881Spetersvn_error_t *
1316251881Spetersvn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool)
1317251881Speter{
1318251881Speter  return svn_error_trace(fs->vtable->youngest_rev(youngest_p, fs, pool));
1319251881Speter}
1320251881Speter
1321251881Spetersvn_error_t *
1322251881Spetersvn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool)
1323251881Speter{
1324251881Speter  return svn_error_trace(fs->vtable->deltify(fs, revision, pool));
1325251881Speter}
1326251881Speter
1327251881Spetersvn_error_t *
1328251881Spetersvn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev,
1329251881Speter                     const char *propname, apr_pool_t *pool)
1330251881Speter{
1331251881Speter  return svn_error_trace(fs->vtable->revision_prop(value_p, fs, rev,
1332251881Speter                                                   propname, pool));
1333251881Speter}
1334251881Speter
1335251881Spetersvn_error_t *
1336251881Spetersvn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev,
1337251881Speter                         apr_pool_t *pool)
1338251881Speter{
1339251881Speter  return svn_error_trace(fs->vtable->revision_proplist(table_p, fs, rev,
1340251881Speter                                                       pool));
1341251881Speter}
1342251881Speter
1343251881Spetersvn_error_t *
1344251881Spetersvn_fs_change_rev_prop2(svn_fs_t *fs, svn_revnum_t rev, const char *name,
1345251881Speter                        const svn_string_t *const *old_value_p,
1346251881Speter                        const svn_string_t *value, apr_pool_t *pool)
1347251881Speter{
1348251881Speter  return svn_error_trace(fs->vtable->change_rev_prop(fs, rev, name,
1349251881Speter                                                     old_value_p,
1350251881Speter                                                     value, pool));
1351251881Speter}
1352251881Speter
1353251881Spetersvn_error_t *
1354251881Spetersvn_fs_change_rev_prop(svn_fs_t *fs, svn_revnum_t rev, const char *name,
1355251881Speter                       const svn_string_t *value, apr_pool_t *pool)
1356251881Speter{
1357251881Speter  return svn_error_trace(
1358251881Speter           svn_fs_change_rev_prop2(fs, rev, name, NULL, value, pool));
1359251881Speter}
1360251881Speter
1361251881Spetersvn_error_t *
1362251881Spetersvn_fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p,
1363251881Speter                             svn_fs_root_t *source_root,
1364251881Speter                             const char *source_path,
1365251881Speter                             svn_fs_root_t *target_root,
1366251881Speter                             const char *target_path, apr_pool_t *pool)
1367251881Speter{
1368251881Speter  return svn_error_trace(target_root->vtable->get_file_delta_stream(
1369251881Speter                           stream_p,
1370251881Speter                           source_root, source_path,
1371251881Speter                           target_root, target_path, pool));
1372251881Speter}
1373251881Speter
1374251881Spetersvn_error_t *
1375251881Spetersvn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
1376251881Speter{
1377251881Speter  /* If you change this, consider changing svn_fs__identifier(). */
1378251881Speter  *uuid = apr_pstrdup(pool, fs->uuid);
1379251881Speter  return SVN_NO_ERROR;
1380251881Speter}
1381251881Speter
1382251881Spetersvn_error_t *
1383251881Spetersvn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool)
1384251881Speter{
1385251881Speter  if (! uuid)
1386251881Speter    {
1387251881Speter      uuid = svn_uuid_generate(pool);
1388251881Speter    }
1389251881Speter  else
1390251881Speter    {
1391251881Speter      apr_uuid_t parsed_uuid;
1392251881Speter      apr_status_t apr_err = apr_uuid_parse(&parsed_uuid, uuid);
1393251881Speter      if (apr_err)
1394251881Speter        return svn_error_createf(SVN_ERR_BAD_UUID, NULL,
1395251881Speter                                 _("Malformed UUID '%s'"), uuid);
1396251881Speter    }
1397251881Speter  return svn_error_trace(fs->vtable->set_uuid(fs, uuid, pool));
1398251881Speter}
1399251881Speter
1400251881Spetersvn_error_t *
1401251881Spetersvn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
1402251881Speter            const char *token, const char *comment,
1403251881Speter            svn_boolean_t is_dav_comment, apr_time_t expiration_date,
1404251881Speter            svn_revnum_t current_rev, svn_boolean_t steal_lock,
1405251881Speter            apr_pool_t *pool)
1406251881Speter{
1407251881Speter  /* Enforce that the comment be xml-escapable. */
1408251881Speter  if (comment)
1409251881Speter    {
1410251881Speter      if (! svn_xml_is_xml_safe(comment, strlen(comment)))
1411251881Speter        return svn_error_create
1412251881Speter          (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
1413251881Speter           _("Lock comment contains illegal characters"));
1414251881Speter    }
1415251881Speter
1416251881Speter  /* Enforce that the token be an XML-safe URI. */
1417251881Speter  if (token)
1418251881Speter    {
1419251881Speter      const char *c;
1420251881Speter
1421251881Speter      if (strncmp(token, "opaquelocktoken:", 16))
1422251881Speter        return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
1423251881Speter                                 _("Lock token URI '%s' has bad scheme; "
1424251881Speter                                   "expected '%s'"),
1425251881Speter                                 token, "opaquelocktoken");
1426251881Speter
1427251881Speter      for (c = token; *c; c++)
1428251881Speter        if (! svn_ctype_isascii(*c))
1429251881Speter          return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
1430251881Speter                                   _("Lock token '%s' is not ASCII "
1431251881Speter                                     "at byte %u"),
1432251881Speter                                   token, (unsigned)(c - token));
1433251881Speter
1434251881Speter      /* strlen(token) == c - token. */
1435251881Speter      if (! svn_xml_is_xml_safe(token, c - token))
1436251881Speter        return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
1437251881Speter                                 _("Lock token URI '%s' is not XML-safe"),
1438251881Speter                                 token);
1439251881Speter    }
1440251881Speter
1441251881Speter  if (expiration_date < 0)
1442251881Speter        return svn_error_create
1443251881Speter          (SVN_ERR_INCORRECT_PARAMS, NULL,
1444251881Speter           _("Negative expiration date passed to svn_fs_lock"));
1445251881Speter
1446251881Speter  return svn_error_trace(fs->vtable->lock(lock, fs, path, token, comment,
1447251881Speter                                          is_dav_comment, expiration_date,
1448251881Speter                                          current_rev, steal_lock, pool));
1449251881Speter}
1450251881Speter
1451251881Spetersvn_error_t *
1452251881Spetersvn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool)
1453251881Speter{
1454251881Speter  return svn_error_trace(fs->vtable->generate_lock_token(token, fs, pool));
1455251881Speter}
1456251881Speter
1457251881Spetersvn_error_t *
1458251881Spetersvn_fs_unlock(svn_fs_t *fs, const char *path, const char *token,
1459251881Speter              svn_boolean_t break_lock, apr_pool_t *pool)
1460251881Speter{
1461251881Speter  return svn_error_trace(fs->vtable->unlock(fs, path, token, break_lock,
1462251881Speter                                            pool));
1463251881Speter}
1464251881Speter
1465251881Spetersvn_error_t *
1466251881Spetersvn_fs_get_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
1467251881Speter                apr_pool_t *pool)
1468251881Speter{
1469251881Speter  return svn_error_trace(fs->vtable->get_lock(lock, fs, path, pool));
1470251881Speter}
1471251881Speter
1472251881Spetersvn_error_t *
1473251881Spetersvn_fs_get_locks2(svn_fs_t *fs, const char *path, svn_depth_t depth,
1474251881Speter                  svn_fs_get_locks_callback_t get_locks_func,
1475251881Speter                  void *get_locks_baton, apr_pool_t *pool)
1476251881Speter{
1477251881Speter  SVN_ERR_ASSERT((depth == svn_depth_empty) ||
1478251881Speter                 (depth == svn_depth_files) ||
1479251881Speter                 (depth == svn_depth_immediates) ||
1480251881Speter                 (depth == svn_depth_infinity));
1481251881Speter  return svn_error_trace(fs->vtable->get_locks(fs, path, depth,
1482251881Speter                                               get_locks_func,
1483251881Speter                                               get_locks_baton, pool));
1484251881Speter}
1485251881Speter
1486251881Spetersvn_error_t *
1487251881Spetersvn_fs_get_locks(svn_fs_t *fs, const char *path,
1488251881Speter                 svn_fs_get_locks_callback_t get_locks_func,
1489251881Speter                 void *get_locks_baton, apr_pool_t *pool)
1490251881Speter{
1491251881Speter  return svn_error_trace(svn_fs_get_locks2(fs, path, svn_depth_infinity,
1492251881Speter                                           get_locks_func, get_locks_baton,
1493251881Speter                                           pool));
1494251881Speter}
1495251881Speter
1496251881Speter
1497251881Speter/* --- History functions --- */
1498251881Speter
1499251881Spetersvn_error_t *
1500251881Spetersvn_fs_history_prev(svn_fs_history_t **prev_history_p,
1501251881Speter                    svn_fs_history_t *history, svn_boolean_t cross_copies,
1502251881Speter                    apr_pool_t *pool)
1503251881Speter{
1504251881Speter  return svn_error_trace(history->vtable->prev(prev_history_p, history,
1505251881Speter                                               cross_copies, pool));
1506251881Speter}
1507251881Speter
1508251881Spetersvn_error_t *
1509251881Spetersvn_fs_history_location(const char **path, svn_revnum_t *revision,
1510251881Speter                        svn_fs_history_t *history, apr_pool_t *pool)
1511251881Speter{
1512251881Speter  return svn_error_trace(history->vtable->location(path, revision, history,
1513251881Speter                                                   pool));
1514251881Speter}
1515251881Speter
1516251881Speter
1517251881Speter/* --- Node-ID functions --- */
1518251881Speter
1519251881Spetersvn_fs_id_t *
1520251881Spetersvn_fs_parse_id(const char *data, apr_size_t len, apr_pool_t *pool)
1521251881Speter{
1522251881Speter  fs_library_vtable_t *vtable;
1523251881Speter  svn_error_t *err;
1524251881Speter
1525251881Speter  err = get_library_vtable(&vtable, SVN_FS_TYPE_BDB, pool);
1526251881Speter  if (err)
1527251881Speter    {
1528251881Speter      svn_error_clear(err);
1529251881Speter      return NULL;
1530251881Speter    }
1531251881Speter  return vtable->parse_id(data, len, pool);
1532251881Speter}
1533251881Speter
1534251881Spetersvn_string_t *
1535251881Spetersvn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool)
1536251881Speter{
1537251881Speter  return id->vtable->unparse(id, pool);
1538251881Speter}
1539251881Speter
1540251881Spetersvn_boolean_t
1541251881Spetersvn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b)
1542251881Speter{
1543251881Speter  return (a->vtable->compare(a, b) != -1);
1544251881Speter}
1545251881Speter
1546251881Speterint
1547251881Spetersvn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b)
1548251881Speter{
1549251881Speter  return a->vtable->compare(a, b);
1550251881Speter}
1551251881Speter
1552251881Spetersvn_error_t *
1553251881Spetersvn_fs_print_modules(svn_stringbuf_t *output,
1554251881Speter                     apr_pool_t *pool)
1555251881Speter{
1556251881Speter  const struct fs_type_defn *defn = fs_modules;
1557251881Speter  fs_library_vtable_t *vtable;
1558251881Speter  apr_pool_t *iterpool = svn_pool_create(pool);
1559251881Speter
1560251881Speter  while (defn)
1561251881Speter    {
1562251881Speter      char *line;
1563251881Speter      svn_error_t *err;
1564251881Speter
1565251881Speter      svn_pool_clear(iterpool);
1566251881Speter
1567251881Speter      err = get_library_vtable_direct(&vtable, defn, iterpool);
1568251881Speter      if (err)
1569251881Speter        {
1570251881Speter          if (err->apr_err == SVN_ERR_FS_UNKNOWN_FS_TYPE)
1571251881Speter            {
1572251881Speter              svn_error_clear(err);
1573251881Speter              defn = defn->next;
1574251881Speter              continue;
1575251881Speter            }
1576251881Speter          else
1577251881Speter            return err;
1578251881Speter        }
1579251881Speter
1580251881Speter      line = apr_psprintf(iterpool, "* fs_%s : %s\n",
1581251881Speter                          defn->fsap_name, vtable->get_description());
1582251881Speter      svn_stringbuf_appendcstr(output, line);
1583251881Speter      defn = defn->next;
1584251881Speter    }
1585251881Speter
1586251881Speter  svn_pool_destroy(iterpool);
1587251881Speter
1588251881Speter  return SVN_NO_ERROR;
1589251881Speter}
1590251881Speter
1591251881Spetersvn_fs_path_change2_t *
1592251881Spetersvn_fs_path_change2_create(const svn_fs_id_t *node_rev_id,
1593251881Speter                           svn_fs_path_change_kind_t change_kind,
1594251881Speter                           apr_pool_t *pool)
1595251881Speter{
1596251881Speter  return svn_fs__path_change_create_internal(node_rev_id, change_kind, pool);
1597251881Speter}
1598251881Speter
1599251881Speter/* Return the library version number. */
1600251881Speterconst svn_version_t *
1601251881Spetersvn_fs_version(void)
1602251881Speter{
1603251881Speter  SVN_VERSION_BODY;
1604251881Speter}
1605