fs-loader.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 843 行 · 第 1/2 页

C
843
字号
/*
 * fs_loader.c:  Front-end to the various FS back ends
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */


#include <string.h>
#include <apr.h>
#include <apr_hash.h>
#include <apr_dso.h>

#include "svn_types.h"
#include "svn_version.h"
#include "svn_pools.h"
#include "svn_fs.h"
#include "svn_path.h"
#include "svn_private_config.h"

#include "fs-loader.h"

/* This is defined by configure on platforms which use configure, but
   we need to define a fallback for Windows. */
#ifndef DEFAULT_FS_TYPE
#define DEFAULT_FS_TYPE "bdb"
#endif

#define FS_TYPE_FILENAME "fs-type"

/* The implementation of this library is deliberately not separated
   into multiple files, to avoid circular dependency problems with
   Unix static linking.  We want FS back ends to be able to use our
   functions without forcing applications to link against this library
   twice. */


/* --- Utility functions for the loader --- */

static const struct fs_type_defn {
  const char *fs_type;
  const char *fsap_name;
  fs_init_func_t initfunc;
} fs_modules[] = {
  {
    SVN_FS_TYPE_BDB, "base",
#ifdef SVN_LIBSVN_FS_LINKS_FS_BASE
    svn_fs_base__init
#endif
  },

  {
    SVN_FS_TYPE_FSFS, "fs",
#ifdef SVN_LIBSVN_FS_LINKS_FS_FS
    svn_fs_fs__init
#endif
  },

  { NULL }
};

