summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_fs_base/util/fs_skels.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_base/util/fs_skels.c')
-rw-r--r--subversion/libsvn_fs_base/util/fs_skels.c1515
1 files changed, 1515 insertions, 0 deletions
diff --git a/subversion/libsvn_fs_base/util/fs_skels.c b/subversion/libsvn_fs_base/util/fs_skels.c
new file mode 100644
index 0000000..f3466b9
--- /dev/null
+++ b/subversion/libsvn_fs_base/util/fs_skels.c
@@ -0,0 +1,1515 @@
+/* fs_skels.c --- conversion between fs native types and skeletons
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include <string.h>
+
+#include <apr_md5.h>
+#include <apr_sha1.h>
+
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_types.h"
+#include "svn_time.h"
+
+#include "private/svn_skel.h"
+#include "private/svn_dep_compat.h"
+#include "private/svn_subr_private.h"
+
+#include "svn_checksum.h"
+#include "fs_skels.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(svn_skel_t *skel)
+{
+ if (svn_skel__list_length(skel) != 2)
+ return FALSE;
+
+ if (svn_skel__matches_atom(skel->children, "md5")
+ && skel->children->next->is_atom)
+ return TRUE;
+
+ if (svn_skel__matches_atom(skel->children, "sha1")
+ && skel->children->next->is_atom)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static svn_boolean_t
+is_valid_revision_skel(svn_skel_t *skel)
+{
+ int len = svn_skel__list_length(skel);
+
+ if ((len == 2)
+ && svn_skel__matches_atom(skel->children, "revision")
+ && skel->children->next->is_atom)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static svn_boolean_t
+is_valid_transaction_skel(svn_skel_t *skel, transaction_kind_t *kind)
+{
+ int len = svn_skel__list_length(skel);
+
+ if (len != 5)
+ return FALSE;
+
+ /* Determine (and verify) the kind. */
+ if (svn_skel__matches_atom(skel->children, "transaction"))
+ *kind = transaction_kind_normal;
+ else if (svn_skel__matches_atom(skel->children, "committed"))
+ *kind = transaction_kind_committed;
+ else if (svn_skel__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(svn_skel_t *skel)
+{
+ int len;
+ svn_skel_t *window;
+ svn_skel_t *diff;
+
+ /* check the delta skel. */
+ if ((svn_skel__list_length(skel) != 2)
+ || (! skel->children->is_atom))
+ return FALSE;
+
+ /* check the window. */
+ window = skel->children->next;
+ len = svn_skel__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_skel__list_length(diff) == 3)
+ && (svn_skel__matches_atom(diff->children, "svndiff"))
+ && ((svn_skel__matches_atom(diff->children->next, "0"))
+ || (svn_skel__matches_atom(diff->children->next, "1")))
+ && (diff->children->next->next->is_atom))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static svn_boolean_t
+is_valid_representation_skel(svn_skel_t *skel)
+{
+ int len = svn_skel__list_length(skel);
+ svn_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 1 or 2 checksums (which is a list form). */
+ header = skel->children;
+ header_len = svn_skel__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 md5 checksum present */
+ && (header->children->is_atom)
+ && (header->children->next->is_atom)
+ && (is_valid_checksum_skel(header->children->next->next)))
+ || ((header_len == 4) /* 3 means md5 and sha1 checksums present */
+ && (header->children->is_atom)
+ && (header->children->next->is_atom)
+ && (is_valid_checksum_skel(header->children->next->next))
+ && (is_valid_checksum_skel(header->children->next->next->next)))))
+ return FALSE;
+
+ /* check for fulltext rep. */
+ if ((len == 2)
+ && (svn_skel__matches_atom(header->children, "fulltext")))
+ return TRUE;
+
+ /* check for delta rep. */
+ if ((len >= 2)
+ && (svn_skel__matches_atom(header->children, "delta")))
+ {
+ /* it's a delta rep. check the validity. */
+ svn_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(svn_skel_t *skel, svn_skel_t **kind_p)
+{
+ int len = svn_skel__list_length(skel);
+
+ if (len < 2)
+ return FALSE;
+
+ /* set the *KIND_P pointer. */
+ *kind_p = skel->children;
+
+ /* check for valid lengths. */
+ if (! ((len == 2) || (len == 3) || (len == 4) || (len == 6)))
+ return FALSE;
+
+ /* got mergeinfo stuff? */
+ if ((len > 4)
+ && (! (skel->children->next->next->next->next->is_atom
+ && skel->children->next->next->next->next->next->is_atom)))
+ return FALSE;
+
+ /* got predecessor count? */
+ if ((len > 3)
+ && (! skel->children->next->next->next->is_atom))
+ return FALSE;
+
+ /* got predecessor? */
+ if ((len > 2)
+ && (! skel->children->next->next->is_atom))
+ return FALSE;
+
+ /* got the basics? */
+ if (! (skel->children->is_atom
+ && skel->children->next->is_atom
+ && (skel->children->next->data[0] == '/')))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static svn_boolean_t
+is_valid_node_revision_skel(svn_skel_t *skel)
+{
+ int len = svn_skel__list_length(skel);
+ svn_skel_t *header = skel->children;
+ svn_skel_t *kind;
+
+ if (len < 1)
+ return FALSE;
+
+ if (! is_valid_node_revision_header_skel(header, &kind))
+ return FALSE;
+
+ if (svn_skel__matches_atom(kind, "dir"))
+ {
+ if (! ((len == 3)
+ && header->next->is_atom
+ && header->next->next->is_atom))
+ return FALSE;
+ }
+ else if (svn_skel__matches_atom(kind, "file"))
+ {
+ if (len < 3)
+ return FALSE;
+
+ if (! header->next->is_atom)
+ return FALSE;
+
+ /* As of SVN_FS_BASE__MIN_REP_SHARING_FORMAT version, the
+ DATA-KEY slot can be a 2-tuple. */
+ if (! header->next->next->is_atom)
+ {
+ if (! ((svn_skel__list_length(header->next->next) == 2)
+ && header->next->next->children->is_atom
+ && header->next->next->children->len
+ && header->next->next->children->next->is_atom
+ && header->next->next->children->next->len))
+ return FALSE;
+ }
+
+ if ((len > 3) && (! header->next->next->next->is_atom))
+ return FALSE;
+
+ if (len > 4)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static svn_boolean_t
+is_valid_copy_skel(svn_skel_t *skel)
+{
+ return ((svn_skel__list_length(skel) == 4)
+ && (svn_skel__matches_atom(skel->children, "copy")
+ || svn_skel__matches_atom(skel->children, "soft-copy"))
+ && skel->children->next->is_atom
+ && skel->children->next->next->is_atom
+ && skel->children->next->next->next->is_atom);
+}
+
+
+static svn_boolean_t
+is_valid_change_skel(svn_skel_t *skel, svn_fs_path_change_kind_t *kind)
+{
+ if ((svn_skel__list_length(skel) == 6)
+ && svn_skel__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)
+ {
+ svn_skel_t *kind_skel = skel->children->next->next->next;
+
+ /* check the kind (and return it) */
+ if (svn_skel__matches_atom(kind_skel, "reset"))
+ {
+ if (kind)
+ *kind = svn_fs_path_change_reset;
+ return TRUE;
+ }
+ if (svn_skel__matches_atom(kind_skel, "add"))
+ {
+ if (kind)
+ *kind = svn_fs_path_change_add;
+ return TRUE;
+ }
+ if (svn_skel__matches_atom(kind_skel, "delete"))
+ {
+ if (kind)
+ *kind = svn_fs_path_change_delete;
+ return TRUE;
+ }
+ if (svn_skel__matches_atom(kind_skel, "replace"))
+ {
+ if (kind)
+ *kind = svn_fs_path_change_replace;
+ return TRUE;
+ }
+ if (svn_skel__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(svn_skel_t *skel)
+{
+ if ((svn_skel__list_length(skel) == 8)
+ && svn_skel__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_revision_skel(revision_t **revision_p,
+ svn_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,
+ svn_skel_t *skel,
+ apr_pool_t *pool)
+{
+ transaction_t *transaction;
+ transaction_kind_t kind;
+ svn_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 =
+ SVN_STR_TO_REV(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_skel__parse_proplist(&(transaction->proplist),
+ proplist, pool));
+
+ /* COPIES */
+ if ((len = svn_skel__list_length(copies)))
+ {
+ const char *copy_id;
+ apr_array_header_t *txncopies;
+ svn_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);
+ APR_ARRAY_PUSH(txncopies, const char *) = 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,
+ svn_skel_t *skel,
+ apr_pool_t *pool)
+{
+ representation_t *rep;
+ svn_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_skel__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);
+
+ /* MD5 */
+ if (header_skel->children->next->next)
+ {
+ svn_skel_t *checksum_skel = header_skel->children->next->next;
+ rep->md5_checksum =
+ svn_checksum__from_digest_md5((const unsigned char *)
+ (checksum_skel->children->next->data),
+ pool);
+
+ /* SHA1 */
+ if (header_skel->children->next->next->next)
+ {
+ checksum_skel = header_skel->children->next->next->next;
+ rep->sha1_checksum =
+ svn_checksum__from_digest_sha1(
+ (const unsigned char *)(checksum_skel->children->next->data),
+ pool);
+ }
+ }
+
+ /* 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. */
+ svn_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_skel__list_length(skel) - 1,
+ sizeof(chunk));
+
+ /* Process the chunks. */
+ while (chunk_skel)
+ {
+ svn_skel_t *window_skel = chunk_skel->children->next;
+ svn_skel_t *diff_skel = window_skel->children;
+ apr_int64_t val;
+ apr_uint64_t uval;
+ const char *str;
+
+ /* Allocate a chunk and its window */
+ chunk = apr_palloc(pool, sizeof(*chunk));
+
+ /* Populate the window */
+ str = apr_pstrmemdup(pool, diff_skel->children->next->data,
+ diff_skel->children->next->len);
+ SVN_ERR(svn_cstring_strtoui64(&uval, str, 0, 255, 10));
+ chunk->version = (apr_byte_t)uval;
+
+ chunk->string_key
+ = apr_pstrmemdup(pool,
+ diff_skel->children->next->next->data,
+ diff_skel->children->next->next->len);
+
+ str = apr_pstrmemdup(pool, window_skel->children->next->data,
+ window_skel->children->next->len);
+ SVN_ERR(svn_cstring_strtoui64(&uval, str, 0, APR_SIZE_MAX, 10));
+ chunk->size = (apr_size_t)uval;
+
+ chunk->rep_key
+ = apr_pstrmemdup(pool,
+ window_skel->children->next->next->data,
+ window_skel->children->next->next->len);
+
+ str = apr_pstrmemdup(pool, chunk_skel->children->data,
+ chunk_skel->children->len);
+ SVN_ERR(svn_cstring_strtoi64(&val, str, 0, APR_INT64_MAX, 10));
+ chunk->offset = (svn_filesize_t)val;
+
+ /* Add this chunk to the array. */
+ APR_ARRAY_PUSH(chunks, rep_delta_chunk_t *) = 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,
+ svn_skel_t *skel,
+ apr_pool_t *pool)
+{
+ node_revision_t *noderev;
+ svn_skel_t *header_skel, *cur_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_skel__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)
+ {
+ cur_skel = header_skel->children->next->next;
+ if (cur_skel->len)
+ noderev->predecessor_id = svn_fs_base__id_parse(cur_skel->data,
+ cur_skel->len, pool);
+
+ /* PREDECESSOR-COUNT */
+ noderev->predecessor_count = -1;
+ if (cur_skel->next)
+ {
+ const char *str;
+
+ cur_skel = cur_skel->next;
+ if (cur_skel->len)
+ {
+ str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len);
+ SVN_ERR(svn_cstring_atoi(&noderev->predecessor_count, str));
+ }
+
+ /* HAS-MERGEINFO and MERGEINFO-COUNT */
+ if (cur_skel->next)
+ {
+ int val;
+
+ cur_skel = cur_skel->next;
+ str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len);
+ SVN_ERR(svn_cstring_atoi(&val, str));
+ noderev->has_mergeinfo = (val != 0);
+
+ str = apr_pstrmemdup(pool, cur_skel->next->data,
+ cur_skel->next->len);
+ SVN_ERR(svn_cstring_atoi64(&noderev->mergeinfo_count, str));
+ }
+ }
+ }
+
+ /* 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->is_atom)
+ {
+ /* This is a real data rep key. */
+ if (skel->children->next->next->len)
+ noderev->data_key = apr_pstrmemdup(pool,
+ skel->children->next->next->data,
+ skel->children->next->next->len);
+ noderev->data_key_uniquifier = NULL;
+ }
+ else
+ {
+ /* This is a 2-tuple with a data rep key and a uniquifier. */
+ noderev->data_key =
+ apr_pstrmemdup(pool,
+ skel->children->next->next->children->data,
+ skel->children->next->next->children->len);
+ noderev->data_key_uniquifier =
+ apr_pstrmemdup(pool,
+ skel->children->next->next->children->next->data,
+ skel->children->next->next->children->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,
+ svn_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_skel__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,
+ svn_skel_t *skel,
+ apr_pool_t *pool)
+{
+ apr_hash_t *entries = NULL;
+ int len = svn_skel__list_length(skel);
+ svn_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_skel__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,
+ svn_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,
+ svn_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_skel__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_revision_skel(svn_skel_t **skel_p,
+ const revision_t *revision,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel;
+
+ /* Create the skel. */
+ skel = svn_skel__make_empty_list(pool);
+
+ /* TXN_ID */
+ svn_skel__prepend(svn_skel__str_atom(revision->txn_id, pool), skel);
+
+ /* "revision" */
+ svn_skel__prepend(svn_skel__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(svn_skel_t **skel_p,
+ const transaction_t *transaction,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel;
+ svn_skel_t *proplist_skel, *copies_skel, *header_skel;
+ svn_string_t *id_str;
+ transaction_kind_t kind;
+
+ /* Create the skel. */
+ skel = svn_skel__make_empty_list(pool);
+
+ switch (transaction->kind)
+ {
+ case transaction_kind_committed:
+ header_skel = svn_skel__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_skel__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_skel__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_skel__make_empty_list(pool);
+ if (transaction->copies && transaction->copies->nelts)
+ {
+ int i;
+ for (i = transaction->copies->nelts - 1; i >= 0; i--)
+ {
+ svn_skel__prepend(svn_skel__str_atom(
+ APR_ARRAY_IDX(transaction->copies, i,
+ const char *),
+ pool),
+ copies_skel);
+ }
+ }
+ svn_skel__prepend(copies_skel, skel);
+
+ /* PROPLIST */
+ SVN_ERR(svn_skel__unparse_proplist(&proplist_skel,
+ transaction->proplist, pool));
+ svn_skel__prepend(proplist_skel, skel);
+
+ /* REVISION or BASE-ID */
+ if (transaction->kind == transaction_kind_committed)
+ {
+ /* Committed transactions have a revision number... */
+ svn_skel__prepend(svn_skel__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_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool),
+ skel);
+ }
+
+ /* ROOT-ID */
+ id_str = svn_fs_base__id_unparse(transaction->root_id, pool);
+ svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool), skel);
+
+ /* KIND (see above) */
+ svn_skel__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;
+}
+
+
+/* Construct a skel representing CHECKSUM, allocated in POOL, and prepend
+ * it onto the existing skel SKEL. */
+static svn_error_t *
+prepend_checksum(svn_skel_t *skel,
+ svn_checksum_t *checksum,
+ apr_pool_t *pool)
+{
+ svn_skel_t *checksum_skel = svn_skel__make_empty_list(pool);
+
+ switch (checksum->kind)
+ {
+ case svn_checksum_md5:
+ svn_skel__prepend(svn_skel__mem_atom(checksum->digest,
+ APR_MD5_DIGESTSIZE, pool),
+ checksum_skel);
+ svn_skel__prepend(svn_skel__str_atom("md5", pool), checksum_skel);
+ break;
+
+ case svn_checksum_sha1:
+ svn_skel__prepend(svn_skel__mem_atom(checksum->digest,
+ APR_SHA1_DIGESTSIZE, pool),
+ checksum_skel);
+ svn_skel__prepend(svn_skel__str_atom("sha1", pool), checksum_skel);
+ break;
+
+ default:
+ return skel_err("checksum");
+ }
+ svn_skel__prepend(checksum_skel, skel);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_fs_base__unparse_representation_skel(svn_skel_t **skel_p,
+ const representation_t *rep,
+ int format,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel = svn_skel__make_empty_list(pool);
+ svn_skel_t *header_skel = svn_skel__make_empty_list(pool);
+
+ /** Some parts of the header are common to all representations; do
+ those parts first. **/
+
+ /* SHA1 */
+ if ((format >= SVN_FS_BASE__MIN_REP_SHARING_FORMAT) && rep->sha1_checksum)
+ SVN_ERR(prepend_checksum(header_skel, rep->sha1_checksum, pool));
+
+ /* MD5 */
+ {
+ svn_checksum_t *md5_checksum = rep->md5_checksum;
+ if (! md5_checksum)
+ md5_checksum = svn_checksum_create(svn_checksum_md5, pool);
+ SVN_ERR(prepend_checksum(header_skel, md5_checksum, pool));
+ }
+
+ /* TXN */
+ if (rep->txn_id)
+ svn_skel__prepend(svn_skel__str_atom(rep->txn_id, pool), header_skel);
+ else
+ svn_skel__prepend(svn_skel__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_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+ else
+ svn_skel__prepend(svn_skel__str_atom(rep->contents.fulltext.string_key,
+ pool), skel);
+
+ /* "fulltext" */
+ svn_skel__prepend(svn_skel__str_atom("fulltext", pool), header_skel);
+
+ /* header */
+ svn_skel__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--)
+ {
+ svn_skel_t *window_skel = svn_skel__make_empty_list(pool);
+ svn_skel_t *chunk_skel = svn_skel__make_empty_list(pool);
+ svn_skel_t *diff_skel = svn_skel__make_empty_list(pool);
+ const char *size_str, *offset_str, *version_str;
+ rep_delta_chunk_t *chunk = APR_ARRAY_IDX(chunks, i - 1,
+ rep_delta_chunk_t *);
+
+ /* 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_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), diff_skel);
+ else
+ svn_skel__prepend(svn_skel__str_atom(chunk->string_key, pool),
+ diff_skel);
+ svn_skel__prepend(svn_skel__str_atom(version_str, pool), diff_skel);
+ svn_skel__prepend(svn_skel__str_atom("svndiff", pool), diff_skel);
+
+ /* REP-KEY */
+ if ((! chunk->rep_key) || (! *(chunk->rep_key)))
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool),
+ window_skel);
+ else
+ svn_skel__prepend(svn_skel__str_atom(chunk->rep_key, pool),
+ window_skel);
+ svn_skel__prepend(svn_skel__str_atom(size_str, pool), window_skel);
+ svn_skel__prepend(diff_skel, window_skel);
+
+ /* window header. */
+ svn_skel__prepend(window_skel, chunk_skel);
+ svn_skel__prepend(svn_skel__str_atom(offset_str, pool),
+ chunk_skel);
+
+ /* Add this window item to the main skel. */
+ svn_skel__prepend(chunk_skel, skel);
+ }
+
+ /* "delta" */
+ svn_skel__prepend(svn_skel__str_atom("delta", pool), header_skel);
+
+ /* header */
+ svn_skel__prepend(header_skel, skel);
+ }
+ else /* unknown kind */
+ SVN_ERR_MALFUNCTION();
+
+ /* 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(svn_skel_t **skel_p,
+ const node_revision_t *noderev,
+ int format,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel;
+ svn_skel_t *header_skel;
+ const char *num_str;
+
+ /* Create the skel. */
+ skel = svn_skel__make_empty_list(pool);
+ header_skel = svn_skel__make_empty_list(pool);
+
+ /* Store mergeinfo stuffs only if the schema level supports it. */
+ if (format >= SVN_FS_BASE__MIN_MERGEINFO_FORMAT)
+ {
+ /* MERGEINFO-COUNT */
+ num_str = apr_psprintf(pool, "%" APR_INT64_T_FMT,
+ noderev->mergeinfo_count);
+ svn_skel__prepend(svn_skel__str_atom(num_str, pool), header_skel);
+
+ /* HAS-MERGEINFO */
+ svn_skel__prepend(svn_skel__mem_atom(noderev->has_mergeinfo ? "1" : "0",
+ 1, pool), header_skel);
+
+ /* PREDECESSOR-COUNT padding (only if we *don't* have a valid
+ value; if we do, we'll pick that up below) */
+ if (noderev->predecessor_count == -1)
+ {
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
+ }
+ }
+
+ /* PREDECESSOR-COUNT */
+ if (noderev->predecessor_count != -1)
+ {
+ const char *count_str = apr_psprintf(pool, "%d",
+ noderev->predecessor_count);
+ svn_skel__prepend(svn_skel__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_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool),
+ header_skel);
+ }
+ else
+ {
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
+ }
+
+ /* CREATED-PATH */
+ svn_skel__prepend(svn_skel__str_atom(noderev->created_path, pool),
+ header_skel);
+
+ /* KIND */
+ if (noderev->kind == svn_node_file)
+ svn_skel__prepend(svn_skel__str_atom("file", pool), header_skel);
+ else if (noderev->kind == svn_node_dir)
+ svn_skel__prepend(svn_skel__str_atom("dir", pool), header_skel);
+ else
+ SVN_ERR_MALFUNCTION();
+
+ /* ### 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_skel__prepend(svn_skel__str_atom(noderev->edit_key, pool), skel);
+
+ /* DATA-KEY | (DATA-KEY DATA-KEY-UNIQID) */
+ if ((noderev->data_key_uniquifier) && (*noderev->data_key_uniquifier))
+ {
+ /* Build a 2-tuple with a rep key and uniquifier. */
+ svn_skel_t *data_key_skel = svn_skel__make_empty_list(pool);
+
+ /* DATA-KEY-UNIQID */
+ svn_skel__prepend(svn_skel__str_atom(noderev->data_key_uniquifier,
+ pool),
+ data_key_skel);
+
+ /* DATA-KEY */
+ if ((noderev->data_key) && (*noderev->data_key))
+ svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool),
+ data_key_skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), data_key_skel);
+
+ /* Add our 2-tuple to the main skel. */
+ svn_skel__prepend(data_key_skel, skel);
+ }
+ else
+ {
+ /* Just store the rep key (or empty placeholder) in the main skel. */
+ if ((noderev->data_key) && (*noderev->data_key))
+ svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+ }
+
+ /* PROP-KEY */
+ if ((noderev->prop_key) && (*noderev->prop_key))
+ svn_skel__prepend(svn_skel__str_atom(noderev->prop_key, pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* HEADER */
+ svn_skel__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(svn_skel_t **skel_p,
+ const copy_t *copy,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel;
+ svn_string_t *tmp_str;
+
+ /* Create the skel. */
+ skel = svn_skel__make_empty_list(pool);
+
+ /* DST-NODE-ID */
+ tmp_str = svn_fs_base__id_unparse(copy->dst_noderev_id, pool);
+ svn_skel__prepend(svn_skel__mem_atom(tmp_str->data, tmp_str->len, pool),
+ skel);
+
+ /* SRC-TXN-ID */
+ if ((copy->src_txn_id) && (*copy->src_txn_id))
+ svn_skel__prepend(svn_skel__str_atom(copy->src_txn_id, pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* SRC-PATH */
+ if ((copy->src_path) && (*copy->src_path))
+ svn_skel__prepend(svn_skel__str_atom(copy->src_path, pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* "copy" */
+ if (copy->kind == copy_kind_real)
+ svn_skel__prepend(svn_skel__str_atom("copy", pool), skel);
+ else
+ svn_skel__prepend(svn_skel__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(svn_skel_t **skel_p,
+ apr_hash_t *entries,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel = svn_skel__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;
+ svn_skel_t *entry_skel = svn_skel__make_empty_list(pool);
+
+ apr_hash_this(hi, &key, &klen, &val);
+ value = val;
+
+ /* VALUE */
+ id_str = svn_fs_base__id_unparse(value, pool);
+ svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len,
+ pool),
+ entry_skel);
+
+ /* NAME */
+ svn_skel__prepend(svn_skel__mem_atom(key, klen, pool), entry_skel);
+
+ /* Add entry to the entries skel. */
+ svn_skel__prepend(entry_skel, skel);
+ }
+ }
+
+ /* Return the skel. */
+ *skel_p = skel;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_fs_base__unparse_change_skel(svn_skel_t **skel_p,
+ const change_t *change,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel;
+ svn_string_t *tmp_str;
+ svn_fs_path_change_kind_t kind;
+
+ /* Create the skel. */
+ skel = svn_skel__make_empty_list(pool);
+
+ /* PROP-MOD */
+ if (change->prop_mod)
+ svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* TEXT-MOD */
+ if (change->text_mod)
+ svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* KIND */
+ switch (change->kind)
+ {
+ case svn_fs_path_change_reset:
+ svn_skel__prepend(svn_skel__str_atom("reset", pool), skel);
+ break;
+ case svn_fs_path_change_add:
+ svn_skel__prepend(svn_skel__str_atom("add", pool), skel);
+ break;
+ case svn_fs_path_change_delete:
+ svn_skel__prepend(svn_skel__str_atom("delete", pool), skel);
+ break;
+ case svn_fs_path_change_replace:
+ svn_skel__prepend(svn_skel__str_atom("replace", pool), skel);
+ break;
+ case svn_fs_path_change_modify:
+ default:
+ svn_skel__prepend(svn_skel__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_skel__prepend(svn_skel__mem_atom(tmp_str->data, tmp_str->len, pool),
+ skel);
+ }
+ else
+ {
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+ }
+
+ /* PATH */
+ svn_skel__prepend(svn_skel__str_atom(change->path, pool), skel);
+
+ /* "change" */
+ svn_skel__prepend(svn_skel__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(svn_skel_t **skel_p,
+ const svn_lock_t *lock,
+ apr_pool_t *pool)
+{
+ svn_skel_t *skel;
+
+ /* Create the skel. */
+ skel = svn_skel__make_empty_list(pool);
+
+ /* EXP-DATE is optional. If not present, just use an empty atom. */
+ if (lock->expiration_date)
+ svn_skel__prepend(svn_skel__str_atom(
+ svn_time_to_cstring(lock->expiration_date, pool),
+ pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* CREATION-DATE */
+ svn_skel__prepend(svn_skel__str_atom(
+ svn_time_to_cstring(lock->creation_date, pool),
+ pool), skel);
+
+ /* XML_P */
+ if (lock->is_dav_comment)
+ svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
+ else
+ svn_skel__prepend(svn_skel__str_atom("0", pool), skel);
+
+ /* COMMENT */
+ if (lock->comment)
+ svn_skel__prepend(svn_skel__str_atom(lock->comment, pool), skel);
+ else
+ svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
+
+ /* OWNER */
+ svn_skel__prepend(svn_skel__str_atom(lock->owner, pool), skel);
+
+ /* LOCK-TOKEN */
+ svn_skel__prepend(svn_skel__str_atom(lock->token, pool), skel);
+
+ /* PATH */
+ svn_skel__prepend(svn_skel__str_atom(lock->path, pool), skel);
+
+ /* "lock" */
+ svn_skel__prepend(svn_skel__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;
+}
OpenPOWER on IntegriCloud