fs-helpers.c

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

C
586
字号
/* fs-helpers.c --- tests for the filesystem
 *
 * ====================================================================
 * 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 <stdlib.h>
#include <string.h>
#include <apr_pools.h>
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_fs.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_test.h"
#include "fs-helpers.h"

#include "../libsvn_fs_base/fs.h"
#include "../libsvn_fs_base/dag.h"
#include "../libsvn_fs_base/trail.h"

#include "../libsvn_fs_base/bdb/rev-table.h"
#include "../libsvn_fs_base/bdb/nodes-table.h"


/*-------------------------------------------------------------------*/

/** Helper routines. **/


/* Generic Berkeley DB error handler function. */
static void
berkeley_error_handler (const char *errpfx, char *msg)
{
  fprintf (stderr, "%s%s\n", errpfx ? errpfx : "", msg);
}

static void
fs_warning_handler (void *baton, svn_error_t *err)
{
  svn_handle_warning(stderr, err);
}

svn_error_t *
svn_test__fs_new (svn_fs_t **fs_p, apr_pool_t *pool)
{
  apr_hash_t *fs_config = apr_hash_make (pool);
  apr_hash_set (fs_config, SVN_FS_CONFIG_BDB_TXN_NOSYNC,
                APR_HASH_KEY_STRING, "1");

  *fs_p = svn_fs_new (fs_config, pool);
  if (! *fs_p)
    return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
                             "Couldn't alloc a new fs object.");

  /* Provide a warning function that just dumps the message to stderr.  */
  svn_fs_set_warning_func (*fs_p, fs_warning_handler, NULL);

  return SVN_NO_ERROR;
}



svn_error_t *
svn_test__create_fs (svn_fs_t **fs_p,
                     const char *name, 
                     apr_pool_t *pool)
{
  apr_finfo_t finfo;

  /* If there's already a repository named NAME, delete it.  Doing
     things this way means that repositories stick around after a
     failure for postmortem analysis, but also that tests can be
     re-run without cleaning out the repositories created by prior
     runs.  */
  if (apr_stat (&finfo, name, APR_FINFO_TYPE, pool) == APR_SUCCESS)
    {
      if (finfo.filetype == APR_DIR)
        SVN_ERR (svn_fs_delete_berkeley (name, pool));
      else
        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
                                  "there is already a file named '%s'", name);
    }

  SVN_ERR (svn_test__fs_new (fs_p, pool));
  SVN_ERR (svn_fs_create_berkeley (*fs_p, name));
  
  /* Provide a handler for Berkeley DB error messages.  */
  SVN_ERR (svn_fs_set_berkeley_errcall (*fs_p, berkeley_error_handler));

  /* Register this fs for cleanup. */
  svn_test_add_dir_cleanup (name);

  return SVN_NO_ERROR;
}


svn_error_t *
svn_test__create_repos (svn_repos_t **repos_p,
                        const char *name, 
                        apr_pool_t *pool)
{
  apr_finfo_t finfo;
  apr_hash_t *fs_config;

  /* If there's already a repository named NAME, delete it.  Doing
     things this way means that repositories stick around after a
     failure for postmortem analysis, but also that tests can be
     re-run without cleaning out the repositories created by prior
     runs.  */
  if (apr_stat (&finfo, name, APR_FINFO_TYPE, pool) == APR_SUCCESS)
    {
      if (finfo.filetype == APR_DIR)
        SVN_ERR (svn_repos_delete (name, pool));
      else
        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
                                  "there is already a file named '%s'", name);
    }

  fs_config = apr_hash_make (pool);
  apr_hash_set (fs_config, SVN_FS_CONFIG_BDB_TXN_NOSYNC,
                APR_HASH_KEY_STRING, "1");
  if (getenv ("FS_TYPE"))
    apr_hash_set (fs_config, SVN_FS_CONFIG_FS_TYPE, APR_HASH_KEY_STRING,
                  getenv ("FS_TYPE"));
  SVN_ERR (svn_repos_create (repos_p, name, NULL, NULL, NULL,
                             fs_config, pool));

  /* Provide a handler for Berkeley DB error messages if we're using bdb.  */
  if (getenv ("FS_TYPE") == NULL || strcmp (getenv ("FS_TYPE"), "bdb") == 0)
    SVN_ERR (svn_fs_set_berkeley_errcall (svn_repos_fs (*repos_p), 
                                          berkeley_error_handler));

  /* Register this repo for cleanup. */
  svn_test_add_dir_cleanup (name);

  return SVN_NO_ERROR;
}