static svn_error_t *
load_module (fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
{
  *initfunc = NULL;

#if APR_HAS_DSO
  {
    apr_dso_handle_t *dso;
    apr_dso_handle_sym_t symbol;
    const char *libname;
    const char *funcname;
    apr_status_t status;

    libname = apr_psprintf (pool, "libsvn_fs_%s-%d.so.0",
                            name, SVN_VER_MAJOR);
    funcname = apr_psprintf (pool, "svn_fs_%s__init", name);

    /* Find/load the specified library.  If we get an error, assume
       the library doesn't exist.  The library will be unloaded when
       pool is destroyed. */
    status = apr_dso_load (&dso, libname, pool);
    if (status)
      return SVN_NO_ERROR;

    /* find the initialization routine */
    status = apr_dso_sym (&symbol, dso, funcname);
    if (status)
      return svn_error_wrap_apr (status, _("'%s' does not define '%s()'"),
                                 libname, funcname);

    *initfunc = (fs_init_func_t) symbol;
  }
#endif /* APR_HAS_DSO */

  return SVN_NO_ERROR;
}

/* Fetch a library vtable by FS type. */
static svn_error_t *
get_library_vtable (fs_library_vtable_t **vtable, const char *fs_type,
                    apr_pool_t *pool)
{
  const struct fs_type_defn *fst;
  const char *fsap_name;
  fs_init_func_t initfunc = NULL;
  const svn_version_t *my_version = svn_fs_version();
  const svn_version_t *fs_version;

  for (fst = fs_modules; fst->fs_type; fst++)
    {
      if (strcmp (fs_type, fst->fs_type) == 0)
        break;
    }

  if (fst->fs_type)
    {
      fsap_name = fst->fsap_name;
      initfunc = fst->initfunc;
      if (! initfunc)
        SVN_ERR (load_module (&initfunc, fsap_name, pool));
    }

  if (! initfunc)
    return svn_error_createf (SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
                              _("Unknown FS type '%s'"), fs_type);

  SVN_ERR (initfunc (my_version, vtable));
  fs_version = (*vtable)->get_version();
  if (!svn_ver_compatible (my_version, fs_version))
    return svn_error_createf (SVN_ERR_VERSION_MISMATCH, NULL,
                              _("Mismatched FS module version for '%s':"
                                " found %d.%d.%d%s,"
                                " expected %d.%d.%d%s"),
                              fs_type,
                              my_version->major, my_version->minor,
                              my_version->patch, my_version->tag,
                              fs_version->major, fs_version->minor,
                              fs_version->patch, fs_version->tag);
  return SVN_NO_ERROR;
}

/* Fetch the library vtable for an existing FS. */
static svn_error_t *
fs_library_vtable (fs_library_vtable_t **vtable, const char *path,
                   apr_pool_t *pool)
{
  const char *filename, *fs_type;
  char buf[128];
  svn_error_t *err;
  apr_file_t *file;
  apr_size_t len;

  /* Read the fsap-name file to get the FSAP name, or assume the default. */
  filename = svn_path_join (path, FS_TYPE_FILENAME, pool);
  err = svn_io_file_open (&file, filename, APR_READ|APR_BUFFERED, 0, pool);
  if (err && APR_STATUS_IS_ENOENT (err->apr_err))
    {
      svn_error_clear (err);
      fs_type = SVN_FS_TYPE_BDB;
    }
  else if (err)
    return err;
  else
    {
      len = sizeof(buf);
      SVN_ERR (svn_io_read_length_line (file, buf, &len, pool));
      SVN_ERR (svn_io_file_close (file, pool));
      fs_type = buf;
    }

  /* Fetch the library vtable by name, now that we've chosen one. */
  return get_library_vtable (vtable, fs_type, pool);
}

static svn_error_t *
write_fs_type (const char *path, const char *fs_type, apr_pool_t *pool)
{
  const char *filename;
  apr_file_t *file;

  filename = svn_path_join (path, FS_TYPE_FILENAME, pool);
  SVN_ERR (svn_io_file_open (&file, filename,
                             APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED,
                             APR_OS_DEFAULT, pool));
  SVN_ERR (svn_io_file_write_full (file, fs_type, strlen(fs_type), NULL,
                                   pool));
  SVN_ERR (svn_io_file_write_full (file, "\n", 1, NULL, pool));
  SVN_ERR (svn_io_file_close (file, pool));
  return SVN_NO_ERROR;
}


/* --- Functions for operating on filesystems by pathname --- */

/* A default warning handling function.  */
static void
default_warning_func (void *baton, svn_error_t *err)
{
  /* The one unforgiveable sin is to fail silently.  Dumping to stderr
     or /dev/tty is not acceptable default behavior for server
     processes, since those may both be equivalent to /dev/null.  */
  abort ();
}

svn_fs_t *
svn_fs_new (apr_hash_t *fs_config, apr_pool_t *pool)
{
  svn_fs_t *fs;

  fs = apr_palloc (pool, sizeof (*fs));
  fs->pool = pool;
  fs->path = NULL;
  fs->warning = default_warning_func;
  fs->warning_baton = NULL;
  fs->config = fs_config;
  fs->vtable = NULL;
  fs->fsap_data = NULL;
  return fs;
}

void
svn_fs_set_warning_func (svn_fs_t *fs, svn_fs_warning_callback_t warning,
                         void *warning_baton)
{
  fs->warning = warning;
  fs->warning_baton = warning_baton;
}

svn_error_t *
svn_fs_create (svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
               apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;
  const char *fs_type = NULL;

  if (fs_config)
    fs_type = apr_hash_get (fs_config, SVN_FS_CONFIG_FS_TYPE,
                            APR_HASH_KEY_STRING);
  if (fs_type == NULL)
    fs_type = DEFAULT_FS_TYPE;
  SVN_ERR (get_library_vtable (&vtable, fs_type, pool));

  /* Create the FS directory and write out the fsap-name file. */
  SVN_ERR (svn_io_dir_make_sgid (path, APR_OS_DEFAULT, pool));
  SVN_ERR (write_fs_type (path, fs_type, pool));

  /* Perform the actual creation. */
  *fs_p = svn_fs_new (fs_config, pool);
  return vtable->create (*fs_p, path, pool);
}

svn_error_t *
svn_fs_open (svn_fs_t **fs_p, const char *path, apr_hash_t *fs_config,
             apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (fs_library_vtable (&vtable, path, pool));
  *fs_p = svn_fs_new (fs_config, pool);
  return vtable->open (*fs_p, path, pool);
}

const char *
svn_fs_path (svn_fs_t *fs, apr_pool_t *pool)
{
  return apr_pstrdup (pool, fs->path);
}

svn_error_t *
svn_fs_delete_fs (const char *path, apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (fs_library_vtable (&vtable, path, pool));
  return vtable->delete_fs (path, pool);
}

svn_error_t *
svn_fs_hotcopy (const char *src_path, const char *dest_path,
                svn_boolean_t clean, apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;
  const char *path;
  svn_node_kind_t kind;

  SVN_ERR (fs_library_vtable (&vtable, src_path, pool));
  SVN_ERR (vtable->hotcopy (src_path, dest_path, clean, pool));

  /* Copy the fs-type file. */
  path = svn_path_join (src_path, FS_TYPE_FILENAME, pool);
  SVN_ERR (svn_io_check_path (path, &kind, pool));
  if (kind != svn_node_none)
    SVN_ERR (svn_io_dir_file_copy (src_path, dest_path, FS_TYPE_FILENAME,
                                   pool));

  return SVN_NO_ERROR;
}


/* --- Berkeley-specific functions --- */

svn_error_t *
svn_fs_create_berkeley (svn_fs_t *fs, const char *path)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, fs->pool));

  /* Create the FS directory and write out the fsap-name file. */
  SVN_ERR (svn_io_dir_make (path, APR_OS_DEFAULT, fs->pool));
  SVN_ERR (write_fs_type (path, SVN_FS_TYPE_BDB, fs->pool));

  /* Perform the actual creation. */
  return vtable->create (fs, path, fs->pool);
}

