?? delta.c
字號:
/* * delta.c: an editor driver for expressing differences between two trees * * ==================================================================== * 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 <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_path.h"#include "svn_repos.h"#include "svn_pools.h"#include "svn_props.h"#include "svn_private_config.h"#include "repos.h"/* THINGS TODO: Currently the code herein gives only a slight nod to fully supporting directory deltas that involve renames, copies, and such. */ /* Some datatypes and declarations used throughout the file. *//* Parameters which remain constant throughout a delta traversal. At the top of the recursion, we initialize one of these structures. Then we pass it down to every call. This way, functions invoked deep in the recursion can get access to this traversal's global parameters, without using global variables. */struct context { const svn_delta_editor_t *editor; const char *edit_base_path; svn_fs_root_t *source_root; svn_fs_root_t *target_root; svn_repos_authz_func_t authz_read_func; void *authz_read_baton; svn_boolean_t text_deltas; svn_boolean_t recurse; svn_boolean_t entry_props; svn_boolean_t ignore_ancestry;};/* The type of a function that accepts changes to an object's property list. OBJECT is the object whose properties are being changed. NAME is the name of the property to change. VALUE is the new value for the property, or zero if the property should be deleted. */typedef svn_error_t *proplist_change_fn_t(struct context *c, void *object, const char *name, const svn_string_t *value, apr_pool_t *pool);/* Some prototypes for functions used throughout. See each individual function for information about what it does. *//* Retrieving the base revision from the path/revision hash. */static svn_revnum_t get_path_revision(svn_fs_root_t *root, const char *path, apr_pool_t *pool);/* proplist_change_fn_t property changing functions. */static svn_error_t *change_dir_prop(struct context *c, void *object, const char *path, const svn_string_t *value, apr_pool_t *pool);static svn_error_t *change_file_prop(struct context *c, void *object, const char *path, const svn_string_t *value, apr_pool_t *pool);/* Constructing deltas for properties of files and directories. */static svn_error_t *delta_proplists(struct context *c, const char *source_path, const char *target_path, proplist_change_fn_t *change_fn, void *object, apr_pool_t *pool);/* Constructing deltas for file constents. */static svn_error_t *send_text_delta(struct context *c, void *file_baton, const char *base_checksum, svn_txdelta_stream_t *delta_stream, apr_pool_t *pool);static svn_error_t *delta_files(struct context *c, void *file_baton, const char *source_path, const char *target_path, apr_pool_t *pool);/* Generic directory deltafication routines. */static svn_error_t *delete(struct context *c, void *dir_baton, const char *edit_path, apr_pool_t *pool);static svn_error_t *add_file_or_dir(struct context *c, void *dir_baton, const char *target_path, const char *edit_path, svn_node_kind_t tgt_kind, apr_pool_t *pool);static svn_error_t *replace_file_or_dir(struct context *c, void *dir_baton, const char *source_path, const char *target_path, const char *edit_path, svn_node_kind_t tgt_kind, apr_pool_t *pool);static svn_error_t *absent_file_or_dir(struct context *c, void *dir_baton, const char *edit_path, svn_node_kind_t tgt_kind, apr_pool_t *pool);static svn_error_t *delta_dirs(struct context *c, void *dir_baton, const char *source_path, const char *target_path, const char *edit_path, apr_pool_t *pool);/* Return the error 'SVN_ERR_AUTHZ_ROOT_UNREADABLE' if PATH in ROOT is * unreadable according to AUTHZ_READ_FUNC with AUTHZ_READ_BATON. * * PATH should be the implicit root path of an editor drive, that is, * the path used by editor->open_root(). */static svn_error_t *authz_root_check(svn_fs_root_t *root, const char *path, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, apr_pool_t *pool){ svn_boolean_t allowed; if (authz_read_func) { SVN_ERR(authz_read_func(&allowed, root, path, authz_read_baton, pool)); if (! allowed) return svn_error_create(SVN_ERR_AUTHZ_ROOT_UNREADABLE, 0, _("Unable to open root of edit")); } return SVN_NO_ERROR;}static svn_error_t *not_a_dir_error(const char *role, const char *path){ return svn_error_createf (SVN_ERR_FS_NOT_DIRECTORY, 0, "Invalid %s directory '%s'", role, path ? path : "(null)");}/* Public interface to computing directory deltas. */svn_error_t *svn_repos_dir_delta(svn_fs_root_t *src_root, const char *src_parent_dir, const char *src_entry, svn_fs_root_t *tgt_root, const char *tgt_fullpath, const svn_delta_editor_t *editor, void *edit_baton, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, svn_boolean_t text_deltas, svn_boolean_t recurse, svn_boolean_t entry_props, svn_boolean_t ignore_ancestry, apr_pool_t *pool){ void *root_baton = NULL; struct context c; const char *src_fullpath; const svn_fs_id_t *src_id, *tgt_id; svn_node_kind_t src_kind, tgt_kind; svn_revnum_t rootrev; int distance; const char *authz_root_path; /* SRC_PARENT_DIR must be valid. */ if (! src_parent_dir) return not_a_dir_error("source parent", src_parent_dir); /* TGT_FULLPATH must be valid. */ if (! tgt_fullpath) return svn_error_create(SVN_ERR_FS_PATH_SYNTAX, 0, _("Invalid target path")); /* Calculate the fs path implicitly used for editor->open_root, so we can do an authz check on that path first. */ if (*src_entry) authz_root_path = svn_path_dirname(tgt_fullpath, pool); else authz_root_path = tgt_fullpath; /* Construct the full path of the source item. */ src_fullpath = svn_path_join(src_parent_dir, src_entry, pool); /* Get the node kinds for the source and target paths. */ SVN_ERR(svn_fs_check_path(&tgt_kind, tgt_root, tgt_fullpath, pool)); SVN_ERR(svn_fs_check_path(&src_kind, src_root, src_fullpath, pool)); /* If neither of our paths exists, we don't really have anything to do. */ if ((tgt_kind == svn_node_none) && (src_kind == svn_node_none)) goto cleanup; /* If either the source or the target is a non-directory, we require that a SRC_ENTRY be supplied. */ if ((! *src_entry) && ((src_kind != svn_node_dir) || tgt_kind != svn_node_dir)) return svn_error_create (SVN_ERR_FS_PATH_SYNTAX, 0, _("Invalid editor anchoring; at least one of the " "input paths is not a directory and there was no source entry")); /* Set the global target revision if one can be determined. */ if (svn_fs_is_revision_root(tgt_root)) { SVN_ERR(editor->set_target_revision (edit_baton, svn_fs_revision_root_revision(tgt_root), pool)); } else if (svn_fs_is_txn_root(tgt_root)) { svn_fs_t *fs = svn_fs_root_fs(tgt_root); const char *txn_name = svn_fs_txn_root_name(tgt_root, pool); svn_fs_txn_t *txn; SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, pool)); SVN_ERR(editor->set_target_revision (edit_baton, svn_fs_txn_base_revision(txn), pool)); } /* Setup our pseudo-global structure here. We need these variables throughout the deltafication process, so pass them around by reference to all the helper functions. */ c.editor = editor; c.source_root = src_root; c.target_root = tgt_root; c.authz_read_func = authz_read_func; c.authz_read_baton = authz_read_baton; c.text_deltas = text_deltas; c.recurse = recurse; c.entry_props = entry_props; c.ignore_ancestry = ignore_ancestry; /* Get our editor root's revision. */ rootrev = get_path_revision(src_root, src_parent_dir, pool); /* If one or the other of our paths doesn't exist, we have to handle those cases specially. */ if (tgt_kind == svn_node_none) { /* Caller thinks that target still exists, but it doesn't. So transform their source path to "nothing" by deleting it. */ SVN_ERR(authz_root_check(tgt_root, authz_root_path, authz_read_func, authz_read_baton, pool)); SVN_ERR(editor->open_root(edit_baton, rootrev, pool, &root_baton)); SVN_ERR(delete(&c, root_baton, src_entry, pool)); goto cleanup; } if (src_kind == svn_node_none) { /* The source path no longer exists, but the target does. So transform "nothing" into "something" by adding. */ SVN_ERR(authz_root_check(tgt_root, authz_root_path, authz_read_func, authz_read_baton, pool)); SVN_ERR(editor->open_root(edit_baton, rootrev, pool, &root_baton)); SVN_ERR(add_file_or_dir(&c, root_baton, tgt_fullpath, src_entry, tgt_kind, pool)); goto cleanup; } /* Get and compare the node IDs for the source and target. */ SVN_ERR(svn_fs_node_id(&tgt_id, tgt_root, tgt_fullpath, pool)); SVN_ERR(svn_fs_node_id(&src_id, src_root, src_fullpath, pool)); distance = svn_fs_compare_ids(src_id, tgt_id); if (distance == 0) { /* They are the same node! No-op (you gotta love those). */ goto cleanup; } else if (*src_entry) { /* If the nodes have different kinds, we must delete the one and add the other. Also, if they are completely unrelated and our caller is interested in relatedness, we do the same thing. */ if ((src_kind != tgt_kind) || ((distance == -1) && (! ignore_ancestry))) { SVN_ERR(authz_root_check(tgt_root, authz_root_path, authz_read_func, authz_read_baton, pool)); SVN_ERR(editor->open_root(edit_baton, rootrev, pool, &root_baton)); SVN_ERR(delete(&c, root_baton, src_entry, pool)); SVN_ERR(add_file_or_dir(&c, root_baton, tgt_fullpath, src_entry, tgt_kind, pool)); } /* Otherwise, we just replace the one with the other. */ else { SVN_ERR(authz_root_check(tgt_root, authz_root_path, authz_read_func, authz_read_baton, pool)); SVN_ERR(editor->open_root(edit_baton, rootrev, pool, &root_baton)); SVN_ERR(replace_file_or_dir(&c, root_baton, src_fullpath, tgt_fullpath, src_entry, tgt_kind, pool)); } } else { /* There is no entry given, so delta the whole parent directory. */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -