/* fs_skels.c --- conversion between fs native types and skeletons
*
* ====================================================================
* 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 <string.h>
#include "svn_error.h"
#include "svn_string.h"
#include "svn_types.h"
#include "svn_time.h"
#include "fs_skels.h"
#include "skel.h"
#include "../id.h"
static svn_error_t *
skel_err(const char *skel_type)
{
return svn_error_createf(SVN_ERR_FS_MALFORMED_SKEL, NULL,
"Malformed%s%s skeleton",
skel_type ? " " : "",
skel_type ? skel_type : "");
}
/*** Validity Checking ***/
static svn_boolean_t
is_valid_checksum_skel(skel_t *skel)
{
if (svn_fs_base__list_length(skel) != 2)
return FALSE;
if (svn_fs_base__matches_atom(skel->children, "md5")
&& skel->children->next->is_atom)
return TRUE;
return FALSE;
}
static svn_boolean_t
is_valid_proplist_skel(skel_t *skel)
{
int len = svn_fs_base__list_length(skel);
if ((len >= 0) && (len & 1) == 0)
{
skel_t *elt;
for (elt = skel->children; elt; elt = elt->next)
if (! elt->is_atom)
return FALSE;
return TRUE;
}
return FALSE;
}
static svn_boolean_t
is_valid_revision_skel(skel_t *skel)
{
int len = svn_fs_base__list_length(skel);
if ((len == 2)
&& svn_fs_base__matches_atom(skel->children, "revision")
&& skel->children->next->is_atom)
return TRUE;
return FALSE;
}
static svn_boolean_t
is_valid_transaction_skel(skel_t *skel, transaction_kind_t *kind)
{
int len = svn_fs_base__list_length(skel);
if (len != 5)
return FALSE;
/* Determine (and verify) the kind. */
if (svn_fs_base__matches_atom(skel->children, "transaction"))
*kind = transaction_kind_normal;
else if (svn_fs_base__matches_atom(skel->children, "committed"))
*kind = transaction_kind_committed;
else if (svn_fs_base__matches_atom(skel->children, "dead"))
*kind = transaction_kind_dead;
else
return FALSE;
if (skel->children->next->is_atom
&& skel->children->next->next->is_atom
&& (! skel->children->next->next->next->is_atom)
&& (! skel->children->next->next->next->next->is_atom))
return TRUE;
return FALSE;
}
static svn_boolean_t
is_valid_rep_delta_chunk_skel(skel_t *skel)
{
int len;
skel_t *window;
skel_t *diff;
/* check the delta skel. */
if ((svn_fs_base__list_length(skel) != 2)
|| (! skel->children->is_atom))
return FALSE;
/* check the window. */
window = skel->children->next;
len = svn_fs_base__list_length(window);
if ((len < 3) || (len > 4))
return FALSE;
if (! ((! window->children->is_atom)
&& (window->children->next->is_atom)
&& (window->children->next->next->is_atom)))
return FALSE;
if ((len == 4)
&& (! window->children->next->next->next->is_atom))
return FALSE;
/* check the diff. ### currently we support only svndiff version
0 delta data. */
diff = window->children;
if ((svn_fs_base__list_length(diff) == 3)
&& (svn_fs_base__matches_atom(diff->children, "svndiff"))
&& ((svn_fs_base__matches_atom(diff->children->next, "0"))
|| (svn_fs_base__matches_atom(diff->children->next, "1")))
&& (diff->children->next->next->is_atom))
return TRUE;
return FALSE;
}
static svn_boolean_t
is_valid_representation_skel(skel_t *skel)
{
int len = svn_fs_base__list_length(skel);
skel_t *header;
int header_len;
/* the rep has at least two items in it, a HEADER list, and at least
one piece of kind-specific data. */
if (len < 2)
return FALSE;
/* check the header. it must have KIND and TXN atoms, and
optionally a CHECKSUM (which is a list form). */
header = skel->children;
header_len = svn_fs_base__list_length(header);
if (! (((header_len == 2) /* 2 means old repository, checksum absent */
&& (header->children->is_atom)
&& (header->children->next->is_atom))
|| ((header_len == 3) /* 3 means checksum present */
&& (header->children->is_atom)
&& (header->children->next->is_atom)
&& (is_valid_checksum_skel(header->children->next->next)))))
return FALSE;
/* check for fulltext rep. */
if ((len == 2)
&& (svn_fs_base__matches_atom(header->children, "fulltext")))
return TRUE;
/* check for delta rep. */
if ((len >= 2)
&& (svn_fs_base__matches_atom(header->children, "delta")))
{
/* it's a delta rep. check the validity. */
skel_t *chunk = skel->children->next;
/* loop over chunks, checking each one. */
while (chunk)
{
if (! is_valid_rep_delta_chunk_skel(chunk))
return FALSE;
chunk = chunk->next;
}
/* all good on this delta rep. */
return TRUE;
}
return FALSE;
}
static svn_boolean_t
is_valid_node_revision_header_skel(skel_t *skel, skel_t **kind_p)
{
int len = svn_fs_base__list_length(skel);
if (len < 2)
return FALSE;
/* set the *KIND_P pointer. */
*kind_p = skel->children;
/* without predecessor... */
if ((len == 2)
&& skel->children->is_atom
&& skel->children->next->is_atom
&& (skel->children->next->data[0] == '/'))
return TRUE;
/* or with predecessor... */
if ((len == 3)
&& skel->children->is_atom
&& skel->children->next->is_atom
&& (skel->children->next->data[0] == '/')
&& skel->children->next->next->is_atom)
return TRUE;
/* or with predecessor and predecessor count... */
if ((len == 4)
&& skel->children->is_atom
&& skel->children->next->is_atom
&& (skel->children->next->data[0] == '/')
&& skel->children->next->next->is_atom
&& skel->children->next->next->next->is_atom)
return TRUE;
return FALSE;
}
static svn_boolean_t
is_valid_node_revision_skel(skel_t *skel)
{
int len = svn_fs_base__list_length(skel);
if (len >= 1)
{
skel_t *header = skel->children;
skel_t *kind;
if (is_valid_node_revision_header_skel(header, &kind))
{
if (svn_fs_base__matches_atom(kind, "dir")
&& len == 3
&& header->next->is_atom
&& header->next->next->is_atom)
return TRUE;
if (svn_fs_base__matches_atom(kind, "file")
&& ((len == 3) || (len == 4))
&& header->next->is_atom
&& header->next->next->is_atom)
{
if ((len == 4) && (! header->next->next->next->is_atom))
return FALSE;
return TRUE;
}
}
}
return FALSE;
}
static svn_boolean_t
is_valid_copy_skel(skel_t *skel)
{
return (((svn_fs_base__list_length(skel) == 4)
&& (svn_fs_base__matches_atom(skel->children, "copy")
|| svn_fs_base__matches_atom(skel->children, "soft-copy"))
&& skel->children->next->is_atom
&& skel->children->next->next->is_atom
&& skel->children->next->next->next->is_atom) ? TRUE : FALSE);
}
static svn_boolean_t
is_valid_change_skel(skel_t *skel, svn_fs_path_change_kind_t *kind)
{
if ((svn_fs_base__list_length(skel) == 6)
&& svn_fs_base__matches_atom(skel->children, "change")
&& skel->children->next->is_atom
&& skel->children->next->next->is_atom
&& skel->children->next->next->next->is_atom
&& skel->children->next->next->next->next->is_atom
&& skel->children->next->next->next->next->next->is_atom)
{
skel_t *kind_skel = skel->children->next->next->next;
/* check the kind (and return it) */
if (svn_fs_base__matches_atom(kind_skel, "reset"))
{
if (kind)
*kind = svn_fs_path_change_reset;
return TRUE;
}
if (svn_fs_base__matches_atom(kind_skel, "add"))
{
if (kind)
*kind = svn_fs_path_change_add;
return TRUE;
}
if (svn_fs_base__matches_atom(kind_skel, "delete"))
{
if (kind)
*kind = svn_fs_path_change_delete;
return TRUE;
}
if (svn_fs_base__matches_atom(kind_skel, "replace"))
{
if (kind)
*kind = svn_fs_path_change_replace;
return TRUE;
}
if (svn_fs_base__matches_atom(kind_skel, "modify"))
{
if (kind)
*kind = svn_fs_path_change_modify;
return TRUE;
}
}
return FALSE;
}
static svn_boolean_t
is_valid_lock_skel(skel_t *skel)
{
if ((svn_fs_base__list_length(skel) == 8)
&& svn_fs_base__matches_atom(skel->children, "lock")
&& skel->children->next->is_atom
&& skel->children->next->next->is_atom
&& skel->children->next->next->next->is_atom
&& skel->children->next->next->next->next->is_atom
&& skel->children->next->next->next->next->next->is_atom
&& skel->children->next->next->next->next->next->next->is_atom
&& skel->children->next->next->next->next->next->next->next->is_atom)
return TRUE;
return FALSE;
}
/*** Parsing (conversion from skeleton to native FS type) ***/
svn_error_t *
svn_fs_base__parse_proplist_skel(apr_hash_t **proplist_p,
skel_t *skel,
apr_pool_t *pool)
{
apr_hash_t *proplist = NULL;
skel_t *elt;
/* Validate the skel. */
if (! is_valid_proplist_skel(skel))
return skel_err("proplist");
/* Create the returned structure */
if (skel->children)
proplist = apr_hash_make(pool);
for (elt = skel->children; elt; elt = elt->next->next)
{
svn_string_t *value = svn_string_ncreate(elt->next->data,
elt->next->len, pool);
apr_hash_set(proplist,
apr_pstrmemdup(pool, elt->data, elt->len),
elt->len,
value);
}
/* Return the structure. */
*proplist_p = proplist;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_revision_skel(revision_t **revision_p,
skel_t *skel,
apr_pool_t *pool)
{
revision_t *revision;
/* Validate the skel. */
if (! is_valid_revision_skel(skel))
return skel_err("revision");
/* Create the returned structure */
revision = apr_pcalloc(pool, sizeof(*revision));
revision->txn_id = apr_pstrmemdup(pool, skel->children->next->data,
skel->children->next->len);
/* Return the structure. */
*revision_p = revision;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_transaction_skel(transaction_t **transaction_p,
skel_t *skel,
apr_pool_t *pool)
{
transaction_t *transaction;
transaction_kind_t kind;
skel_t *root_id, *base_id_or_rev, *proplist, *copies;
int len;
/* Validate the skel. */
if (! is_valid_transaction_skel(skel, &kind))
return skel_err("transaction");
root_id = skel->children->next;
base_id_or_rev = skel->children->next->next;
proplist = skel->children->next->next->next;
copies = skel->children->next->next->next->next;
/* Create the returned structure */
transaction = apr_pcalloc(pool, sizeof(*transaction));
/* KIND */
transaction->kind = kind;
/* REVISION or BASE-ID */
if (kind == transaction_kind_committed)
{
/* Committed transactions have a revision number... */
transaction->base_id = NULL;
transaction->revision = atoi(apr_pstrmemdup(pool, base_id_or_rev->data,
base_id_or_rev->len));
if (! SVN_IS_VALID_REVNUM(transaction->revision))
return skel_err("transaction");
}
else
{
/* ...where unfinished transactions have a base node-revision-id. */
transaction->revision = SVN_INVALID_REVNUM;
transaction->base_id = svn_fs_base__id_parse(base_id_or_rev->data,
base_id_or_rev->len, pool);
}
/* ROOT-ID */
transaction->root_id = svn_fs_base__id_parse(root_id->data,
root_id->len, pool);
/* PROPLIST */
SVN_ERR(svn_fs_base__parse_proplist_skel(&(transaction->proplist),
proplist, pool));
/* COPIES */
if ((len = svn_fs_base__list_length(copies)))
{
const char *copy_id;
apr_array_header_t *txncopies;
skel_t *cpy = copies->children;
txncopies = apr_array_make(pool, len, sizeof(copy_id));
while (cpy)
{
copy_id = apr_pstrmemdup(pool, cpy->data, cpy->len);
(*((const char **)(apr_array_push(txncopies)))) = copy_id;
cpy = cpy->next;
}
transaction->copies = txncopies;
}
/* Return the structure. */
*transaction_p = transaction;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_representation_skel(representation_t **rep_p,
skel_t *skel,
apr_pool_t *pool)
{
representation_t *rep;
skel_t *header_skel;
/* Validate the skel. */
if (! is_valid_representation_skel(skel))
return skel_err("representation");
header_skel = skel->children;
/* Create the returned structure */
rep = apr_pcalloc(pool, sizeof(*rep));
/* KIND */
if (svn_fs_base__matches_atom(header_skel->children, "fulltext"))
rep->kind = rep_kind_fulltext;
else
rep->kind = rep_kind_delta;
/* TXN */
rep->txn_id = apr_pstrmemdup(pool, header_skel->children->next->data,
header_skel->children->next->len);
/* CHECKSUM */
if (header_skel->children->next->next)
{
memcpy(rep->checksum,
header_skel->children->next->next->children->next->data,
APR_MD5_DIGESTSIZE);
}
else
{
/* Older repository, no checksum, so manufacture an all-zero checksum */
memset(rep->checksum, 0, APR_MD5_DIGESTSIZE);
}
/* KIND-SPECIFIC stuff */
if (rep->kind == rep_kind_fulltext)
{
/* "fulltext"-specific. */
rep->contents.fulltext.string_key
= apr_pstrmemdup(pool,
skel->children->next->data,
skel->children->next->len);
}
else
{
/* "delta"-specific. */
skel_t *chunk_skel = skel->children->next;
rep_delta_chunk_t *chunk;
apr_array_header_t *chunks;
/* Alloc the chunk array. */
chunks = apr_array_make(pool, svn_fs_base__list_length(skel) - 1,
sizeof(chunk));
/* Process the chunks. */
while (chunk_skel)
{
skel_t *window_skel = chunk_skel->children->next;
skel_t *diff_skel = window_skel->children;
/* Allocate a chunk and its window */
chunk = apr_palloc(pool, sizeof(*chunk));
/* Populate the window */
chunk->version
= (apr_byte_t)atoi(apr_pstrmemdup
(pool,
diff_skel->children->next->data,
diff_skel->children->next->len));
chunk->string_key
= apr_pstrmemdup(pool,
diff_skel->children->next->next->data,
diff_skel->children->next->next->len);
chunk->size
= atoi(apr_pstrmemdup(pool,
window_skel->children->next->data,
window_skel->children->next->len));
chunk->rep_key
= apr_pstrmemdup(pool,
window_skel->children->next->next->data,
window_skel->children->next->next->len);
chunk->offset =
svn__atoui64(apr_pstrmemdup(pool,
chunk_skel->children->data,
chunk_skel->children->len));
/* Add this chunk to the array. */
(*((rep_delta_chunk_t **)(apr_array_push(chunks)))) = chunk;
/* Next... */
chunk_skel = chunk_skel->next;
}
/* Add the chunks array to the representation. */
rep->contents.delta.chunks = chunks;
}
/* Return the structure. */
*rep_p = rep;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_node_revision_skel(node_revision_t **noderev_p,
skel_t *skel,
apr_pool_t *pool)
{
node_revision_t *noderev;
skel_t *header_skel;
/* Validate the skel. */
if (! is_valid_node_revision_skel(skel))
return skel_err("node-revision");
header_skel = skel->children;
/* Create the returned structure */
noderev = apr_pcalloc(pool, sizeof(*noderev));
/* KIND */
if (svn_fs_base__matches_atom(header_skel->children, "dir"))
noderev->kind = svn_node_dir;
else
noderev->kind = svn_node_file;
/* CREATED-PATH */
noderev->created_path = apr_pstrmemdup(pool,
header_skel->children->next->data,
header_skel->children->next->len);
/* PREDECESSOR-ID */
if (header_skel->children->next->next)
{
noderev->predecessor_id
= svn_fs_base__id_parse(header_skel->children->next->next->data,
header_skel->children->next->next->len, pool);
/* PREDECESSOR-COUNT */
noderev->predecessor_count = -1;
if (header_skel->children->next->next->next)
noderev->predecessor_count =
atoi(apr_pstrmemdup(pool,
header_skel->children->next->next->next->data,
header_skel->children->next->next->next->len));
}
/* PROP-KEY */
if (skel->children->next->len)
noderev->prop_key = apr_pstrmemdup(pool, skel->children->next->data,
skel->children->next->len);
/* DATA-KEY */
if (skel->children->next->next->len)
noderev->data_key = apr_pstrmemdup(pool, skel->children->next->next->data,
skel->children->next->next->len);
/* EDIT-DATA-KEY (optional, files only) */
if ((noderev->kind == svn_node_file)
&& skel->children->next->next->next
&& skel->children->next->next->next->len)
noderev->edit_key
= apr_pstrmemdup(pool, skel->children->next->next->next->data,
skel->children->next->next->next->len);
/* Return the structure. */
*noderev_p = noderev;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_copy_skel(copy_t **copy_p,
skel_t *skel,
apr_pool_t *pool)
{
copy_t *copy;
/* Validate the skel. */
if (! is_valid_copy_skel(skel))
return skel_err("copy");
/* Create the returned structure */
copy = apr_pcalloc(pool, sizeof(*copy));
/* KIND */
if (svn_fs_base__matches_atom(skel->children, "soft-copy"))
copy->kind = copy_kind_soft;
else
copy->kind = copy_kind_real;
/* SRC-PATH */
copy->src_path = apr_pstrmemdup(pool,
skel->children->next->data,
skel->children->next->len);
/* SRC-TXN-ID */
copy->src_txn_id = apr_pstrmemdup(pool,
skel->children->next->next->data,
skel->children->next->next->len);
/* DST-NODE-ID */
copy->dst_noderev_id
= svn_fs_base__id_parse(skel->children->next->next->next->data,
skel->children->next->next->next->len, pool);
/* Return the structure. */
*copy_p = copy;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_entries_skel(apr_hash_t **entries_p,
skel_t *skel,
apr_pool_t *pool)
{
apr_hash_t *entries = NULL;
int len = svn_fs_base__list_length(skel);
skel_t *elt;
if (! (len >= 0))
return skel_err("entries");
if (len > 0)
{
/* Else, allocate a hash and populate it. */
entries = apr_hash_make(pool);
/* Check entries are well-formed as we go along. */
for (elt = skel->children; elt; elt = elt->next)
{
const char *name;
svn_fs_id_t *id;
/* ENTRY must be a list of two elements. */
if (svn_fs_base__list_length(elt) != 2)
return skel_err("entries");
/* Get the entry's name and ID. */
name = apr_pstrmemdup(pool, elt->children->data,
elt->children->len);
id = svn_fs_base__id_parse(elt->children->next->data,
elt->children->next->len, pool);
/* Add the entry to the hash. */
apr_hash_set(entries, name, elt->children->len, id);
}
}
/* Return the structure. */
*entries_p = entries;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_change_skel(change_t **change_p,
skel_t *skel,
apr_pool_t *pool)
{
change_t *change;
svn_fs_path_change_kind_t kind;
/* Validate the skel. */
if (! is_valid_change_skel(skel, &kind))
return skel_err("change");
/* Create the returned structure */
change = apr_pcalloc(pool, sizeof(*change));
/* PATH */
change->path = apr_pstrmemdup(pool, skel->children->next->data,
skel->children->next->len);
/* NODE-REV-ID */
if (skel->children->next->next->len)
change->noderev_id = svn_fs_base__id_parse
(skel->children->next->next->data, skel->children->next->next->len,
pool);
/* KIND */
change->kind = kind;
/* TEXT-MOD */
if (skel->children->next->next->next->next->len)
change->text_mod = TRUE;
/* PROP-MOD */
if (skel->children->next->next->next->next->next->len)
change->prop_mod = TRUE;
/* Return the structure. */
*change_p = change;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__parse_lock_skel(svn_lock_t **lock_p,
skel_t *skel,
apr_pool_t *pool)
{
svn_lock_t *lock;
const char *timestr;
/* Validate the skel. */
if (! is_valid_lock_skel(skel))
return skel_err("lock");
/* Create the returned structure */
lock = apr_pcalloc(pool, sizeof(*lock));
/* PATH */
lock->path = apr_pstrmemdup(pool, skel->children->next->data,
skel->children->next->len);
/* LOCK-TOKEN */
lock->token = apr_pstrmemdup(pool,
skel->children->next->next->data,
skel->children->next->next->len);
/* OWNER */
lock->owner = apr_pstrmemdup(pool,
skel->children->next->next->next->data,
skel->children->next->next->next->len);
/* COMMENT (could be just an empty atom) */
if (skel->children->next->next->next->next->len)
lock->comment =
apr_pstrmemdup(pool,
skel->children->next->next->next->next->data,
skel->children->next->next->next->next->len);
/* XML_P */
if (svn_fs_base__matches_atom
(skel->children->next->next->next->next->next, "1"))
lock->is_dav_comment = TRUE;
else
lock->is_dav_comment = FALSE;
/* CREATION-DATE */
timestr = apr_pstrmemdup
(pool,
skel->children->next->next->next->next->next->next->data,
skel->children->next->next->next->next->next->next->len);
SVN_ERR(svn_time_from_cstring(&(lock->creation_date),
timestr, pool));
/* EXPIRATION-DATE (could be just an empty atom) */
if (skel->children->next->next->next->next->next->next->next->len)
{
timestr =
apr_pstrmemdup
(pool,
skel->children->next->next->next->next->next->next->next->data,
skel->children->next->next->next->next->next->next->next->len);
SVN_ERR(svn_time_from_cstring(&(lock->expiration_date),
timestr, pool));
}
/* Return the structure. */
*lock_p = lock;
return SVN_NO_ERROR;
}
/*** Unparsing (conversion from native FS type to skeleton) ***/
svn_error_t *
svn_fs_base__unparse_proplist_skel(skel_t **skel_p,
apr_hash_t *proplist,
apr_pool_t *pool)
{
skel_t *skel = svn_fs_base__make_empty_list(pool);
apr_hash_index_t *hi;
/* Create the skel. */
if (proplist)
{
/* Loop over hash entries */
for (hi = apr_hash_first(pool, proplist); hi; hi = apr_hash_next(hi))
{
const void *key;
void *val;
apr_ssize_t klen;
svn_string_t *value;
apr_hash_this(hi, &key, &klen, &val);
value = val;
/* VALUE */
svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
value->len, pool),
skel);
/* NAME */
svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool), skel);
}
}
/* Validate and return the skel. */
if (! is_valid_proplist_skel(skel))
return skel_err("proplist");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_revision_skel(skel_t **skel_p,
const revision_t *revision,
apr_pool_t *pool)
{
skel_t *skel;
/* Create the skel. */
skel = svn_fs_base__make_empty_list(pool);
/* TXN_ID */
svn_fs_base__prepend(svn_fs_base__str_atom(revision->txn_id, pool), skel);
/* "revision" */
svn_fs_base__prepend(svn_fs_base__str_atom("revision", pool), skel);
/* Validate and return the skel. */
if (! is_valid_revision_skel(skel))
return skel_err("revision");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_transaction_skel(skel_t **skel_p,
const transaction_t *transaction,
apr_pool_t *pool)
{
skel_t *skel;
skel_t *proplist_skel, *copies_skel, *header_skel;
svn_string_t *id_str;
transaction_kind_t kind;
/* Create the skel. */
skel = svn_fs_base__make_empty_list(pool);
switch (transaction->kind)
{
case transaction_kind_committed:
header_skel = svn_fs_base__str_atom("committed", pool);
if ((transaction->base_id)
|| (! SVN_IS_VALID_REVNUM(transaction->revision)))
return skel_err("transaction");
break;
case transaction_kind_dead:
header_skel = svn_fs_base__str_atom("dead", pool);
if ((! transaction->base_id)
|| (SVN_IS_VALID_REVNUM(transaction->revision)))
return skel_err("transaction");
break;
case transaction_kind_normal:
header_skel = svn_fs_base__str_atom("transaction", pool);
if ((! transaction->base_id)
|| (SVN_IS_VALID_REVNUM(transaction->revision)))
return skel_err("transaction");
break;
default:
return skel_err("transaction");
}
/* COPIES */
copies_skel = svn_fs_base__make_empty_list(pool);
if (transaction->copies && transaction->copies->nelts)
{
int i;
for (i = transaction->copies->nelts - 1; i >= 0; i--)
{
svn_fs_base__prepend(svn_fs_base__str_atom
(APR_ARRAY_IDX(transaction->copies, i,
const char *), pool),
copies_skel);
}
}
svn_fs_base__prepend(copies_skel, skel);
/* PROPLIST */
SVN_ERR(svn_fs_base__unparse_proplist_skel(&proplist_skel,
transaction->proplist, pool));
svn_fs_base__prepend(proplist_skel, skel);
/* REVISION or BASE-ID */
if (transaction->kind == transaction_kind_committed)
{
/* Committed transactions have a revision number... */
svn_fs_base__prepend(svn_fs_base__str_atom
(apr_psprintf(pool, "%ld",
transaction->revision), pool),
skel);
}
else
{
/* ...where other transactions have a base node revision ID. */
id_str = svn_fs_base__id_unparse(transaction->base_id, pool);
svn_fs_base__prepend(svn_fs_base__mem_atom(id_str->data, id_str->len,
pool), skel);
}
/* ROOT-ID */
id_str = svn_fs_base__id_unparse(transaction->root_id, pool);
svn_fs_base__prepend(svn_fs_base__mem_atom(id_str->data, id_str->len,
pool), skel);
/* KIND (see above) */
svn_fs_base__prepend(header_skel, skel);
/* Validate and return the skel. */
if (! is_valid_transaction_skel(skel, &kind))
return skel_err("transaction");
if (kind != transaction->kind)
return skel_err("transaction");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_representation_skel(skel_t **skel_p,
const representation_t *rep,
apr_pool_t *pool)
{
skel_t *skel = svn_fs_base__make_empty_list(pool);
skel_t *header_skel = svn_fs_base__make_empty_list(pool);
/** Some parts of the header are common to all representations; do
those parts first. **/
/* CHECKSUM */
{
skel_t *checksum_skel = svn_fs_base__make_empty_list(pool);
svn_fs_base__prepend(svn_fs_base__mem_atom
(rep->checksum, APR_MD5_DIGESTSIZE, pool),
checksum_skel);
svn_fs_base__prepend(svn_fs_base__str_atom("md5", pool), checksum_skel);
svn_fs_base__prepend(checksum_skel, header_skel);
}
/* TXN */
if (rep->txn_id)
svn_fs_base__prepend(svn_fs_base__str_atom(rep->txn_id, pool),
header_skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), header_skel);
/** Do the kind-specific stuff. **/
if (rep->kind == rep_kind_fulltext)
{
/*** Fulltext Representation. ***/
/* STRING-KEY */
if ((! rep->contents.fulltext.string_key)
|| (! *rep->contents.fulltext.string_key))
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
else
svn_fs_base__prepend(svn_fs_base__str_atom
(rep->contents.fulltext.string_key, pool), skel);
/* "fulltext" */
svn_fs_base__prepend(svn_fs_base__str_atom("fulltext", pool),
header_skel);
/* header */
svn_fs_base__prepend(header_skel, skel);
}
else if (rep->kind == rep_kind_delta)
{
/*** Delta Representation. ***/
int i;
apr_array_header_t *chunks = rep->contents.delta.chunks;
/* Loop backwards through the windows, creating and prepending skels. */
for (i = chunks->nelts; i > 0; i--)
{
skel_t *window_skel = svn_fs_base__make_empty_list(pool);
skel_t *chunk_skel = svn_fs_base__make_empty_list(pool);
skel_t *diff_skel = svn_fs_base__make_empty_list(pool);
const char *size_str, *offset_str, *version_str;
rep_delta_chunk_t *chunk =
(((rep_delta_chunk_t **) chunks->elts)[i - 1]);
/* OFFSET */
offset_str = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT,
chunk->offset);
/* SIZE */
size_str = apr_psprintf(pool, "%" APR_SIZE_T_FMT, chunk->size);
/* VERSION */
version_str = apr_psprintf(pool, "%d", chunk->version);
/* DIFF */
if ((! chunk->string_key) || (! *chunk->string_key))
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool),
diff_skel);
else
svn_fs_base__prepend(svn_fs_base__str_atom(chunk->string_key,
pool), diff_skel);
svn_fs_base__prepend(svn_fs_base__str_atom(version_str, pool),
diff_skel);
svn_fs_base__prepend(svn_fs_base__str_atom("svndiff", pool),
diff_skel);
/* REP-KEY */
if ((! chunk->rep_key) || (! *(chunk->rep_key)))
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool),
window_skel);
else
svn_fs_base__prepend(svn_fs_base__str_atom(chunk->rep_key,
pool),
window_skel);
svn_fs_base__prepend(svn_fs_base__str_atom(size_str, pool),
window_skel);
svn_fs_base__prepend(diff_skel, window_skel);
/* window header. */
svn_fs_base__prepend(window_skel, chunk_skel);
svn_fs_base__prepend(svn_fs_base__str_atom(offset_str, pool),
chunk_skel);
/* Add this window item to the main skel. */
svn_fs_base__prepend(chunk_skel, skel);
}
/* "delta" */
svn_fs_base__prepend(svn_fs_base__str_atom("delta", pool),
header_skel);
/* header */
svn_fs_base__prepend(header_skel, skel);
}
else /* unknown kind */
abort();
/* Validate and return the skel. */
if (! is_valid_representation_skel(skel))
return skel_err("representation");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_node_revision_skel(skel_t **skel_p,
const node_revision_t *noderev,
apr_pool_t *pool)
{
skel_t *skel;
skel_t *header_skel;
/* Create the skel. */
skel = svn_fs_base__make_empty_list(pool);
header_skel = svn_fs_base__make_empty_list(pool);
/* PREDECESSOR-COUNT */
if (noderev->predecessor_count != -1)
{
const char *count_str = apr_psprintf(pool, "%d",
noderev->predecessor_count);
svn_fs_base__prepend(svn_fs_base__str_atom(count_str, pool),
header_skel);
}
/* PREDECESSOR-ID */
if (noderev->predecessor_id)
{
svn_string_t *id_str = svn_fs_base__id_unparse(noderev->predecessor_id,
pool);
svn_fs_base__prepend(svn_fs_base__mem_atom(id_str->data, id_str->len,
pool),
header_skel);
}
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), header_skel);
/* CREATED-PATH */
svn_fs_base__prepend(svn_fs_base__str_atom(noderev->created_path, pool),
header_skel);
/* KIND */
if (noderev->kind == svn_node_file)
svn_fs_base__prepend(svn_fs_base__str_atom("file", pool), header_skel);
else if (noderev->kind == svn_node_dir)
svn_fs_base__prepend(svn_fs_base__str_atom("dir", pool), header_skel);
else
abort();
/* ### do we really need to check *node->FOO_key ? if a key doesn't
### exist, then the field should be NULL ... */
/* EDIT-DATA-KEY (optional) */
if ((noderev->edit_key) && (*noderev->edit_key))
svn_fs_base__prepend(svn_fs_base__str_atom(noderev->edit_key, pool),
skel);
/* DATA-KEY */
if ((noderev->data_key) && (*noderev->data_key))
svn_fs_base__prepend(svn_fs_base__str_atom(noderev->data_key, pool),
skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* PROP-KEY */
if ((noderev->prop_key) && (*noderev->prop_key))
svn_fs_base__prepend(svn_fs_base__str_atom(noderev->prop_key, pool),
skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* HEADER */
svn_fs_base__prepend(header_skel, skel);
/* Validate and return the skel. */
if (! is_valid_node_revision_skel(skel))
return skel_err("node-revision");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_copy_skel(skel_t **skel_p,
const copy_t *copy,
apr_pool_t *pool)
{
skel_t *skel;
svn_string_t *tmp_str;
/* Create the skel. */
skel = svn_fs_base__make_empty_list(pool);
/* DST-NODE-ID */
tmp_str = svn_fs_base__id_unparse(copy->dst_noderev_id, pool);
svn_fs_base__prepend(svn_fs_base__mem_atom(tmp_str->data, tmp_str->len,
pool), skel);
/* SRC-TXN-ID */
if ((copy->src_txn_id) && (*copy->src_txn_id))
svn_fs_base__prepend(svn_fs_base__str_atom(copy->src_txn_id, pool),
skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* SRC-PATH */
if ((copy->src_path) && (*copy->src_path))
svn_fs_base__prepend(svn_fs_base__str_atom(copy->src_path, pool), skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* "copy" */
if (copy->kind == copy_kind_real)
svn_fs_base__prepend(svn_fs_base__str_atom("copy", pool), skel);
else
svn_fs_base__prepend(svn_fs_base__str_atom("soft-copy", pool), skel);
/* Validate and return the skel. */
if (! is_valid_copy_skel(skel))
return skel_err("copy");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_entries_skel(skel_t **skel_p,
apr_hash_t *entries,
apr_pool_t *pool)
{
skel_t *skel = svn_fs_base__make_empty_list(pool);
apr_hash_index_t *hi;
/* Create the skel. */
if (entries)
{
/* Loop over hash entries */
for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
{
const void *key;
void *val;
apr_ssize_t klen;
svn_fs_id_t *value;
svn_string_t *id_str;
skel_t *entry_skel = svn_fs_base__make_empty_list(pool);
apr_hash_this(hi, &key, &klen, &val);
value = val;
/* VALUE */
id_str = svn_fs_base__id_unparse(value, pool);
svn_fs_base__prepend(svn_fs_base__mem_atom(id_str->data,
id_str->len, pool),
entry_skel);
/* NAME */
svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool),
entry_skel);
/* Add entry to the entries skel. */
svn_fs_base__prepend(entry_skel, skel);
}
}
/* Return the skel. */
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_change_skel(skel_t **skel_p,
const change_t *change,
apr_pool_t *pool)
{
skel_t *skel;
svn_string_t *tmp_str;
svn_fs_path_change_kind_t kind;
/* Create the skel. */
skel = svn_fs_base__make_empty_list(pool);
/* PROP-MOD */
if (change->prop_mod)
svn_fs_base__prepend(svn_fs_base__str_atom("1", pool), skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* TEXT-MOD */
if (change->text_mod)
svn_fs_base__prepend(svn_fs_base__str_atom("1", pool), skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* KIND */
switch (change->kind)
{
case svn_fs_path_change_reset:
svn_fs_base__prepend(svn_fs_base__str_atom("reset", pool), skel);
break;
case svn_fs_path_change_add:
svn_fs_base__prepend(svn_fs_base__str_atom("add", pool), skel);
break;
case svn_fs_path_change_delete:
svn_fs_base__prepend(svn_fs_base__str_atom("delete", pool), skel);
break;
case svn_fs_path_change_replace:
svn_fs_base__prepend(svn_fs_base__str_atom("replace", pool), skel);
break;
case svn_fs_path_change_modify:
default:
svn_fs_base__prepend(svn_fs_base__str_atom("modify", pool), skel);
break;
}
/* NODE-REV-ID */
if (change->noderev_id)
{
tmp_str = svn_fs_base__id_unparse(change->noderev_id, pool);
svn_fs_base__prepend(svn_fs_base__mem_atom(tmp_str->data,
tmp_str->len, pool),
skel);
}
else
{
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
}
/* PATH */
svn_fs_base__prepend(svn_fs_base__str_atom(change->path, pool), skel);
/* "change" */
svn_fs_base__prepend(svn_fs_base__str_atom("change", pool), skel);
/* Validate and return the skel. */
if (! is_valid_change_skel(skel, &kind))
return skel_err("change");
if (kind != change->kind)
return skel_err("change");
*skel_p = skel;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__unparse_lock_skel(skel_t **skel_p,
const svn_lock_t *lock,
apr_pool_t *pool)
{
skel_t *skel;
/* Create the skel. */
skel = svn_fs_base__make_empty_list(pool);
/* EXP-DATE is optional. If not present, just use an empty atom. */
if (lock->expiration_date)
svn_fs_base__prepend
(svn_fs_base__str_atom
(svn_time_to_cstring(lock->expiration_date, pool), pool), skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* CREATION-DATE */
svn_fs_base__prepend
(svn_fs_base__str_atom
(svn_time_to_cstring(lock->creation_date, pool), pool), skel);
/* XML_P */
if (lock->is_dav_comment)
svn_fs_base__prepend(svn_fs_base__str_atom("1", pool), skel);
else
svn_fs_base__prepend(svn_fs_base__str_atom("0", pool), skel);
/* COMMENT */
if (lock->comment)
svn_fs_base__prepend(svn_fs_base__str_atom(lock->comment, pool), skel);
else
svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
/* OWNER */
svn_fs_base__prepend(svn_fs_base__str_atom(lock->owner, pool), skel);
/* LOCK-TOKEN */
svn_fs_base__prepend(svn_fs_base__str_atom(lock->token, pool), skel);
/* PATH */
svn_fs_base__prepend(svn_fs_base__str_atom(lock->path, pool), skel);
/* "lock" */
svn_fs_base__prepend(svn_fs_base__str_atom("lock", pool), skel);
/* Validate and return the skel. */
if (! is_valid_lock_skel(skel))
return skel_err("lock");
*skel_p = skel;
return SVN_NO_ERROR;
}
syntax highlighted by Code2HTML, v. 0.9.1