svn_error_t *
svn_fs_open_berkeley (svn_fs_t *fs, const char *path)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, fs->pool));
  return vtable->open (fs, path, fs->pool);
}

const char *
svn_fs_berkeley_path (svn_fs_t *fs, apr_pool_t *pool)
{
  return svn_fs_path (fs, pool);
}

svn_error_t *
svn_fs_delete_berkeley (const char *path, apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, pool));
  return vtable->delete_fs (path, pool);
}

svn_error_t *
svn_fs_hotcopy_berkeley (const char *src_path, const char *dest_path,
                         svn_boolean_t clean_logs, apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, pool));
  SVN_ERR (vtable->hotcopy (src_path, dest_path, clean_logs, pool));
  SVN_ERR (write_fs_type (dest_path, SVN_FS_TYPE_BDB, pool));
  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_berkeley_recover (const char *path, apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, pool));
  return vtable->bdb_recover (path, pool);
}

svn_error_t *
svn_fs_set_berkeley_errcall (svn_fs_t *fs,
                             void (*handler) (const char *errpfx, char *msg))
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, fs->pool));
  return vtable->bdb_set_errcall (fs, handler);
}

svn_error_t *
svn_fs_berkeley_logfiles (apr_array_header_t **logfiles,
                          const char *path,
                          svn_boolean_t only_unused,
                          apr_pool_t *pool)
{
  fs_library_vtable_t *vtable;

  SVN_ERR (get_library_vtable (&vtable, SVN_FS_TYPE_BDB, pool));
  return vtable->bdb_logfiles (logfiles, path, only_unused, pool);
}


/* --- Transaction functions --- */

svn_error_t *
svn_fs_begin_txn (svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
                  apr_pool_t *pool)
{
  return fs->vtable->begin_txn (txn_p, fs, rev, pool);
}

svn_error_t *
svn_fs_commit_txn (const char **conflict_p, svn_revnum_t *new_rev,
                   svn_fs_txn_t *txn, apr_pool_t *pool)
{
  return txn->vtable->commit (conflict_p, new_rev, txn, pool);
}

svn_error_t *
svn_fs_abort_txn (svn_fs_txn_t *txn, apr_pool_t *pool)
{
  return txn->vtable->abort (txn, pool);
}

svn_error_t *
svn_fs_purge_txn (svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
  return fs->vtable->purge_txn (fs, txn_id, pool);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?