/** * @copyright * ==================================================================== * 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/. * ==================================================================== * @endcopyright * * @file svn_repos.h * @brief tools built on top of the filesystem. */ #ifndef SVN_REPOS_H #define SVN_REPOS_H #include #include #include "svn_fs.h" #include "svn_delta.h" #include "svn_types.h" #include "svn_error.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* ---------------------------------------------------------------*/ /** Callback type for checking authorization on paths produced by (at * least) svn_repos_dir_delta(). * * Set @a *allowed to TRUE to indicate that some operation is * authorized for @a path in @a root, or set it to FALSE to indicate * unauthorized (presumably according to state stored in @a baton). * * Do not assume @a pool has any lifetime beyond this call. * * The exact operation being authorized depends on the callback * implementation. For read authorization, for example, the caller * would implement an instance that does read checking, and pass it as * a parameter named [perhaps] 'authz_read_func'. The receiver of * that parameter might also take another parameter named * 'authz_write_func', which although sharing this type, would be a * different implementation. * * Note: If someday we want more sophisticated authorization states * than just yes/no, @a allowed can become an enum type. */ typedef svn_error_t *(*svn_repos_authz_func_t) (svn_boolean_t *allowed, svn_fs_root_t *root, const char *path, void *baton, apr_pool_t *pool); /** The repository object. */ typedef struct svn_repos_t svn_repos_t; /* Opening and creating repositories. */ /** Find the root path of the repository that contains @a path. * * If a repository was found, the path to the root of the repository * is returned, else @c NULL. The pointer to the returned path may be * equal to @a path argument. */ const char *svn_repos_find_root_path (const char *path, apr_pool_t *pool); /** Set @a *repos_p to a repository object for the repository at @a path. * * Allocate @a *repos_p in @a pool. * * Acquires a shared lock on the repository, and attaches a cleanup * function to @a pool to remove the lock. If no lock can be acquired, * returns error, with undefined effect on @a *repos_p. If an exclusive * lock is present, this blocks until it's gone. */ svn_error_t *svn_repos_open (svn_repos_t **repos_p, const char *path, apr_pool_t *pool); /** Create a new Subversion repository at @a path, building the necessary * directory structure, creating the Berkeley DB filesystem environment, * and so on. Return the (open) repository object in @a *repos_p, * allocated in @a pool. * * @a config is a client configuration hash of @c svn_config_t * items * keyed on config category names, and may be NULL. * * @a fs_config is passed to the filesystem, and may be NULL. * * @a unused_1 and @a unused_2 are not used and should be NULL. */ svn_error_t *svn_repos_create (svn_repos_t **repos_p, const char *path, const char *unused_1, const char *unused_2, apr_hash_t *config, apr_hash_t *fs_config, apr_pool_t *pool); /** Destroy the Subversion repository found at @a path, using @a pool for any * necessary allocations. */ svn_error_t *svn_repos_delete (const char *path, apr_pool_t *pool); /** Return the filesystem associated with repository object @a repos. */ svn_fs_t *svn_repos_fs (svn_repos_t *repos); /** Make a hot copy of the Subversion repository found at @a src_path * to @a dst_path. * * @copydoc svn_fs_hotcopy_berkeley() */ svn_error_t * svn_repos_hotcopy (const char *src_path, const char *dst_path, svn_boolean_t clean_logs, apr_pool_t *pool); /** Run database recovery procedures on the repository at @a path, * returning the database to a consistent state. Use @a pool for all * allocation. * * Acquires an @a exclusive lock on the repository, recovers the * database, and releases the lock. If an exclusive lock can't be * acquired, returns error. */ svn_error_t *svn_repos_recover (const char *path, apr_pool_t *pool); /** This function is a wrapper around svn_fs_berkeley_logfiles(), * returning log file paths relative to the root of the repository. * * @copydoc svn_fs_berkeley_logfiles() */ svn_error_t *svn_repos_db_logfiles (apr_array_header_t **logfiles, const char *path, svn_boolean_t only_unused, apr_pool_t *pool); /* Repository Paths */ /** Return the top-level repository path allocated in @a pool. */ const char *svn_repos_path (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's Berkeley DB environment, allocated in * @a pool. */ const char *svn_repos_db_env (svn_repos_t *repos, apr_pool_t *pool); /** Return path to @a repos's config directory, allocated in @a pool. */ const char *svn_repos_conf_dir (svn_repos_t *repos, apr_pool_t *pool); /** Return path to @a repos's svnserve.conf, allocated in @a pool. */ const char *svn_repos_svnserve_conf (svn_repos_t *repos, apr_pool_t *pool); /** Return path to @a repos's lock directory, allocated in @a pool. */ const char *svn_repos_lock_dir (svn_repos_t *repos, apr_pool_t *pool); /** Return path to @a repos's db lockfile, allocated in @a pool. */ const char *svn_repos_db_lockfile (svn_repos_t *repos, apr_pool_t *pool); /** Return path to @a repos's db logs lockfile, allocated in @a pool. */ const char *svn_repos_db_logs_lockfile (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's hook directory, allocated in @a pool. */ const char *svn_repos_hook_dir (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's start-commit hook, allocated in @a pool. */ const char *svn_repos_start_commit_hook (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's pre-commit hook, allocated in @a pool. */ const char *svn_repos_pre_commit_hook (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's post-commit hook, allocated in @a pool. */ const char *svn_repos_post_commit_hook (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's pre-revprop-change hook, allocated in * @a pool. */ const char *svn_repos_pre_revprop_change_hook (svn_repos_t *repos, apr_pool_t *pool); /** Return the path to @a repos's post-revprop-change hook, allocated in * @a pool. */ const char *svn_repos_post_revprop_change_hook (svn_repos_t *repos, apr_pool_t *pool); /* ---------------------------------------------------------------*/ /* Reporting the state of a working copy, for updates. */ /** Construct and return a @a report_baton that will be paired with some * @c svn_ra_reporter_t table. The table and baton are used to build a * transaction in the system; when the report is finished, * @c svn_repos_dir_delta is called on the transaction, driving * @a editor/@a edit_baton. * * Specifically, the report will create a transaction made by @a username, * relative to @a fs_base in the filesystem. @a target is a single path * component, used to limit the scope of the report to a single entry of * @a fs_base, or "" if all of @a fs_base itself is the main subject of * the report. * * @a tgt_path and @a revnum is the fs path/revision pair that is the * "target" of @c dir_delta. In other words, a tree delta will be * returned that transforms the transaction into @a tgt_path/@a revnum. * @a tgt_path may (indeed, should) be @c NULL when the source and target * paths of the report are the same. That is, @a tgt_path should *only* * be specified when specifying that the resultant editor drive be one * that transforms the reported hierarchy into a pristine tree of * @a tgt_path at revision @a revnum. Else, a @c NULL value for @a tgt_path * will indicate that the editor should be driven in such a way as to * transform the reported hierarchy to revision @a revnum, preserving the * reported hierarchy. * * @a text_deltas instructs the driver of the @a editor to enable * the generation of text deltas. * * @a recurse instructs the driver of the @a editor to send a recursive * delta (or not.) * * @a ignore_ancestry instructs the driver to ignore node ancestry * when determining how to transmit differences. * * The @a authz_read_func and @a authz_read_baton are passed along to * @c svn_repos_dir_delta(); see that function for how they are used. * * All allocation for the context and collected state will occur in * @a pool. */ svn_error_t * svn_repos_begin_report (void **report_baton, svn_revnum_t revnum, const char *username, svn_repos_t *repos, const char *fs_base, const char *target, const char *tgt_path, svn_boolean_t text_deltas, svn_boolean_t recurse, svn_boolean_t ignore_ancestry, const svn_delta_editor_t *editor, void *edit_baton, svn_repos_authz_func_t authz_read_func, void *authz_read_baton, apr_pool_t *pool); /** Given a @a report_baton constructed by @c svn_repos_begin_report(), this * routine will build @a revision:@a path into the current transaction. * This routine is called multiple times to create a transaction that * is a "mirror" of a working copy. * * The first call of this in a given report usually passes an empty * @a path; that allows the reporter to set up the correct root revision * (useful when creating a txn, for example). * * If @a start_empty is set and @a path is a directory, then remove * all children and props of the freshly-linked directory. This is * for 'low confidence' client reporting. * * All temporary allocations are done in @a pool. */ svn_error_t *svn_repos_set_path (void *report_baton, const char *path, svn_revnum_t revision, svn_boolean_t start_empty, apr_pool_t *pool); /** Given a @a report_baton constructed by @c svn_repos_begin_report(), * this routine will build @a revision:@a link_path into the current * transaction at @a path. Note that while @a path is relative to the * anchor/target used in the creation of the @a report_baton, @a link_path * is an absolute filesystem path! * * If @a start_empty is set and @a path is a directory, then remove * all children and props of the freshly-linked directory. This is * for 'low confidence' client reporting. * * All temporary allocations are done in @a pool. */ svn_error_t *svn_repos_link_path (void *report_baton, const char *path, const char *link_path, svn_revnum_t revision, svn_boolean_t start_empty, apr_pool_t *pool); /** Given a @a report_baton constructed by @c svn_repos_begin_report(), * this routine will remove @a path from the current fs transaction. * * (This allows the reporter's driver to describe missing pieces of a * working copy, so that 'svn up' can recreate them.) * * All temporary allocations are done in @a pool. */ svn_error_t *svn_repos_delete_path (void *report_baton, const char *path, apr_pool_t *pool); /** Make the filesystem compare the transaction to a revision and have * it drive an update editor (using @c svn_repos_delta_dirs()), then * abort the transaction. If an error occurs during the driving of * the editor, we do NOT abort the edit; that responsibility belongs * to the caller, if it happens at all. The fs transaction will be * aborted even if the editor drive fails, so the caller does not need * to clean up. */ svn_error_t *svn_repos_finish_report (void *report_baton, apr_pool_t *pool); /** The report-driver is bailing, so abort the fs transaction. This * function can be called anytime before @c svn_repos_finish_report() is * called. No other reporting functions should be called after calling * this function. */ svn_error_t *svn_repos_abort_report (void *report_baton, apr_pool_t *pool); /* ---------------------------------------------------------------*/ /* The magical dir_delta update routines. */ /** Use the provided @a editor and @a edit_baton to describe the changes * necessary for making a given node (and its descendants, if it is a * directory) under @a src_root look exactly like @a tgt_path under * @a tgt_root. @a src_entry is the node to update. If @a src_entry * is empty, then compute the difference between the entire tree * anchored at @a src_parent_dir under @a src_root and @a tgt_path * under @a target_root. Else, describe the changes needed to update * only that entry in @a src_parent_dir. Typically, callers of this * function will use a @a tgt_path that is the concatenation of @a * src_parent_dir and @a src_entry. * * @a src_root and @a tgt_root can both be either revision or transaction * roots. If @a tgt_root is a revision, @a editor's @c set_target_revision() * will be called with the @a tgt_root's revision number, else it will * not be called at all. * * If @a authz_read_func is non-null, invoke it before any call to * * @a editor->open_root * @a editor->add_directory * @a editor->open_directory * @a editor->add_file * @a editor->open_file * * passing @a tgt_root, the same path that would be passed to the * editor function in question, and @a authz_read_baton. If the * @a *allowed parameter comes back TRUE, then proceed with the planned * editor call; else if FALSE, then invoke @a editor->absent_file or * @a editor->absent_directory as appropriate, except if the planned * editor call was open_root, throw SVN_ERR_AUTHZ_ROOT_UNREADABLE. * * If @a text_deltas is @c FALSE, send a single @c NULL txdelta window to * the window handler returned by @a editor->apply_textdelta(). * * If @a entry_props is @c TRUE, accompany each opened/added entry with * propchange editor calls that relay special "entry props" (this * is typically used only for working copy updates). * * @a ignore_ancestry instructs the function to ignore node ancestry * when determining how to transmit differences. * * Before completing successfully, this function calls @a editor's * @c close_edit(), so the caller should expect its @a edit_baton to be * invalid after its use with this function. * * Do any allocation necessary for the delta computation in @a pool. * This function's maximum memory consumption is at most roughly * proportional to the greatest depth of the tree under @a tgt_root, not * the total size of the delta. */ 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_path, 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); /** Use the provided @a editor and @a edit_baton to describe the * skeletal changes made in a particular filesystem @a root * (revision or transaction). * * The @a editor passed to this function should be aware of the fact * that calls to its change_dir_prop(), change_file_prop(), and * apply_textdelta() functions will not contain meaningful data, and * merely serve as indications that properties or textual contents * were changed. * * NOTE: this editor driver passes SVN_INVALID_REVNUM for all * revision parameters in the editor interface except the copyfrom * parameter of the add_file() and add_directory() editor functions. * * ### TODO: This ought to take an svn_repos_authz_func_t too. * The only reason it doesn't yet is the difficulty of implementing * that correctly, plus lack of strong present need -- it's currently * only used in creating a DAV MERGE response, in 'svnadmin dump', and * in svnlook. */ svn_error_t * svn_repos_replay (svn_fs_root_t *root, const svn_delta_editor_t *editor, void *edit_baton, apr_pool_t *pool); /* ---------------------------------------------------------------*/ /* Making commits. */ /** Return an @a editor and @a edit_baton to commit changes to @a session->fs, * beginning at location 'rev:@a base_path', where "rev" is the argument * given to @c open_root(). Store @a user as the author of the commit and * @a log_msg as the commit message. * * @a repos is a previously opened repository. @a repos_url is the decoded * URL to the base of the repository, and is used to check copyfrom paths. * * Calling @a (*editor)->close_edit completes the commit. Before * @c close_edit returns, but after the commit has succeeded, it will * invoke @a callback with the new revision number, the commit date (as a * const char *), commit author (as a const char *), and * @a callback_baton as arguments. If @a callback returns an error, that * error will be returned from @c close_edit, otherwise if there was a * post-commit hook failure, then that error will be returned and will * have code SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED. */ svn_error_t *svn_repos_get_commit_editor (const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, const char *repos_url, const char *base_path, const char *user, const char *log_msg, svn_commit_callback_t callback, void *callback_baton, apr_pool_t *pool); /* ---------------------------------------------------------------*/ /* Finding particular revisions. */ /** Set @a *revision to the revision number in @a repos's filesystem that was * youngest at time @a tm. */ svn_error_t * svn_repos_dated_revision (svn_revnum_t *revision, svn_repos_t *repos, apr_time_t tm, apr_pool_t *pool); /** Given a @a root/@a path within some filesystem, return three pieces of * information allocated in @a pool: * * - set @a *committed_rev to the revision in which the object was * last modified. (In fs parlance, this is the revision in which * the particular node-rev-id was 'created'.) * * - set @a *committed_date to the date of said revision, or @c NULL * if not available. * * - set @a *last_author to the author of said revision, or @c NULL * if not available. */ svn_error_t * svn_repos_get_committed_info (svn_revnum_t *committed_rev, const char **committed_date, const char **last_author, svn_fs_root_t *root, const char *path, apr_pool_t *pool); /** Callback type for use with svn_repos_history(). @a path and @a * revision represent interesting history locations in the lifetime * of the path passed to svn_repos_history(). @a baton is the same * baton given to svn_repos_history(). @a pool is provided for the * convenience of the implementor, who should not expect it to live * longer than a single callback call. */ typedef svn_error_t *(*svn_repos_history_func_t) (void *baton, const char *path, svn_revnum_t revision, apr_pool_t *pool); /** Call @a history_func (with @a history_baton) for each interesting * history location in the lifetime of @a path in @a fs, from the * youngest of @a end and @ start to the oldest. Only cross * filesystem copy history if @a cross_copies is @c TRUE. And do all * of this in @a pool. */ svn_error_t * svn_repos_history (svn_fs_t *fs, const char *path, svn_repos_history_func_t history_func, void *history_baton, svn_revnum_t start, svn_revnum_t end, svn_boolean_t cross_copies, apr_pool_t *pool); /* ### other queries we can do someday -- * fetch the last revision created by (once usernames become revision properties!) * fetch the last revision where was modified */ /* ---------------------------------------------------------------*/ /* Retrieving log messages. */ /** Invoke @a receiver with @a receiver_baton on each log message from * @a start to @a end in @a repos's filesystem. @a start may be greater * or less than @a end; this just controls whether the log messages are * processed in descending or ascending revision number order. * * If @a start or @a end is @c SVN_INVALID_REVNUM, it defaults to youngest. * * If @a paths is non-null and has one or more elements, then only show * revisions in which at least one of @a paths was changed (i.e., if * file, text or props changed; if dir, props changed or an entry was * added or deleted). Each path is an const char * representing * an absolute path in the repository. * * ### todo: need to consider whether the above directory behavior is * most useful, or if we should actually treat _any_ node change in a * directory as a visible change for purposes of log... i.e., show * bubble-up. The reason this might be useful is so that running log * on a directory would give a msg for every change under that dir, * no matter how far down. See the thread started on the dev list by * Lars Kellogg-Stedman with the subject * "Single repository, multiple projects?" for more. We may simple * need to offer a few different semantics for @a paths. * * If @a discover_changed_paths, then each call to @a receiver passes a * const apr_hash_t * for the receiver's @a changed_paths * argument; the hash's keys are all the paths committed in that revision. * Otherwise, each call to @a receiver passes null for @a changed_paths. * * If @a strict_node_history is set, copy history (if any exists) will * not be traversed while harvesting revision logs for each path. * * If any invocation of @a receiver returns error, return that error * immediately and without wrapping it. * * If @a start or @a end is a non-existent revision, return the error * @c SVN_ERR_FS_NO_SUCH_REVISION, without ever invoking @a receiver. * * See also the documentation for @c svn_log_message_receiver_t. * * Use @a pool for temporary allocations. */ svn_error_t * svn_repos_get_logs (svn_repos_t *repos, const apr_array_header_t *paths, svn_revnum_t start, svn_revnum_t end, svn_boolean_t discover_changed_paths, svn_boolean_t strict_node_history, svn_log_message_receiver_t receiver, void *receiver_baton, apr_pool_t *pool); /* ---------------------------------------------------------------*/ /** * @defgroup svn_repos_hook_wrappers Hook-sensitive wrappers for libsvn_fs * routines. * @{ */ /** Like @c svn_fs_commit_txn(), but invoke the @a repos's pre- and * post-commit hooks around the commit. Use @a pool for any necessary * allocations. * * If the pre-commit hook or svn_fs_commit_txn() fails, throw the * original error to caller. If an error occurs when running the * post-commit hook, return the original error wrapped with * SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED. If the caller sees this * error, it knows that the commit succeeded anyway. * * @a conflict_p, @a new_rev, and @a txn are as in @c svn_fs_commit_txn(). */ svn_error_t *svn_repos_fs_commit_txn (const char **conflict_p, svn_repos_t *repos, svn_revnum_t *new_rev, svn_fs_txn_t *txn, apr_pool_t *pool); /** Like @c svn_fs_begin_txn(), but use @a author and @a log_msg to set the * corresponding properties on transaction @a *txn_p. @a repos is the * repository object which contains the filesystem. @a rev, @a *txn_p, and * @a pool are as in @c svn_fs_begin_txn(). * * Before a txn is created, the repository's start-commit hooks are * run; if any of them fail, no txn is created, @a *txn_p is unaffected, * and @c SVN_ERR_REPOS_HOOK_FAILURE is returned. * * @a log_msg may be @c NULL to indicate the message is not (yet) available. * The caller will need to attach it to the transaction at a later time. */ svn_error_t *svn_repos_fs_begin_txn_for_commit (svn_fs_txn_t **txn_p, svn_repos_t *repos, svn_revnum_t rev, const char *author, const char *log_msg, apr_pool_t *pool); /** Like @c svn_fs_begin_txn(), but use @a author to set the corresponding * property on transaction @a *txn_p. @a repos is the repository object * which contains the filesystem. @a rev, @a *txn_p, and @a pool are as in * @c svn_fs_begin_txn(). * * ### Someday: before a txn is created, some kind of read-hook could * be called here. */ svn_error_t *svn_repos_fs_begin_txn_for_update (svn_fs_txn_t **txn_p, svn_repos_t *repos, svn_revnum_t rev, const char *author, apr_pool_t *pool); /** Like @c svn_fs_change_rev_prop(), but invoke the @a repos's pre- and * post-revprop-change hooks around the change. Use @a pool for * temporary allocations. * * @a rev is the revision whose property to change, @a name is the * name of the property, and @a new_value is the new value of the * property. @a author is the authenticated username of the person * changing the property value, or null if not available. */ svn_error_t *svn_repos_fs_change_rev_prop (svn_repos_t *repos, svn_revnum_t rev, const char *author, const char *name, const svn_string_t *new_value, apr_pool_t *pool); /* ---------------------------------------------------------------*/ /* Prop-changing wrappers for libsvn_fs routines. */ /* NOTE: svn_repos_fs_change_rev_prop() also exists, but is located above with the hook-related functions. */ /** Validating wrapper for @c svn_fs_change_node_prop() (which see for * argument descriptions). */ svn_error_t *svn_repos_fs_change_node_prop (svn_fs_root_t *root, const char *path, const char *name, const svn_string_t *value, apr_pool_t *pool); /** Validating wrapper for @c svn_fs_change_txn_prop() (which see for * argument descriptions). */ svn_error_t *svn_repos_fs_change_txn_prop (svn_fs_txn_t *txn, const char *name, const svn_string_t *value, apr_pool_t *pool); /** @} */ /* ---------------------------------------------------------------*/ /** * @defgroup svn_repos_inspection Data structures and editor things for * repository inspection. * @{ * * As it turns out, the @c svn_repos_dir_delta() interface can be * extremely useful for examining the repository, or more exactly, * changes to the repository. @c svn_repos_dir_delta() allows for * differences between two trees to be described using an editor. * * By using the specific editor found below in conjunction with * @c svn_repos_dir_delta(), the description of how to transform one tree * into another can be used to build an in-memory linked-list tree, * which each node representing a repository node that was changed as a * result of having @c svn_repos_dir_delta() drive that editor. */ /** A node in the repository. */ typedef struct svn_repos_node_t { /** Node type (file, dir, etc.) */ svn_node_kind_t kind; /** How this node entered the node tree: 'A'dd, 'D'elete, 'R'eplace */ char action; /** Were there any textual mods? (files only) */ svn_boolean_t text_mod; /** Where there any property mods? */ svn_boolean_t prop_mod; /** The name of this node as it appears in its parent's entries list */ const char *name; /** The filesystem revision where this was copied from (if any) */ svn_revnum_t copyfrom_rev; /** The filesystem path where this was copied from (if any) */ const char *copyfrom_path; /** Pointer to the next sibling of this node */ struct svn_repos_node_t *sibling; /** Pointer to the first child of this node */ struct svn_repos_node_t *child; /** Pointer to the parent of this node */ struct svn_repos_node_t *parent; } svn_repos_node_t; /** Set @a *editor and @a *edit_baton to an editor that, when driven by * @c svn_repos_dir_delta(), builds an svn_repos_node_t * tree * representing the delta from @a base_root to @a root in @a repos's * filesystem. * * Invoke @c svn_repos_node_from_baton() on @a edit_baton to obtain the root * node afterwards. * * Note that the delta includes "bubbled-up" directories; that is, * many of the directory nodes will have no prop_mods. * * Allocate the tree and its contents in @a node_pool; do all other * allocation in @a pool. */ svn_error_t *svn_repos_node_editor (const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, svn_fs_root_t *base_root, svn_fs_root_t *root, apr_pool_t *node_pool, apr_pool_t *pool); /** Return the root node of the linked-list tree generated by driving * the editor created by @c svn_repos_node_editor() with * @c svn_repos_dir_delta(), which is stored in @a edit_baton. This is * only really useful if used *after* the editor drive is completed. */ svn_repos_node_t *svn_repos_node_from_baton (void *edit_baton); /** @} */ /* ---------------------------------------------------------------*/ /** * @defgroup svn_repos_dump_load Dumping and loading filesystem data * @{ * * The filesystem 'dump' format contains nothing but the abstract * structure of the filesystem -- independent of any internal node-id * schema or database back-end. All of the data in the dumpfile is * acquired by public function calls into svn_fs.h. Similarly, the * parser which reads the dumpfile is able to reconstruct the * filesystem using only public svn_fs.h routines. * * Thus the dump/load feature's main purpose is for *migrating* data * from one svn filesystem to another -- presumably two filesystems * which have different internal implementations. * * If you simply want to backup your filesystem, you're probably * better off using the built-in facilities of the DB backend (using * Berkeley DB's hot-backup feature, for example.) * * For a description of the dumpfile format, see * /trunk/notes/fs_dumprestore.txt. */ /* The RFC822-style headers in our dumpfile format. */ #define SVN_REPOS_DUMPFILE_MAGIC_HEADER "SVN-fs-dump-format-version" #define SVN_REPOS_DUMPFILE_FORMAT_VERSION 2 #define SVN_REPOS_DUMPFILE_UUID "UUID" #define SVN_REPOS_DUMPFILE_CONTENT_LENGTH "Content-length" #define SVN_REPOS_DUMPFILE_REVISION_NUMBER "Revision-number" #define SVN_REPOS_DUMPFILE_NODE_PATH "Node-path" #define SVN_REPOS_DUMPFILE_NODE_KIND "Node-kind" #define SVN_REPOS_DUMPFILE_NODE_ACTION "Node-action" #define SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH "Node-copyfrom-path" #define SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV "Node-copyfrom-rev" #define SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_CHECKSUM "Text-copy-source-md5" #define SVN_REPOS_DUMPFILE_TEXT_CONTENT_CHECKSUM "Text-content-md5" #define SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH "Prop-content-length" #define SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH "Text-content-length" /** The different "actions" attached to nodes in the dumpfile. */ enum svn_node_action { svn_node_action_change, svn_node_action_add, svn_node_action_delete, svn_node_action_replace }; /** The different policies for processing the UUID in the dumpfile. */ enum svn_repos_load_uuid { svn_repos_load_uuid_default, svn_repos_load_uuid_ignore, svn_repos_load_uuid_force }; /** Dump the contents of the filesystem within already-open @a repos into * writable @a dumpstream. Begin at revision @a start_rev, and dump every * revision up through @a end_rev. Use @a pool for all allocation. If * non-@c NULL, send feedback to @a feedback_stream. @a dumpstream can be * @c NULL for the purpose of verifying the repository. * * If @a start_rev is @c SVN_INVALID_REVNUM, then start dumping at revision * 0. If @a end_rev is @c SVN_INVALID_REVNUM, then dump through the @c HEAD * revision. * * If @a incremental is @c TRUE, the first revision dumped will be a diff * against the previous revision (usually it looks like a full dump of * the tree). * * If @a cancel_func is not @c NULL, it is called periodically with * @a cancel_baton as argument to see if the client wishes to cancel * the dump. */ svn_error_t *svn_repos_dump_fs (svn_repos_t *repos, svn_stream_t *dumpstream, svn_stream_t *feedback_stream, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_boolean_t incremental, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool); /** Read and parse dumpfile-formatted @a dumpstream, reconstructing * filesystem revisions in already-open @a repos, handling uuids * in accordance with @a uuid_action. * * Read and parse dumpfile-formatted @a dumpstream, reconstructing * filesystem revisions in already-open @a repos. Use @a pool for all * allocation. If non-@c NULL, send feedback to @a feedback_stream. * * If the dumpstream contains copy history that is unavailable in the * repository, an error will be thrown. * * The repository's UUID will be updated iff * the dumpstream contains a UUID and * @a uuid_action is not equal to @c svn_repos_load_uuid_ignore and * either the repository contains no revisions or * @a uuid_action is equal to @c svn_repos_load_uuid_force. * * If the dumpstream contains no UUID, then @a uuid_action is * ignored and the repository UUID is not touched. * * If @a cancel_func is not @c NULL, it is called periodically with * @a cancel_baton as argument to see if the client wishes to cancel * the load. */ svn_error_t *svn_repos_load_fs (svn_repos_t *repos, svn_stream_t *dumpstream, svn_stream_t *feedback_stream, enum svn_repos_load_uuid uuid_action, const char *parent_dir, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool); /** A vtable that is driven by @c svn_repos_parse_dumpstream. */ typedef struct svn_repos_parse_fns_t { /** The parser has discovered a new revision record within the * parsing session represented by @a parse_baton. All the headers are * placed in @a headers (allocated in @a pool), which maps const * char * header-name ==> const char * header-value. * The @a revision_baton received back (also allocated in @a pool) * represents the revision. */ svn_error_t *(*new_revision_record) (void **revision_baton, apr_hash_t *headers, void *parse_baton, apr_pool_t *pool); /** The parser has discovered a new uuid record within the parsing * session represented by @a parse_baton. The uuid's value is * @a uuid, and it is allocated in @a pool. */ svn_error_t *(*uuid_record) (const char *uuid, void *parse_baton, apr_pool_t *pool); /** The parser has discovered a new node record within the current * revision represented by @a revision_baton. All the headers are * placed in @a headers as above, allocated in @a pool. The * @a node_baton received back is allocated in @a pool and represents * the node. */ svn_error_t *(*new_node_record) (void **node_baton, apr_hash_t *headers, void *revision_baton, apr_pool_t *pool); /** For a given @a revision_baton, set a property @a name to @a value. */ svn_error_t *(*set_revision_property) (void *revision_baton, const char *name, const svn_string_t *value); /** For a given @a node_baton, set a property @a name to @a value. */ svn_error_t *(*set_node_property) (void *node_baton, const char *name, const svn_string_t *value); /** For a given @a node_baton, remove all properties. */ svn_error_t *(*remove_node_props) (void *node_baton); /** For a given @a node_baton, receive a writable @a stream capable of * receiving the node's fulltext. After writing the fulltext, call * the stream's @c close() function. * * If a @c NULL is returned instead of a stream, the vtable is * indicating that no text is desired, and the parser will not * attempt to send it. */ svn_error_t *(*set_fulltext) (svn_stream_t **stream, void *node_baton); /** The parser has reached the end of the current node represented by * @a node_baton, it can be freed. */ svn_error_t *(*close_node) (void *node_baton); /** The parser has reached the end of the current revision * represented by @a revision_baton. In other words, there are no more * changed nodes within the revision. The baton can be freed. */ svn_error_t *(*close_revision) (void *revision_baton); } svn_repos_parser_fns_t; /** Read and parse dumpfile-formatted @a stream, calling callbacks in * @a parse_fns/@a parse_baton, and using @a pool for allocations. * * If @a cancel_func is not @c NULL, it is called periodically with * @a cancel_baton as argument to see if the client wishes to cancel * the dump. * * This parser has built-in knowledge of the dumpfile format, but only * in a general sense: * * * it recognizes revision and node records by looking for either * a REVISION_NUMBER or NODE_PATH headers. * * * it recognizes the CONTENT-LENGTH headers, so it knows if and * how to suck up the content body. * * * it knows how to parse a content body into two parts: props * and text, and pass the pieces to the vtable. * * This is enough knowledge to make it easy on vtable implementors, * but still allow expansion of the format: most headers are ignored. */ svn_error_t * svn_repos_parse_dumpstream (svn_stream_t *stream, const svn_repos_parser_fns_t *parse_fns, void *parse_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool); /** Set @a *parser and @a *parse_baton to a vtable parser which commits new * revisions to the fs in @a repos. The constructed parser will treat * UUID records in a manner consistent with @a uuid_action. Use @a pool * to operate on the fs. * * If @a use_history is set, then the parser will require relative * 'copyfrom' history to exist in the repository when it encounters * nodes that are added-with-history. * * If @a parent_dir is not null, then the parser will reparent all the * loaded nodes, from root to @a parent_dir. The directory @a parent_dir * must be an existing directory in the repository. * * Print all parsing feedback to @a outstream (if non-@c NULL). * */ svn_error_t * svn_repos_get_fs_build_parser (const svn_repos_parser_fns_t **parser, void **parse_baton, svn_repos_t *repos, svn_boolean_t use_history, enum svn_repos_load_uuid uuid_action, svn_stream_t *outstream, const char *parent_dir, apr_pool_t *pool); /** @} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* SVN_REPOS_H */