blob: 756ae54399cbff767d19a3acc174091eb4b49d76 [file] [log] [blame]
/* svn_fs.h : interface to the Subversion filesystem
*
* ====================================================================
* Copyright (c) 2000-2002 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/.
* ====================================================================
*/
/* ==================================================================== */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef SVN_FS_H
#define SVN_FS_H
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_tables.h>
#include "svn_types.h"
#include "svn_error.h"
#include "svn_delta.h"
#include "svn_io.h"
/* Opening and creating filesystems. */
/* An object representing a Subversion filesystem. */
typedef struct svn_fs_t svn_fs_t;
/* Create a new filesystem object in POOL. It doesn't refer to any
actual repository yet; you need to invoke svn_fs_open_* or
svn_fs_create_* on it for that to happen.
NOTE: you probably don't want to use this directly, especially not
if it's followed immediately by a call to svn_fs_open_berkeley().
Take a look at svn_repos_open() instead. */
svn_fs_t *svn_fs_new (apr_pool_t *pool);
/* Free the filesystem object FS. This frees memory, closes files,
frees database library structures, etc. */
svn_error_t *svn_fs_close_fs (svn_fs_t *fs);
/* The type of a warning callback function. BATON is the value specified
in the call to `svn_fs_set_warning_func'; the filesystem passes it through
to the callback. FMT is a printf-style format string, which tells us
how to interpret any successive arguments. */
#ifndef SWIG
typedef void (*svn_fs_warning_callback_t) (void *baton, const char *fmt, ...);
#endif
/* Provide a callback function, WARNING, that FS should use to report
warning messages. To print a warning message, the filesystem will
call WARNING, passing it BATON, a printf-style format string, and
any further arguments as appropriate for the format string.
If it's acceptable to print messages on stderr, then the function
`svn_handle_warning', declared in "svn_error.h", would be a
suitable warning function.
By default, this is set to a function that will crash the process.
Dumping to stderr or /dev/tty is not acceptable default behavior
for server processes, since those may both be equivalent to
/dev/null. */
void svn_fs_set_warning_func (svn_fs_t *fs,
svn_fs_warning_callback_t warning,
void *warning_baton);
/* Subversion filesystems based on Berkeley DB. */
/* There are many possible ways to implement the Subversion filesystem
interface. You could implement it directly using ordinary POSIX
filesystem operations; you could build it using an SQL server as a
back end; you could build it on RCS; and so on.
The functions on this page create filesystem objects that use
Berkeley DB (http://www.sleepycat.com) to store their data.
Berkeley DB supports transactions and recoverability, making it
well-suited for Subversion.
A Berkeley DB ``environment'' is a Unix directory containing
database files, log files, backing files for shared memory buffers,
and so on --- everything necessary for a complex database
application. Each Subversion filesystem lives in a single Berkeley
DB environment. */
/* Create a new, empty Subversion filesystem, stored in a Berkeley DB
environment under PATH. Make FS refer to this new filesystem.
FS provides the memory pool, warning function, etc. If PATH
exists, it must be an empty directory. */
svn_error_t *svn_fs_create_berkeley (svn_fs_t *fs, const char *path);
/* Make FS refer to the Berkeley DB-based Subversion filesystem at
PATH. PATH must refer to a file or directory created by
`svn_fs_create_berkeley'.
Only one thread may operate on any given filesystem object at once.
Two threads may access the same filesystem simultaneously only if
they open separate filesystem objects.
NOTE: you probably don't want to use this directly, especially not
if it's immediately preceded by a call to svn_fs_new(). Take a
look at svn_repos_open() instead. */
svn_error_t *svn_fs_open_berkeley (svn_fs_t *fs, const char *path);
/* Return the path to FS's repository, allocated in POOL.
Note: this is just what was passed to svn_fs_create_berkeley() or
svn_fs_open_berkeley() -- might be absolute, might not. */
const char *svn_fs_berkeley_path (svn_fs_t *fs, apr_pool_t *pool);
/* Register an error handling function for Berkeley DB error messages.
If a Berkeley DB error occurs, the filesystem will call HANDLER
with two strings: an error message prefix, which will be zero, and
an error message. HANDLER should print it out, log it somewhere,
etc.
Since Berkeley DB's error messages are sometimes much more
informative than the error codes the functions return, it's worth
calling this function and providing some kind of error message
handler.
This function calls `DBENV->set_errcall', with HANDLER as the
`db_errcall_fcn' argument. */
svn_error_t *svn_fs_set_berkeley_errcall (svn_fs_t *fs,
void (*handler) (const char *errpfx,
char *msg));
/* Delete the Berkeley DB-based filesystem PATH. This deletes the
database files, log files, shared memory segments, etc. PATH should
refer to a file or directory created by `svn_fs_create_berkeley'. */
svn_error_t *svn_fs_delete_berkeley (const char *PATH, apr_pool_t *pool);
/* Perform any necessary non-catastrophic recovery on a Berkeley
DB-based Subversion filesystem, stored in the environment PATH. Do
any necessary allocation within POOL.
After an unexpected server exit, due to a server crash or a system
crash, a Subversion filesystem based on Berkeley DB needs to run
recovery procedures to bring the database back into a consistent
state and release any locks that were held by the deceased process.
The recovery procedures require exclusive access to the database
--- while they execute, no other process or thread may access the
database.
In a server with multiple worker processes, like Apache, if a
worker process accessing the filesystem dies, you must stop the
other worker processes, and run recovery. Then, the other worker
processes can re-open the database and resume work.
If the server exited cleanly, there is no need to run recovery, but
there is no harm in it, either, and it take very little time. So
it's a fine idea to run recovery when the server process starts,
before it begins handling any requests. */
svn_error_t *svn_fs_berkeley_recover (const char *path,
apr_pool_t *pool);
/* Node and Node Revision ID's. */
/* In a Subversion filesystem, a `node' corresponds roughly to an
`inode' in a Unix filesystem:
- A node is either a file or a directory.
- A node's contents change over time.
- When you change a node's contents, it's still the same node; it's
just been changed. So a node's identity isn't bound to a specific
set of contents.
- If you rename a node, it's still the same node, just under a
different name. So a node's identity isn't bound to a particular
filename.
A `node revision' refers to a node's contents at a specific point in
time. Changing a node's contents always creates a new revision of that
node. Once created, a node revision's contents never change.
When we create a node, its initial contents are the initial revision of
the node. As users make changes to the node over time, we create new
revisions of that same node. When a user commits a change that deletes
a file from the filesystem, we don't delete the node, or any revision
of it --- those stick around to allow us to recreate prior revisions of
the filesystem. Instead, we just remove the reference to the node
from the directory.
Within the database, we refer to nodes and node revisions using strings
of numbers separated by periods that look a lot like RCS revision
numbers.
node_id ::= number | node_revision_id "." number
node_revision_id ::= node_id "." number
So:
- "100" is a node id.
- "100.10" is a node revision id, referring to revision 10 of node 100.
- "100.10.3" is a node id, referring to the third branch based on
revision 10 of node 100.
- "100.10.3.4" is a node revision id, referring to revision 4 of
of the third branch from revision 10 of node 100.
And so on.
Node revision numbers start with 1. Thus, N.1 is the first revision
of node N.
Node / branch numbers start with 1. Thus, N.M.1 is the first
branch off of N.M.
A directory entry identifies the file or subdirectory it refers to
using a node revision number --- not a node number. This means that
a change to a file far down in a directory hierarchy requires the
parent directory of the changed node to be updated, to hold the new
node revision ID. Now, since that parent directory has changed, its
parent needs to be updated.
If a particular subtree was unaffected by a given commit, the node
revision ID that appears in its parent will be unchanged. When
doing an update, we can notice this, and ignore that entire
subtree. This makes it efficient to find localized changes in
large trees.
Note that the number specifying a particular revision of a node is
unrelated to the global filesystem revision when that node revision
was created. So 100.10 may have been created in filesystem revision
1218; 100.10.3.2 may have been created any time after 100.10; it
doesn't matter.
Since revision numbers increase by one each time a delta is added,
we can compute how many deltas separate two related node revisions
simply by comparing their ID's. For example, the distance between
100.10.3.2 and 100.12 is the distance from 100.10.3.2 to their
common ancestor, 100.10 (two deltas), plus the distance from 100.10
to 100.12 (two deltas).
However, this is kind of a kludge, since the number of deltas is
not necessarily an accurate indicator of how different two files
are --- a single delta could be a minor change, or a complete
replacement. Furthermore, the filesystem may decide arbitrary to
store a given node revision as a delta or as full text --- perhaps
depending on how recently the node was used --- so revision id
distance isn't necessarily an accurate predictor of retrieval time.
If you have insights about how this stuff could work better, let me
know. I've read some of Josh MacDonald's stuff on this; his
discussion seems to be mostly about how to retrieve things quickly,
which is important, but only part of the issue. I'd like to find
better ways to recognize renames, and find appropriate ancestors in
a source tree for changed files. */
/* Within the code, we represent node and node revision ID's as arrays
of integers, terminated by a -1 element. This is the type of an
element of a node ID. */
typedef svn_revnum_t svn_fs_id_t;
/* Return the distance between node revisions A and B. Return -1 if
they are completely unrelated. */
int svn_fs_id_distance (const svn_fs_id_t *a, const svn_fs_id_t *b);
/* Perform an exhaustive traversal through node-id and copy-from
history to determine if the nodes associated with ID1 and ID2, and
found in filesystem FS, are related. If so, set *RELATED to 1,
else to 0. Use POOL for allocations. */
svn_error_t *svn_fs_check_related (int *related,
svn_fs_t *fs,
const svn_fs_id_t *id1,
const svn_fs_id_t *id2,
apr_pool_t *pool);
/* Parse the LEN bytes at DATA as a node or node revision ID. Return
zero if the bytes are not a properly-formed ID. A properly formed
ID matches the regexp:
[0-9]+(\.[0-9]+)*
Allocate the parsed ID in POOL. If POOL is zero, malloc the ID; we
need this in certain cases where we can't pass in a pool, but it's
generally best to use a pool whenever possible. */
svn_fs_id_t *svn_fs_parse_id (const char *data, apr_size_t len,
apr_pool_t *pool);
/* Return a Subversion string containing the unparsed form of the node
or node revision id ID. Allocate the string containing the
unparsed form in POOL. */
svn_stringbuf_t *svn_fs_unparse_id (const svn_fs_id_t *id, apr_pool_t *pool);
/* Transactions. */
/* To make a change to a Subversion filesystem:
- Create a transaction object, using `svn_fs_begin_txn'.
- Call `svn_fs_txn_root', to get the transaction's root directory.
- Make whatever changes you like in that tree.
- Commit the transaction, using `svn_fs_commit_txn'.
The filesystem implementation guarantees that your commit will
either:
- succeed completely, so that all of the changes are committed to
create a new revision of the filesystem, or
- fail completely, leaving the filesystem unchanged.
Until you commit the transaction, any changes you make are
invisible. Only when your commit succeeds do they become visible
to the outside world, as a new revision of the filesystem.
If you begin a transaction, and then decide you don't want to make
the change after all (say, because your net connection with the
client disappeared before the change was complete), you can call
`svn_fs_abort_txn', to cancel the entire transaction; this
leaves the filesystem unchanged.
The only way to change the contents of files or directories, or
their properties, is by making a transaction and creating a new
revision, as described above. Once a revision has been committed, it
never changes again; the filesystem interface provides no means to
go back and edit the contents of an old revision. Once history has
been recorded, it is set in stone. Clients depend on this property
to do updates and commits reliably; proxies depend on this property
to cache changes accurately; and so on.
There are two kinds of nodes in the filesystem: mutable, and
immutable. Revisions in the filesystem consist entirely of
immutable nodes, whose contents never change. A transaction in
progress, which the user is still constructing, uses mutable nodes
for those nodes which have been changed so far, and refers to
immutable nodes from existing revisions for portions of the tree
which haven't been changed yet in that transaction.
Immutable nodes, as part of revisions, never refer to mutable
nodes, which are part of uncommitted transactions. Mutable nodes
may refer to immutable nodes, or other mutable nodes.
Note that the terms "immutable" and "mutable" describe whether or
not the nodes have been changed as part of a transaction --- not
the permissions on the nodes they refer to. Even if you aren't
authorized to modify the filesystem's root directory, you might be
authorized to change some descendant of the root; doing so would
create a new mutable copy of the root directory. Mutability refers
to the role of the node: part of an existing revision, or part of a
new one. This is independent of your authorization to make changes
to a given node.
Transactions are actually persistent objects, stored in the
database. You can open a filesystem, begin a transaction, and
close the filesystem, and then a separate process could open the
filesystem, pick up the same transaction, and continue work on it.
When a transaction is successfully committed, it is removed from
the database.
Every transaction is assigned a name. You can open a transaction
by name, and resume work on it, or find out the name of a
transaction you already have open. You can also list all the
transactions currently present in the database.
Transaction names are guaranteed to contain only letters (upper-
and lower-case), digits, `-', and `.', from the ASCII character
set. */
/* The type of a Subversion transaction object. */
typedef struct svn_fs_txn_t svn_fs_txn_t;
/* Begin a new transaction on the filesystem FS, based on existing
revision REV. Set *TXN_P to a pointer to the new transaction.
When committed, this transaction will create a new revision.
Allocate the new transaction in POOL; when POOL is freed, the new
transaction will be closed (neither committed nor aborted). You
can also close the transaction explicitly, using
`svn_fs_close_txn'.
>> Note: if you're building a txn for committing, you probably <<
>> don't want to call this directly. Instead, call <<
>> svn_repos_fs_begin_txn_for_commit(), which honors the <<
>> repository's hook configurations. <<
*/
svn_error_t *svn_fs_begin_txn (svn_fs_txn_t **txn_p,
svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *pool);
/* Commit TXN.
>> Note: you usually don't want to call this directly. <<
>> Instead, call svn_repos_fs_commit_txn(), which honors the <<
>> repository's hook configurations. <<
If the transaction conflicts with other changes committed to the
repository, return an SVN_ERR_FS_CONFLICT error. Otherwise, create
a new filesystem revision containing the changes made in TXN,
storing that new revision number in *NEW_REV, and return zero.
If CONFLICT_P is non-zero, use it to provide details on any
conflicts encountered merging TXN with the most recent committed
revisions. If a conflict occurs, set *CONFLICT_P to the path of
the conflict in TXN. Otherwise, set *CONFLICT_P to null.
If the commit succeeds, it frees TXN, and any temporary resources
it holds. Any root objects (see below) referring to the root
directory of TXN become invalid; performing any operation on them
other than closing them will produce an SVN_ERR_FS_DEAD_TRANSACTION
error.
If the commit fails, TXN is still valid; you can make more
operations to resolve the conflict, or call `svn_fs_abort_txn' to
abort the transaction. */
svn_error_t *svn_fs_commit_txn (const char **conflict_p,
svn_revnum_t *new_rev,
svn_fs_txn_t *txn);
/* Abort the transaction TXN. Any changes made in TXN are discarded,
and the filesystem is left unchanged.
If the abort succeeds, it frees TXN, and any temporary resources
it holds. Any root objects referring to TXN's root directory
become invalid; performing any operation on them other than closing
them will produce an SVN_ERR_FS_DEAD_TRANSACTION error. */
svn_error_t *svn_fs_abort_txn (svn_fs_txn_t *txn);
/* Set *NAME_P to the name of the transaction TXN, as a
null-terminated string. Allocate the name in POOL. */
svn_error_t *svn_fs_txn_name (const char **name_p,
svn_fs_txn_t *txn,
apr_pool_t *pool);
/* Return the filesystem to which TXN belongs. */
svn_fs_t *svn_fs_txn_fs (svn_fs_txn_t *txn);
/* Return TXN's pool. */
apr_pool_t *svn_fs_txn_pool (svn_fs_txn_t *txn);
/* Return TXN's base revision. If TXN's base root id is an mutable
node, return 0. */
svn_revnum_t svn_fs_txn_base_revision (svn_fs_txn_t *txn);
/* Open the transaction named NAME in the filesystem FS. Set *TXN to
the transaction.
If there is no such transaction, SVN_ERR_FS_NO_SUCH_TRANSACTION is
the error returned.
Allocate the new transaction in POOL; when POOL is freed, the new
transaction will be closed (neither committed nor aborted). You
can also close the transaction explicitly, using
`svn_fs_close_txn'. */
svn_error_t *svn_fs_open_txn (svn_fs_txn_t **txn,
svn_fs_t *fs,
const char *name,
apr_pool_t *pool);
/* Close the transaction TXN. This is neither an abort nor a commit;
the state of the transaction so far is stored in the filesystem, to
be opened again later. */
svn_error_t *svn_fs_close_txn (svn_fs_txn_t *txn);
/* Set *NAMES_P to a null-terminated array of pointers to strings,
containing the names of all the currently active transactions in
the filesystem FS. Allocate the array in POOL. */
svn_error_t *svn_fs_list_transactions (char ***names_p,
svn_fs_t *fs,
apr_pool_t *pool);
/* Transaction properties */
/* Set *VALUE_P to the value of the property named PROPNAME on
transaction TXN. If TXN has no property by that name, set *VALUE_P
to zero. Allocate the result in POOL. */
svn_error_t *svn_fs_txn_prop (svn_string_t **value_p,
svn_fs_txn_t *txn,
const char *propname,
apr_pool_t *pool);
/* Set *TABLE_P to the entire property list of transaction TXN in
filesystem FS, as an APR hash table allocated in POOL. The
resulting table maps property names to pointers to svn_string_t
objects containing the property value. */
svn_error_t *svn_fs_txn_proplist (apr_hash_t **table_p,
svn_fs_txn_t *txn,
apr_pool_t *pool);
/* Change a tranactions TXN's property's value, or add/delete a
property. NAME is the name of the property to change, and VALUE is
the new value of the property, or zero if the property should be
removed altogether. Do any necessary temporary allocation in
POOL. */
svn_error_t *svn_fs_change_txn_prop (svn_fs_txn_t *txn,
const char *name,
const svn_string_t *value,
apr_pool_t *pool);
/* Roots. */
/* An svn_fs_root_t object represents the root directory of some
revision or transaction in a filesystem. To refer to particular
node, you provide a root, and a directory path relative that root. */
typedef struct svn_fs_root_t svn_fs_root_t;
/* Set *ROOT_P to the root directory of revision REV in filesystem FS.
Allocate *ROOT_P in POOL. */
svn_error_t *svn_fs_revision_root (svn_fs_root_t **root_p,
svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *pool);
/* Set *ROOT_P to the root directory of TXN. Allocate *ROOT_P in POOL. */
svn_error_t *svn_fs_txn_root (svn_fs_root_t **root_p,
svn_fs_txn_t *txn,
apr_pool_t *pool);
/* Set *ROOT_P to a root object that can be used to access nodes by
node revision ID in FS. Whenever you pass *ROOT_P to a filesystem
access function, any filename "relative" to *ROOT_P must actually
be the printed form of a node revision ID: a sequence of decimal
numbers without leading zeros, separated by '.' characters,
containing an even number of numbers; otherwise, return
SVN_ERR_FS_NOT_ID. Allocate ROOT_P in POOL. */
svn_error_t *svn_fs_id_root (svn_fs_root_t **root_p,
svn_fs_t *fs,
apr_pool_t *pool);
/* Free the root directory ROOT. Simply clearing or destroying the
pool ROOT was allocated in will have the same effect as calling
this function. */
void svn_fs_close_root (svn_fs_root_t *root);
/* Return the filesystem to which ROOT belongs. */
svn_fs_t *svn_fs_root_fs (svn_fs_root_t *root);
/* Return true iff ROOT is a transaction/revision/id root. */
int svn_fs_is_txn_root (svn_fs_root_t *root);
int svn_fs_is_revision_root (svn_fs_root_t *root);
int svn_fs_is_id_root (svn_fs_root_t *root);
/* If ROOT is the root of a transaction, return a pointer to the name
of the transaction; otherwise, return zero. The name is owned by
ROOT, and will be freed when ROOT is closed. */
const char *svn_fs_txn_root_name (svn_fs_root_t *root,
apr_pool_t *pool);
/* If ROOT is the root of a revision, return the revision number.
Otherwise, return -1. */
svn_revnum_t svn_fs_revision_root_revision (svn_fs_root_t *root);
/* If PATH in TXN_ROOT matches the specified ID, then set MATCHES to
true (1). Otherwise, set MATCHES to zero.
In essence, this function answers the question, "I want to change
node ID. Is that the node which is present in TXN_ROOT?" If the
TXN_ROOT is based on the youngest (head) revision, then this test
is essentially a test for out-of-dateness.
Note that a small compensation is made for asking to change a
directory identified by ID, but where the directory's id in the
TXN_ROOT is different because it was modified by the bubble-up
algorithm of a change below the directory. Since there were no
semantic changes, this function deems the bubbled-up directory
to match the specified ID, and returns MATCHES := 1.
All temporary allocation is performed in POOL. */
svn_error_t *svn_fs_txn_path_is_id (int *matches,
svn_fs_root_t *txn_root,
const char *path,
const svn_fs_id_t *id,
apr_pool_t *pool);
/* Directory entry names and directory paths. */
/* Here are the rules for directory entry names, and directory paths:
A directory entry name is a Unicode string encoded in UTF-8, and
may not contain the null character (U+0000). The name should be in
Unicode canonical decomposition and ordering. No directory entry
may be named '.', '..', or the empty string. Given a directory
entry name which fails to meet these requirements, a filesystem
function returns an SVN_ERR_FS_PATH_SYNTAX error.
A directory path is a sequence of zero or more directory entry
names, separated by slash characters (U+002f), and possibly ending
with slash characters. Sequences of two or more consecutive slash
characters are treated as if they were a single slash. If a path
ends with a slash, it refers to the same node it would without the
slash, but that node must be a directory, or else the function
returns an SVN_ERR_FS_NOT_DIRECTORY error.
A path consisting of the empty string, or a string containing only
slashes, refers to the root directory. */
/* Operations appropriate to all kinds of nodes. */
/* Return the type of node present at PATH under ROOT. If PATH
does not exist under ROOT, set *KIND to svn_node_none. */
svn_node_kind_t svn_fs_check_path (svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Allocate and return an array *REVS of svn_revnum_t revisions in
which PATHS under ROOT were modified. Use POOL for all allocations.
The array of *REVS are sorted in descending order. All duplicates
will also be removed. PATHS is an array of `const char *' entries.
NOTE: This function uses node-id ancestry alone to determine
modifiedness, and therefore does NOT claim that in any of the
returned revisions file contents changed, properties changed,
directory entries lists changed, etc. */
svn_error_t *svn_fs_revisions_changed (apr_array_header_t **revs,
svn_fs_root_t *root,
const apr_array_header_t *paths,
apr_pool_t *pool);
/* Set *IS_DIR to non-zero iff PATH in ROOT is a directory.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_is_dir (int *is_dir,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Set *IS_FILE to non-zero iff PATH in ROOT is a file.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_is_file (int *is_file,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Set *ID_P to the node revision ID of PATH in ROOT, allocated in POOL.
If ROOT is the root of a transaction, keep in mind that other
changes to the transaction can change which node PATH refers to,
and even whether the path exists at all. */
svn_error_t *svn_fs_node_id (svn_fs_id_t **id_p,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Set *REVISION to the revision in which PATH under ROOT was created.
Use POOL for any temporary allocations. *REVISION will be set to
SVN_INVALID_REVNUM for uncommitted nodes (i.e. modified nodes under
a transaction root). */
svn_error_t *svn_fs_node_created_rev (svn_revnum_t *revision,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Set *VALUE_P to the value of the property named PROPNAME of PATH in
ROOT. If the node has no property by that name, set *VALUE_P to
zero. Allocate the result in POOL. */
svn_error_t *svn_fs_node_prop (svn_string_t **value_p,
svn_fs_root_t *root,
const char *path,
const char *propname,
apr_pool_t *pool);
/* Set *TABLE_P to the entire property list of PATH in ROOT, as an APR
hash table allocated in POOL. The resulting table maps property
names to pointers to svn_string_t objects containing the property
value. */
svn_error_t *svn_fs_node_proplist (apr_hash_t **table_p,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Change a node's property's value, or add/delete a property.
- ROOT and PATH indicate the node whose property should change.
ROOT must be the root of a transaction, not the root of a revision.
- NAME is the name of the property to change.
- VALUE is the new value of the property, or zero if the property should
be removed altogether.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_change_node_prop (svn_fs_root_t *root,
const char *path,
const char *name,
const svn_string_t *value,
apr_pool_t *pool);
/* Set *CHANGED_P to 1 if the properties at PATH1 under ROOT1 differ
from those at PATH2 under ROOT2, or set it to 0 if they are the
same. Both paths must exist under their respective roots, and both
roots must be in the same filesystem. */
svn_error_t *svn_fs_props_changed (int *changed_p,
svn_fs_root_t *root1,
const char *path1,
svn_fs_root_t *root2,
const char *path2,
apr_pool_t *pool);
/* Discover a node's copy ancestry, if any.
If the node at PATH in ROOT was copied from some other node, set
*REV_P and *PATH_P to the revision and path of the other node,
allocating *PATH_P in POOL.
Else if there is no copy ancestry for the node, set *REV_P to
SVN_INVALID_REVNUM and and *PATH_P to null.
If an error is returned, the values of *REV_P and *PATH_P are
undefined, but otherwise, if one of them is set as described above,
you may assume the other is set correspondingly.
ROOT may be a revision root or a transaction root.
Notes:
- Copy ancestry does not descend. After copying directory D to
E, E will have copy ancestry referring to D, but E's children
may not. See also svn_fs_copy().
- Copy ancestry *under* a copy is preserved. That is, if you
copy /A/D/G/pi to /A/D/G/pi2, and then copy /A/D/G to /G, then
/G/pi2 will still have copy ancestry pointing to /A/D/G/pi.
We don't know if this is a feature or a bug yet; if it turns
out to be a bug, then the fix is to make svn_fs_copied_from()
observe the following logic, which currently callers may
choose to follow themselves: if node X has copy history, but
its ancestor A also has copy history, then you may ignore X's
history if X's revision-of-origin is earlier than A's --
because that would mean that X's copy history was preserved in
a copy-under-a-copy scenario. If X's revision-of-origin is
the same as A's, then it was copied under A during the same
transaction that created A. (X's revision-of-origin cannot be
greater than A's, if X has copy history.) ### todo: See how
people like this, it can always be hidden behind the curtain
if necessary.
- Copy ancestry is not stored as a regular subversion property
because it is not inherited. Copying foo to bar results in a
revision of bar with copy ancestry; but committing a text
change to bar right after that results in a new revision of
bar without copy ancestry. */
svn_error_t *svn_fs_copied_from (svn_revnum_t *rev_p,
const char **path_p,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Given nodes SOURCE and TARGET, and a common ancestor ANCESTOR,
modify TARGET to contain all the changes made between ANCESTOR and
SOURCE, as well as the changes made between ANCESTOR and TARGET.
TARGET_ROOT must be the root of a transaction, not a revision.
SOURCE, TARGET, and ANCESTOR are generally directories; this
function recursively merges the directories' contents. If they are
files, this function simply returns an error whenever SOURCE,
TARGET, and ANCESTOR are all distinct node revisions.
If there are differences between ANCESTOR and SOURCE that conflict
with changes between ANCESTOR and TARGET, this function returns an
SVN_ERR_FS_CONFLICT error.
If the merge is successful, TARGET is left in the merged state, and
the base root of TARGET's txn is set to the root node of SOURCE.
If an error is returned (whether for conflict or otherwise), TARGET
is left unaffected.
If CONFLICT_P is non-null, then: a conflict error sets *CONFLICT_P
to the name of the node in TARGET which couldn't be merged,
otherwise, success sets *CONFLICT_P to null.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_merge (const char **conflict_p,
svn_fs_root_t *source_root,
const char *source_path,
svn_fs_root_t *target_root,
const char *target_path,
svn_fs_root_t *ancestor_root,
const char *ancestor_path,
apr_pool_t *pool);
/* Compare the nodes ROOT1:PATH1 and ROOT2:PATH2, and determine if
they are "different". Return the answer in IS_DIFFERENT.
We define two nodes to be "different" if:
- they are different node types, or
- if both files, they have different node-revision-ids, or
- if both dirs, they have different entry lists.
(Note that there is a small chance of getting a false positive: two
different node-rev-ids don't *necessarily* have different contents.
But right now it's not worth doing byte-for-byte comparisons. This
problem will go away when we have deltified storage.) */
svn_error_t *svn_fs_is_different (int *is_different,
svn_fs_root_t *root1,
const char *path1,
svn_fs_root_t *root2,
const char *path2,
apr_pool_t *pool);
/* Deltification of Storage. */
/* Examine the data associated with PATH under ROOT, and offer the
filesystem a chance store that data in a deltified fashion. ROOT
is a revision root.
If PATH represents a directory, deltify PATH's properties and list
of entries, and if RECURSIVE is non-zero, perform this operation
recursively on PATH's children.
If PATH represents a file, deltify PATH's properties and text
contents (and ignore the RECURSIVE argument).
Use POOL for all necessary allocations. */
svn_error_t *svn_fs_deltify (svn_fs_root_t *root,
const char *path,
int recursive,
apr_pool_t *pool);
/* Ensure that the data associated with PATH under ROOT is stored as
fulltext (that is, in an undeltified fashion). If this is already
the case, do nothing. ROOT is a revision root.
If PATH represents a directory, un-deltify PATH's properties and list
of entries, and if RECURSIVE is non-zero, perform this operation
recursively on PATH's children.
If PATH represents a file, un-deltify PATH's properties and text
contents (and ignore the RECURSIVE argument).
Use POOL for all necessary allocations. */
svn_error_t *svn_fs_undeltify (svn_fs_root_t *root,
const char *path,
int recursive,
apr_pool_t *pool);
/* Directories. */
/* The type of a Subversion directory entry. */
typedef struct svn_fs_dirent_t {
/* The name of this directory entry. */
char *name;
/* The node revision ID it names. */
svn_fs_id_t *id;
} svn_fs_dirent_t;
/* Set *TABLE_P to a newly allocated APR hash table containing the
entries of the directory at PATH in ROOT. The keys of the table
are entry names, as byte strings, excluding the final null
character; the table's values are pointers to svn_fs_dirent_t
structures. Allocate the table and its contents in POOL. */
svn_error_t *svn_fs_dir_entries (apr_hash_t **entries_p,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Create a new directory named PATH in ROOT. The new directory has
no entries, and no properties. ROOT must be the root of a
transaction, not a revision.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_make_dir (svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Delete the node named PATH in ROOT. ROOT must be the root of a
transaction, not a revision. Do any necessary temporary allocation
in POOL.
If the node being deleted is a directory, it must be empty, else
the error SVN_ERR_FS_DIR_NOT_EMPTY is returned.
Attempting to remove the root dir also results in an error,
SVN_ERR_FS_ROOT_DIR, even if the dir is empty. */
svn_error_t *svn_fs_delete (svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Delete the node named PATH in ROOT. If the node being deleted is a
directory, its contents will be deleted recursively. ROOT must be
the root of a transaction, not of a revision. Use POOL for
temporary allocation.
This function may be more efficient than making the equivalent
series of calls to svn_fs_delete, because it takes advantage of the
fact that, to delete an immutable subtree, shared with some
committed revision, you need only remove the directory entry. The
dumb algorithm would recurse into the subtree and end up cloning
each non-empty directory it contains, only to delete it later.
If return SVN_ERR_FS_NO_SUCH_ENTRY, then the basename of PATH is
missing from its parent, that is, the final target of the deletion
is missing. */
svn_error_t *svn_fs_delete_tree (svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Move the node named FROM to TO, both in ROOT. ROOT must be the
root of a transaction, not a revision.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_rename (svn_fs_root_t *root,
const char *from,
const char *to,
apr_pool_t *pool);
/* Create a copy of FROM_PATH in FROM_ROOT named TO_PATH in TO_ROOT.
If FROM_PATH in FROM_ROOT is a directory, copy the tree it refers
to recursively.
The copy will remember its source; use svn_fs_copied_from() to
access this information.
TO_ROOT must be the root of a transaction; FROM_PATH must be the
root of a revision. (Requiring FROM_PATH to be the root of a
revision makes the implementation trivial: there is no detectable
difference (modulo node revision ID's) between copying FROM and
simply adding a reference to it. So the operation takes place in
constant time. However, there's no reason not to extend this to
mutable nodes --- it's just more code.)
Note: to do a copy without preserving copy history, use
svn_fs_link().
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_copy (svn_fs_root_t *from_root,
const char *from_path,
svn_fs_root_t *to_root,
const char *to_path,
apr_pool_t *pool);
/* Like svn_fs_copy(), but doesn't record copy history. I.e., you
cannot use svn_fs_copied_from() later to find out where this copy
came from.
Use svn_fs_link() in situations where you don't care about the copy
history, because it is slightly cheaper than svn_fs_copy(). */
svn_error_t *svn_fs_link (svn_fs_root_t *from_root,
const char *from_path,
svn_fs_root_t *to_root,
const char *to_path,
apr_pool_t *pool);
/* Files. */
/* Set *LENGTH_P to the length of the file PATH in ROOT, in bytes. Do
any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_file_length (apr_off_t *length_p,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Set *CONTENTS to a readable generic stream will yield the contents
of the file PATH in ROOT. Allocate the stream in POOL. You can
only use *CONTENTS for as long as the underlying filesystem is
open. If PATH is not a file, return SVN_ERR_FS_NOT_FILE.
If ROOT is the root of a transaction, it is possible that the
contents of the file PATH will change between calls to
svn_fs_file_contents(). In that case, the result of reading from
*CONTENTS is undefined.
### kff todo: I am worried about lifetime issues with this pool vs
the trail created farther down the call stack. Trace this function
to investigate... */
svn_error_t *svn_fs_file_contents (svn_stream_t **contents,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Create a new file named PATH in ROOT. The file's initial contents
are the empty string, and it has no properties. ROOT must be the
root of a transaction, not a revision.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_make_file (svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Apply a text delta to the file PATH in ROOT. ROOT must be the root
of a transaction, not a revision.
Set *CONTENTS_P to a function ready to receive text delta windows
describing how to change the file's contents, relative to its
current contents. Set *CONTENTS_BATON_P to a baton to pass to
*CONTENTS_P.
If PATH does not exist in ROOT, return an error. (You cannot use
this routine to create new files; use svn_fs_make_file to create
an empty file first.)
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_apply_textdelta (svn_txdelta_window_handler_t *contents_p,
void **contents_baton_p,
svn_fs_root_t *root,
const char *path,
apr_pool_t *pool);
/* Set *CHANGED_P to 1 if the contents at PATH1 under ROOT1 differ
from those at PATH2 under ROOT2, or set it to 0 if they are the
same. Both paths must exist under their respective roots, and both
roots must be in the same filesystem. */
svn_error_t *svn_fs_contents_changed (int *changed_p,
svn_fs_root_t *root1,
const char *path1,
svn_fs_root_t *root2,
const char *path2,
apr_pool_t *pool);
/* Filesystem revisions. */
/* Set *YOUNGEST_P to the number of the youngest revision in filesystem FS.
Use POOL for all temporary allocation.
The oldest revision in any filesystem is numbered zero. */
svn_error_t *svn_fs_youngest_rev (svn_revnum_t *youngest_p,
svn_fs_t *fs,
apr_pool_t *pool);
/* Set *VALUE_P to the value of the property named PROPNAME on
revision REV in the filesystem FS. If REV has no property by that
name, set *VALUE_P to zero. Allocate the result in POOL. */
svn_error_t *svn_fs_revision_prop (svn_string_t **value_p,
svn_fs_t *fs,
svn_revnum_t rev,
const char *propname,
apr_pool_t *pool);
/* Set *TABLE_P to the entire property list of revision REV in
filesystem FS, as an APR hash table allocated in POOL. The table
maps char * property names to svn_string_t * values; the names
and values are allocated in POOL. */
svn_error_t *svn_fs_revision_proplist (apr_hash_t **table_p,
svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *pool);
/* Change a revision's property's value, or add/delete a property.
- FS is a filesystem, and REV is the revision in that filesystem
whose property should change.
- NAME is the name of the property to change.
- VALUE is the new value of the property, or zero if the property should
be removed altogether.
Note that revision properties are non-historied --- you can change
them after the revision has been committed. They are not protected
via transactions.
Do any necessary temporary allocation in POOL. */
svn_error_t *svn_fs_change_rev_prop (svn_fs_t *fs,
svn_revnum_t rev,
const char *name,
const svn_string_t *value,
apr_pool_t *pool);
/* Computing deltas. */
/* Set *STREAM_P to a pointer to a delta stream that will turn the
contents of the file SOURCE into the contents of the file TARGET.
If SOURCE_ROOT is zero, use a file with zero length as the source.
This function does not compare the two files' properties.
Allocate *STREAM_P, and do any necessary temporary allocation, in
POOL. */
svn_error_t *
svn_fs_get_file_delta_stream (svn_txdelta_stream_t **stream_p,
svn_fs_root_t *source_root,
const char *source_path,
svn_fs_root_t *target_root,
const char *target_path,
apr_pool_t *pool);
/* Non-historical properties. */
/* [[Yes, do tell.]] */
#endif /* SVN_FS_H */
#ifdef __cplusplus
}
#endif /* __cplusplus */
/* ----------------------------------------------------------------
* local variables:
* eval: (load-file "../../tools/dev/svn-dev.el")
* end:
*/