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

📄 replay.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * replay.c:   an editor driver for changes made in a given revision *             or transaction * * ==================================================================== * Copyright (c) 2000-2006 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 <assert.h>#include <apr_hash.h>#include <apr_md5.h>#include "svn_types.h"#include "svn_delta.h"#include "svn_fs.h"#include "svn_md5.h"#include "svn_repos.h"#include "svn_props.h"#include "svn_pools.h"#include "svn_path.h"#include "svn_private_config.h"/*** Backstory ***//* The year was 2003.  Subversion usage was rampant in the world, and   there was a rapidly growing issues database to prove it.  To make   matters worse, svn_repos_dir_delta() had simply outgrown itself.   No longer content to simply describe the differences between two   trees, the function had been slowly bearing the added   responsibility of representing the actions that had been taken to   cause those differences -- a burden it was never meant to bear.   Now grown into a twisted mess of razor-sharp metal and glass, and   trembling with a sort of momentarily stayed spring force,   svn_repos_dir_delta was a timebomb poised for total annihilation of   the American Midwest.      Subversion needed a change.   Changes, in fact.  And not just in the literary segue sense.  What   Subversion desperately needed was a new mechanism solely   responsible for replaying repository actions back to some   interested party -- to translate and retransmit the contents of the   Berkeley 'changes' database file. *//*** Overview ***//* The filesystem keeps a record of high-level actions that affect the   files and directories in itself.  The 'changes' table records   additions, deletions, textual and property modifications, and so   on.  The goal of the functions in this file is to examine those   change records, and use them to drive an editor interface in such a   way as to effectively replay those actions.   This is critically different than what svn_repos_dir_delta() was   designed to do.  That function describes, in the simplest way it   can, how to transform one tree into another.  It doesn't care   whether or not this was the same way a user might have done this   transformation.  More to the point, it doesn't care if this is how   those differences *did* come into being.  And it is for this reason   that it cannot be relied upon for tasks such as the repository   dumpfile-generation code, which is supposed to represent not   changes, but actions that cause changes.   So, what's the plan here?   First, we fetch the changes for a particular revision or   transaction.  We get these as an array, sorted chronologically.   From this array we will build a hash, keyed on the path associated   with each change item, and whose values are arrays of changes made   to that path, again preserving the chronological ordering.   Once our hash it built, we then sort all the keys of the hash (the   paths) using a depth-first directory sort routine.   Finally, we drive an editor, moving down our list of sorted paths,   and manufacturing any intermediate editor calls (directory openings   and closures) needed to navigate between each successive path.  For   each path, we replay the sorted actions that occurred at that path.   We we've finished the editor drive, we should have fully replayed   the filesystem events that occurred in that revision or transactions   (though not necessarily in the same order in which they   occurred). */   /*** Helper functions. ***//* Information for an active copy, that is a directory which we are currently   working on and which was added with history. */struct copy_info{  /* Destination path. */  const char *path;  /* Copy source.  NULL/invalid if this is an add without history,     nested inside an add with history. */  const char *copyfrom_path;  svn_revnum_t copyfrom_rev;};struct path_driver_cb_baton{  const svn_delta_editor_t *editor;  void *edit_baton;  /* The root of the revision we're replaying. */  svn_fs_root_t *root;  /* The root of the previous revision.  If this is non-NULL it means that     we are supposed to generate props and text deltas relative to it. */  svn_fs_root_t *compare_root;  apr_hash_t *changed_paths;  svn_repos_authz_func_t authz_read_func;  void *authz_read_baton;  const char *base_path;  int base_path_len;  svn_revnum_t low_water_mark;  /* Stack of active copy operations. */  apr_array_header_t *copies;  /* The global pool for this replay operation. */  apr_pool_t *pool;};/* Recursively traverse PATH (as it exists under SOURCE_ROOT) emitting   the appropriate editor calls to add it and its children without any   history.  This is meant to be used when either a subset of the tree   has been ignored and we need to copy something from that subset to   the part of the tree we do care about, or if a subset of the tree is   unavailable because of authz and we need to use it as the source of   a copy. */static svn_error_t *add_subdir(svn_fs_root_t *source_root,           svn_fs_root_t *target_root,           const svn_delta_editor_t *editor,           void *edit_baton,           const char *path,           void *parent_baton,           const char *source_path,           svn_repos_authz_func_t authz_read_func,           void *authz_read_baton,           apr_pool_t *pool,           void **dir_baton){  apr_pool_t *subpool = svn_pool_create(pool);  apr_hash_index_t *hi, *phi;  apr_hash_t *dirents;  apr_hash_t *props;  SVN_ERR(editor->add_directory(path, parent_baton, NULL,                                SVN_INVALID_REVNUM, pool, dir_baton));  SVN_ERR(svn_fs_node_proplist(&props, source_root, source_path, pool));  for (phi = apr_hash_first(pool, props); phi; phi = apr_hash_next(phi))    {      const void *key;      void *val;      svn_pool_clear(subpool);      apr_hash_this(phi, &key, NULL, &val);      SVN_ERR(editor->change_dir_prop(*dir_baton,                                      key,                                      val,                                      subpool));    }  SVN_ERR(svn_fs_dir_entries(&dirents, source_root, source_path, pool));  for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi))    {      svn_boolean_t readable = TRUE;      svn_fs_dirent_t *dent;      const char *new_path;      void *val;      svn_pool_clear(subpool);      apr_hash_this(hi, NULL, NULL, &val);      dent = val;      new_path = svn_path_join(path, dent->name, subpool);      if (authz_read_func)        SVN_ERR(authz_read_func(&readable, target_root, new_path,                                authz_read_baton, pool));      if (! readable)        continue;      if (dent->kind == svn_node_dir)        {          void *new_dir_baton;          SVN_ERR(add_subdir(source_root, target_root, editor, edit_baton,                             new_path, *dir_baton,                             svn_path_join(source_path, dent->name,                                           subpool),                             authz_read_func, authz_read_baton,                             subpool, &new_dir_baton));          SVN_ERR(editor->close_directory(new_dir_baton, subpool));        }      else if (dent->kind == svn_node_file)        {          svn_txdelta_window_handler_t delta_handler;          void *delta_handler_baton, *file_baton;          svn_txdelta_stream_t *delta_stream;          const char *new_src_path;          unsigned char digest[APR_MD5_DIGESTSIZE];          SVN_ERR(editor->add_file(svn_path_join(path, dent->name, subpool),                                   *dir_baton, NULL, SVN_INVALID_REVNUM,                                   pool, &file_baton));          new_src_path = svn_path_join(source_path, dent->name, subpool);          SVN_ERR(svn_fs_node_proplist(&props, source_root, new_src_path,                                       subpool));          for (phi = apr_hash_first(pool, props);               phi;               phi = apr_hash_next(phi))            {              const void *key;              apr_hash_this(phi, &key, NULL, &val);              SVN_ERR(editor->change_file_prop(file_baton,                                               key,                                               val,                                               subpool));            }          SVN_ERR(editor->apply_textdelta(file_baton, NULL, pool,                                           &delta_handler,                                           &delta_handler_baton));          SVN_ERR(svn_fs_get_file_delta_stream                  (&delta_stream, NULL, NULL, source_root, new_src_path,                   pool));          SVN_ERR(svn_txdelta_send_txstream(delta_stream,                                            delta_handler,                                            delta_handler_baton,                                            pool));          SVN_ERR(svn_fs_file_md5_checksum(digest,                                            source_root,                                            new_src_path,                                            pool));          SVN_ERR(editor->close_file(file_baton,                                     svn_md5_digest_to_cstring(digest, pool),                                     pool));        }      else        abort();    }  svn_pool_destroy(subpool);  return SVN_NO_ERROR;}static svn_boolean_tis_within_base_path(const char *path, const char *base_path, int base_len){  if (base_path[0] == '\0')    return TRUE;  if (strncmp(base_path, path, base_len) == 0      && (path[base_len] == '/' || path[base_len] == '\0'))    return TRUE;  return FALSE;}static svn_error_t *path_driver_cb_func(void **dir_baton,                    void *parent_baton,                    void *callback_baton,                    const char *path,                    apr_pool_t *pool){  struct path_driver_cb_baton *cb = callback_baton;  const svn_delta_editor_t *editor = cb->editor;  void *edit_baton = cb->edit_baton;  svn_fs_root_t *root = cb->root;  svn_fs_path_change_t *change;  svn_boolean_t do_add = FALSE, do_delete = FALSE;  svn_node_kind_t kind;  void *file_baton = NULL;  const char *copyfrom_path = NULL;  const char *real_copyfrom_path = NULL;  svn_revnum_t copyfrom_rev;  svn_boolean_t src_readable = TRUE;  svn_fs_root_t *source_root = cb->compare_root;  const char *source_path = source_root ? path : NULL;  const char *base_path = cb->base_path;  int base_path_len = cb->base_path_len;  *dir_baton = NULL;  /* First, flush the copies stack so it only contains ancestors of path. */  while (cb->copies->nelts > 0         && ! svn_path_is_ancestor(APR_ARRAY_IDX(cb->copies,                                               cb->copies->nelts - 1,                                               struct copy_info).path,                                 path))    cb->copies->nelts--;  change = apr_hash_get(cb->changed_paths, path, APR_HASH_KEY_STRING);  switch (change->change_kind)    {    case svn_fs_path_change_add:      do_add = TRUE;      break;    case svn_fs_path_change_delete:      do_delete = TRUE;      break;    case svn_fs_path_change_replace:      do_add = TRUE;      do_delete = TRUE;      break;    case svn_fs_path_change_modify:    default:      /* do nothing */      break;    }  /* Handle any deletions. */  if (do_delete)    SVN_ERR(editor->delete_entry(path, SVN_INVALID_REVNUM,                                  parent_baton, pool));  /* Fetch the node kind if it makes sense to do so. */  if (! do_delete || do_add)    {      SVN_ERR(svn_fs_check_path(&kind, root, path, pool));      if ((kind != svn_node_dir) && (kind != svn_node_file))        return svn_error_createf           (SVN_ERR_FS_NOT_FOUND, NULL,            _("Filesystem path '%s' is neither a file nor a directory"), path);    }  /* Handle any adds/opens. */  if (do_add)    {      svn_fs_root_t *copyfrom_root = NULL;      /* Was this node copied? */      SVN_ERR(svn_fs_copied_from(&copyfrom_rev, &copyfrom_path,                                 root, path, pool));      if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev))        {          SVN_ERR(svn_fs_revision_root(&copyfrom_root,                                       svn_fs_root_fs(root),                                       copyfrom_rev, pool));          if (cb->authz_read_func)            {

⌨️ 快捷键说明

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