⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs_fs.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 5 页
字号:
/* fs_fs.c --- filesystem operations specific to fs_fs
 *
 * ====================================================================
 * 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 <stdio.h>
#include <string.h>
#include <errno.h>              /* for EINVAL */
#include <ctype.h>

#include <apr_general.h>
#include <apr_pools.h>
#include <apr_file_io.h>
#include <apr_uuid.h>
#include <apr_md5.h>

#include "svn_pools.h"
#include "svn_fs.h"
#include "svn_path.h"
#include "svn_utf.h"
#include "svn_hash.h"
#include "svn_md5.h"
#include "../libsvn_delta/delta.h"

#include "fs.h"
#include "err.h"
#include "tree.h"
#include "dag.h"
#include "revs-txns.h"
#include "key-gen.h"
#include "fs_fs.h"
#include "id.h"

#include "../libsvn_fs/fs-loader.h"

#include "svn_private_config.h"

/* Following are defines that specify the textual elements of the
   native filesystem directories and revision files. */

/* Names of special files in the fs_fs filesystem. */
#define PATH_UUID          "uuid"          /* Contains UUID */
#define PATH_CURRENT       "current"       /* Youngest revision */
#define PATH_LOCK_FILE     "write-lock"    /* Revision lock file */
#define PATH_REVS_DIR      "revs"          /* Directory of revisions */
#define PATH_REVPROPS_DIR  "revprops"      /* Directory of revprops */
#define PATH_TXNS_DIR      "transactions"  /* Directory of transactions */

/* Names of special files and file extensions for transactions */
#define PATH_CHANGES       "changes"       /* Records changes made so far */
#define PATH_TXN_PROPS     "props"         /* Transaction properties */
#define PATH_NEXT_IDS      "next-ids"      /* Next temporary ID assignments */
#define PATH_REV           "rev"           /* Proto rev file */
#define PATH_PREFIX_NODE   "node."         /* Prefix for node filename */
#define PATH_EXT_TXN       ".txn"          /* Extension of txn dir */
#define PATH_EXT_CHILDREN  ".children"     /* Extension for dir contents */
#define PATH_EXT_PROPS     ".props"        /* Extension for node props */

/* Headers used to describe node-revision in the revision file. */
#define HEADER_ID          "id"
#define HEADER_TYPE        "type"
#define HEADER_COUNT       "count"
#define HEADER_PROPS       "props"
#define HEADER_TEXT        "text"
#define HEADER_CPATH       "cpath"
#define HEADER_PRED        "pred"
#define HEADER_COPYFROM    "copyfrom"
#define HEADER_COPYROOT    "copyroot"

/* Kinds that a change can be. */
#define ACTION_MODIFY      "modify"
#define ACTION_ADD         "add"
#define ACTION_DELETE      "delete"
#define ACTION_REPLACE     "replace"
#define ACTION_RESET       "reset"

/* True and False flags. */
#define FLAG_TRUE          "true"
#define FLAG_FALSE         "false"

/* Kinds that a node-rev can be. */
#define KIND_FILE          "file"
#define KIND_DIR           "dir"

/* Kinds of representation. */
#define REP_PLAIN          "PLAIN"
#define REP_DELTA          "DELTA"

/* Notes:

To avoid opening and closing the rev-files all the time, it would
probably be advantageous to keep each rev-file open for the
lifetime of the transaction object.  I'll leave that as a later
optimization for now.

I didn't keep track of pool lifetimes at all in this code.  There
are likely some errors because of that.
   
*/

/* The vtable associated with an open transaction object. */
static txn_vtable_t txn_vtable = {
  svn_fs_fs__commit_txn,
  svn_fs_fs__abort_txn,
  svn_fs_fs__txn_prop,
  svn_fs_fs__txn_proplist,
  svn_fs_fs__change_txn_prop,
  svn_fs_fs__txn_root
};

/* Pathname helper functions */

static const char *
path_uuid (svn_fs_t *fs, apr_pool_t *pool)
{
  return svn_path_join (fs->path, PATH_UUID, pool);
}