svn_error_t *
svn_test__stream_to_string (svn_stringbuf_t **string,
                            svn_stream_t *stream, 
                            apr_pool_t *pool)
{
  char buf[10]; /* Making this really small because a) hey, they're
                   just tests, not the prime place to beg for
                   optimization, and b) we've had repository
                   problems in the past that only showed up when
                   reading a file into a buffer that couldn't hold the
                   file's whole contents -- the kind of thing you'd
                   like to catch while testing.  

                   ### cmpilato todo: Perhaps some day this size can
                   be passed in as a parameter.  Not high on my list
                   of priorities today, though. */

  apr_size_t len;
  svn_stringbuf_t *str = svn_stringbuf_create ("", pool);

  do 
    {
      len = sizeof (buf);
      SVN_ERR (svn_stream_read (stream, buf, &len));
      
      /* Now copy however many bytes were *actually* read into str. */
      svn_stringbuf_appendbytes (str, buf, len);
      
    } while (len);  /* Continue until we're told that no bytes were
                       read. */

  *string = str;
  return SVN_NO_ERROR;
}

svn_error_t *
svn_test__set_file_contents (svn_fs_root_t *root,
                             const char *path,
                             const char *contents, 
                             apr_pool_t *pool)
{
  svn_txdelta_window_handler_t consumer_func;
  void *consumer_baton;
  svn_string_t string;

  SVN_ERR (svn_fs_apply_textdelta (&consumer_func, &consumer_baton,
                                   root, path, NULL, NULL, pool));

  string.data = contents;
  string.len = strlen(contents);
  SVN_ERR (svn_txdelta_send_string (&string, consumer_func,
                                    consumer_baton, pool));

  return SVN_NO_ERROR;
}


svn_error_t *
svn_test__get_file_contents (svn_fs_root_t *root,
                             const char *path,
                             svn_stringbuf_t **str, 
                             apr_pool_t *pool)
{
  svn_stream_t *stream;

  SVN_ERR (svn_fs_file_contents (&stream, root, path, pool));  
  SVN_ERR (svn_test__stream_to_string (str, stream, pool));

  return SVN_NO_ERROR;
}


/* Read all the entries in directory PATH under transaction or
   revision root ROOT, copying their full paths into the TREE_ENTRIES
   hash, and recursing when those entries are directories */
static svn_error_t *
get_dir_entries (apr_hash_t *tree_entries,
                 svn_fs_root_t *root,
                 const char *path, 
                 apr_pool_t *pool)
{
  apr_hash_t *entries;
  apr_hash_index_t *hi;

  SVN_ERR (svn_fs_dir_entries (&entries, root, path, pool));
  
  /* Copy this list to the master list with the path prepended to the
     names */
  for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
    {
      const void *key;
      apr_ssize_t keylen;
      void *val;
      svn_fs_dirent_t *dirent;
      const char *full_path;
 
      apr_hash_this (hi, &key, &keylen, &val);
      dirent = val;

      /* Calculate the full path of this entry (by appending the name
         to the path thus far) */
      full_path = svn_path_join (path, dirent->name, pool);

      /* Now, copy this dirent to the master hash, but this time, use
         the full path for the key */
      apr_hash_set (tree_entries, full_path, APR_HASH_KEY_STRING, dirent);

      /* If this entry is a directory, recurse into the tree. */
      if (dirent->kind == svn_node_dir)
        SVN_ERR (get_dir_entries (tree_entries, root, full_path, pool));
    }

  return SVN_NO_ERROR;
}


static svn_error_t *
validate_tree_entry (svn_fs_root_t *root,
                     const char *path,
                     const char *contents,
                     apr_pool_t *pool)
{
  svn_stream_t *rstream;
  svn_stringbuf_t *rstring;
  svn_boolean_t is_dir;

  /* Verify that this is the expected type of node */
  SVN_ERR (svn_fs_is_dir (&is_dir, root, path, pool));
  if ((!is_dir && !contents) || (is_dir && contents))
    return svn_error_createf
      (SVN_ERR_FS_GENERAL, NULL,
       "node '%s' in tree was of unexpected node type", 
       path);

  /* Verify that the contents are as expected (files only) */
  if (! is_dir)
    {
      SVN_ERR (svn_fs_file_contents (&rstream, root, path, pool));  
      SVN_ERR (svn_test__stream_to_string (&rstring, rstream, pool));
      if (! svn_stringbuf_compare (rstring, 
                                   svn_stringbuf_create (contents, pool)))
        return svn_error_createf 

⌨️ 快捷键说明

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