static const char *
path_current (svn_fs_t *fs, apr_pool_t *pool)
{
  return svn_path_join (fs->path, PATH_CURRENT, pool);
}

static const char *
path_lock (svn_fs_t *fs, apr_pool_t *pool)
{
  return svn_path_join (fs->path, PATH_LOCK_FILE, pool);
}

static const char *
path_rev (svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
{
  return svn_path_join_many (pool, fs->path, PATH_REVS_DIR,
                             apr_psprintf (pool, "%ld", rev), NULL);
}

static const char *
path_revprops (svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool)
{
  return svn_path_join_many (pool, fs->path, PATH_REVPROPS_DIR,
                             apr_psprintf (pool, "%ld", rev), NULL);
}

static const char *
path_txn_dir (svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
  return svn_path_join_many (pool, fs->path, PATH_TXNS_DIR,
                             apr_pstrcat (pool, txn_id, PATH_EXT_TXN, NULL),
                             NULL);
}

static const char *
path_txn_changes (svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
  return svn_path_join (path_txn_dir (fs, txn_id, pool), PATH_CHANGES, pool);
}

static const char *
path_txn_props (svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
  return svn_path_join (path_txn_dir (fs, txn_id, pool), PATH_TXN_PROPS, pool);
}

static const char *
path_txn_next_ids (svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
  return svn_path_join (path_txn_dir (fs, txn_id, pool), PATH_NEXT_IDS, pool);
}

static const char *
path_txn_proto_rev (svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
{
  return svn_path_join (path_txn_dir (fs, txn_id, pool), PATH_REV, pool);
}

static const char *
path_txn_node_rev (svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool)
{
  const char *txn_id = svn_fs_fs__id_txn_id (id);
  const char *node_id = svn_fs_fs__id_node_id (id);
  const char *copy_id = svn_fs_fs__id_copy_id (id);
  const char *name = apr_psprintf (pool, PATH_PREFIX_NODE "%s.%s",
                                   node_id, copy_id);

  return svn_path_join (path_txn_dir (fs, txn_id, pool), name, pool);
}

static const char *
path_txn_node_props (svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool)
{
  return apr_pstrcat (pool, path_txn_node_rev (fs, id, pool), PATH_EXT_PROPS,
                      NULL);
}

static const char *
path_txn_node_children (svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool)
{
  return apr_pstrcat (pool, path_txn_node_rev (fs, id, pool),
                      PATH_EXT_CHILDREN, NULL);
}

/* Fetch the current offset of FILE into *OFFSET_P. */
static svn_error_t *
get_file_offset (apr_off_t *offset_p, apr_file_t *file, apr_pool_t *pool)
{
  apr_off_t offset;

  offset = 0;
  SVN_ERR (svn_io_file_seek (file, APR_CUR, &offset, pool));
  *offset_p = offset;

  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_fs__open (svn_fs_t *fs, const char *path, apr_pool_t *pool)
{
  apr_file_t *current_file;

  /* Attempt to open the 'current' file of this repository.  There
     isn't much need for specific state associated with an open fs_fs
     repository. */

  fs->path = apr_pstrdup (pool, path);

  SVN_ERR (svn_io_file_open (&current_file, path_current (fs, pool),
                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));

  SVN_ERR (svn_io_file_close (current_file, pool));
  
  return SVN_NO_ERROR;
}

/* Find the youngest revision in a repository at path FS_PATH and
   return it in *YOUNGEST_P.  Perform temporary allocations in
   POOL. */
static svn_error_t *
get_youngest (svn_revnum_t *youngest_p,
              const char *fs_path,
              apr_pool_t *pool)
{
  apr_file_t *current_file;
  char buf[80];
  apr_size_t len;

  SVN_ERR (svn_io_file_open (&current_file,
                             svn_path_join (fs_path, PATH_CURRENT, pool),
                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));

  len = sizeof (buf);
  SVN_ERR (svn_io_file_read (current_file, buf, &len, pool));
  buf[len] = '\0';
  
  *youngest_p = SVN_STR_TO_REV (buf);
  
  SVN_ERR (svn_io_file_close (current_file, pool));
  
  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_fs__hotcopy (const char *src_path,
                    const char *dst_path,
                    apr_pool_t *pool)
{
  const char *src_subdir, *dst_subdir;
  svn_revnum_t youngest, rev;
  apr_pool_t *iterpool;

  /* Copy the current file. */
  SVN_ERR (svn_io_dir_file_copy (src_path, dst_path, PATH_CURRENT, pool));

  /* Copy the uuid. */
  SVN_ERR (svn_io_dir_file_copy (src_path, dst_path, PATH_UUID, pool));

  /* Find the youngest revision from this current file. */
  SVN_ERR (get_youngest (&youngest, dst_path, pool));

  /* Copy the necessary rev files. */
  src_subdir = svn_path_join (src_path, PATH_REVS_DIR, pool);
  dst_subdir = svn_path_join (dst_path, PATH_REVS_DIR, pool);

  SVN_ERR (svn_io_make_dir_recursively (dst_subdir, pool));

  iterpool = svn_pool_create (pool);
  for (rev = 0; rev <= youngest; rev++)
    {
      SVN_ERR (svn_io_dir_file_copy (src_subdir, dst_subdir,
                                     apr_psprintf (iterpool, "%ld", rev),
                                     iterpool));
      svn_pool_clear (iterpool);
    }

  /* Copy the necessary revprop files. */
  src_subdir = svn_path_join (src_path, PATH_REVPROPS_DIR, pool);
  dst_subdir = svn_path_join (dst_path, PATH_REVPROPS_DIR, pool);

  SVN_ERR (svn_io_make_dir_recursively (dst_subdir, pool));

  for (rev = 0; rev <= youngest; rev++)
    {
      svn_pool_clear (iterpool);
      SVN_ERR (svn_io_dir_file_copy (src_subdir, dst_subdir,
                                     apr_psprintf (iterpool, "%ld", rev),
                                     iterpool));
    }

  apr_pool_destroy (iterpool);

  /* Make an empty transactions directory for now.  Eventually some
     method of copying in progress transactions will need to be
     developed.*/
  dst_subdir = svn_path_join (dst_path, PATH_TXNS_DIR, pool);
  SVN_ERR (svn_io_make_dir_recursively (dst_subdir, pool));

  return SVN_NO_ERROR;
}


svn_error_t *
svn_fs_fs__youngest_rev (svn_revnum_t *youngest_p,
                         svn_fs_t *fs,
                         apr_pool_t *pool)
{
  SVN_ERR (get_youngest (youngest_p, fs->path, pool));
  
  return SVN_NO_ERROR;
}

/* Given a revision file FILE that has been pre-positioned at the
   beginning of a Node-Rev header block, read in that header block and
   store it in the apr_hash_t HEADERS.  All allocations will be from
   POOL. */
static svn_error_t * read_header_block (apr_hash_t **headers,
                                        apr_file_t *file,
                                        apr_pool_t *pool)
{
  *headers = apr_hash_make (pool);
  
  while (1)
    {
      char header_str[1024];
      const char *name, *value;
      apr_size_t i = 0, header_len;
      apr_size_t limit;
      char *local_name, *local_value;

      limit = sizeof (header_str);
      SVN_ERR (svn_io_read_length_line (file, header_str, &limit, pool));

      if (strlen (header_str) == 0)
        break; /* end of header block */
      
      header_len = strlen (header_str);

      while (header_str[i] != ':')
        {
          if (header_str[i] == '\0')
            return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                     _("Found malformed header in "
                                       "revision file"));
          i++;
        }
      
      /* Create a 'name' string and point to it. */
      header_str[i] = '\0';
      name=header_str;

      /* Skip over the NULL byte and the space following it. */
      i += 2;

      if (i > header_len)
        return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                 _("Found malformed header in "
                                   "revision file"));

      value = header_str + i;

      local_name = apr_pstrdup (pool, name);

⌨️ 快捷键说明

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