summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_fs_fs/id.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_fs/id.c')
-rw-r--r--subversion/libsvn_fs_fs/id.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/subversion/libsvn_fs_fs/id.c b/subversion/libsvn_fs_fs/id.c
new file mode 100644
index 0000000..1317829
--- /dev/null
+++ b/subversion/libsvn_fs_fs/id.c
@@ -0,0 +1,405 @@
+/* id.c : operations on node-revision IDs
+ *
+ * ====================================================================
+ * 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 <stdlib.h>
+
+#include "id.h"
+#include "../libsvn_fs/fs-loader.h"
+#include "private/svn_temp_serializer.h"
+#include "private/svn_string_private.h"
+
+
+typedef struct id_private_t {
+ const char *node_id;
+ const char *copy_id;
+ const char *txn_id;
+ svn_revnum_t rev;
+ apr_off_t offset;
+} id_private_t;
+
+
+/* Accessing ID Pieces. */
+
+const char *
+svn_fs_fs__id_node_id(const svn_fs_id_t *id)
+{
+ id_private_t *pvt = id->fsap_data;
+
+ return pvt->node_id;
+}
+
+
+const char *
+svn_fs_fs__id_copy_id(const svn_fs_id_t *id)
+{
+ id_private_t *pvt = id->fsap_data;
+
+ return pvt->copy_id;
+}
+
+
+const char *
+svn_fs_fs__id_txn_id(const svn_fs_id_t *id)
+{
+ id_private_t *pvt = id->fsap_data;
+
+ return pvt->txn_id;
+}
+
+
+svn_revnum_t
+svn_fs_fs__id_rev(const svn_fs_id_t *id)
+{
+ id_private_t *pvt = id->fsap_data;
+
+ return pvt->rev;
+}
+
+
+apr_off_t
+svn_fs_fs__id_offset(const svn_fs_id_t *id)
+{
+ id_private_t *pvt = id->fsap_data;
+
+ return pvt->offset;
+}
+
+
+svn_string_t *
+svn_fs_fs__id_unparse(const svn_fs_id_t *id,
+ apr_pool_t *pool)
+{
+ id_private_t *pvt = id->fsap_data;
+
+ if ((! pvt->txn_id))
+ {
+ char rev_string[SVN_INT64_BUFFER_SIZE];
+ char offset_string[SVN_INT64_BUFFER_SIZE];
+
+ svn__i64toa(rev_string, pvt->rev);
+ svn__i64toa(offset_string, pvt->offset);
+ return svn_string_createf(pool, "%s.%s.r%s/%s",
+ pvt->node_id, pvt->copy_id,
+ rev_string, offset_string);
+ }
+ else
+ {
+ return svn_string_createf(pool, "%s.%s.t%s",
+ pvt->node_id, pvt->copy_id,
+ pvt->txn_id);
+ }
+}
+
+
+/*** Comparing node IDs ***/
+
+svn_boolean_t
+svn_fs_fs__id_eq(const svn_fs_id_t *a,
+ const svn_fs_id_t *b)
+{
+ id_private_t *pvta = a->fsap_data, *pvtb = b->fsap_data;
+
+ if (a == b)
+ return TRUE;
+ if (strcmp(pvta->node_id, pvtb->node_id) != 0)
+ return FALSE;
+ if (strcmp(pvta->copy_id, pvtb->copy_id) != 0)
+ return FALSE;
+ if ((pvta->txn_id == NULL) != (pvtb->txn_id == NULL))
+ return FALSE;
+ if (pvta->txn_id && pvtb->txn_id && strcmp(pvta->txn_id, pvtb->txn_id) != 0)
+ return FALSE;
+ if (pvta->rev != pvtb->rev)
+ return FALSE;
+ if (pvta->offset != pvtb->offset)
+ return FALSE;
+ return TRUE;
+}
+
+
+svn_boolean_t
+svn_fs_fs__id_check_related(const svn_fs_id_t *a,
+ const svn_fs_id_t *b)
+{
+ id_private_t *pvta = a->fsap_data, *pvtb = b->fsap_data;
+
+ if (a == b)
+ return TRUE;
+ /* If both node_ids start with _ and they have differing transaction
+ IDs, then it is impossible for them to be related. */
+ if (pvta->node_id[0] == '_')
+ {
+ if (pvta->txn_id && pvtb->txn_id &&
+ (strcmp(pvta->txn_id, pvtb->txn_id) != 0))
+ return FALSE;
+ }
+
+ return (strcmp(pvta->node_id, pvtb->node_id) == 0);
+}
+
+
+int
+svn_fs_fs__id_compare(const svn_fs_id_t *a,
+ const svn_fs_id_t *b)
+{
+ if (svn_fs_fs__id_eq(a, b))
+ return 0;
+ return (svn_fs_fs__id_check_related(a, b) ? 1 : -1);
+}
+
+
+
+/* Creating ID's. */
+
+static id_vtable_t id_vtable = {
+ svn_fs_fs__id_unparse,
+ svn_fs_fs__id_compare
+};
+
+
+svn_fs_id_t *
+svn_fs_fs__id_txn_create(const char *node_id,
+ const char *copy_id,
+ const char *txn_id,
+ apr_pool_t *pool)
+{
+ svn_fs_id_t *id = apr_palloc(pool, sizeof(*id));
+ id_private_t *pvt = apr_palloc(pool, sizeof(*pvt));
+
+ pvt->node_id = apr_pstrdup(pool, node_id);
+ pvt->copy_id = apr_pstrdup(pool, copy_id);
+ pvt->txn_id = apr_pstrdup(pool, txn_id);
+ pvt->rev = SVN_INVALID_REVNUM;
+ pvt->offset = -1;
+
+ id->vtable = &id_vtable;
+ id->fsap_data = pvt;
+ return id;
+}
+
+
+svn_fs_id_t *
+svn_fs_fs__id_rev_create(const char *node_id,
+ const char *copy_id,
+ svn_revnum_t rev,
+ apr_off_t offset,
+ apr_pool_t *pool)
+{
+ svn_fs_id_t *id = apr_palloc(pool, sizeof(*id));
+ id_private_t *pvt = apr_palloc(pool, sizeof(*pvt));
+
+ pvt->node_id = apr_pstrdup(pool, node_id);
+ pvt->copy_id = apr_pstrdup(pool, copy_id);
+ pvt->txn_id = NULL;
+ pvt->rev = rev;
+ pvt->offset = offset;
+
+ id->vtable = &id_vtable;
+ id->fsap_data = pvt;
+ return id;
+}
+
+
+svn_fs_id_t *
+svn_fs_fs__id_copy(const svn_fs_id_t *id, apr_pool_t *pool)
+{
+ svn_fs_id_t *new_id = apr_palloc(pool, sizeof(*new_id));
+ id_private_t *new_pvt = apr_palloc(pool, sizeof(*new_pvt));
+ id_private_t *pvt = id->fsap_data;
+
+ new_pvt->node_id = apr_pstrdup(pool, pvt->node_id);
+ new_pvt->copy_id = apr_pstrdup(pool, pvt->copy_id);
+ new_pvt->txn_id = pvt->txn_id ? apr_pstrdup(pool, pvt->txn_id) : NULL;
+ new_pvt->rev = pvt->rev;
+ new_pvt->offset = pvt->offset;
+
+ new_id->vtable = &id_vtable;
+ new_id->fsap_data = new_pvt;
+ return new_id;
+}
+
+
+svn_fs_id_t *
+svn_fs_fs__id_parse(const char *data,
+ apr_size_t len,
+ apr_pool_t *pool)
+{
+ svn_fs_id_t *id;
+ id_private_t *pvt;
+ char *data_copy, *str;
+
+ /* Dup the ID data into POOL. Our returned ID will have references
+ into this memory. */
+ data_copy = apr_pstrmemdup(pool, data, len);
+
+ /* Alloc a new svn_fs_id_t structure. */
+ id = apr_palloc(pool, sizeof(*id));
+ pvt = apr_palloc(pool, sizeof(*pvt));
+ id->vtable = &id_vtable;
+ id->fsap_data = pvt;
+
+ /* Now, we basically just need to "split" this data on `.'
+ characters. We will use svn_cstring_tokenize, which will put
+ terminators where each of the '.'s used to be. Then our new
+ id field will reference string locations inside our duplicate
+ string.*/
+
+ /* Node Id */
+ str = svn_cstring_tokenize(".", &data_copy);
+ if (str == NULL)
+ return NULL;
+ pvt->node_id = str;
+
+ /* Copy Id */
+ str = svn_cstring_tokenize(".", &data_copy);
+ if (str == NULL)
+ return NULL;
+ pvt->copy_id = str;
+
+ /* Txn/Rev Id */
+ str = svn_cstring_tokenize(".", &data_copy);
+ if (str == NULL)
+ return NULL;
+
+ if (str[0] == 'r')
+ {
+ apr_int64_t val;
+ svn_error_t *err;
+
+ /* This is a revision type ID */
+ pvt->txn_id = NULL;
+
+ data_copy = str + 1;
+ str = svn_cstring_tokenize("/", &data_copy);
+ if (str == NULL)
+ return NULL;
+ pvt->rev = SVN_STR_TO_REV(str);
+
+ str = svn_cstring_tokenize("/", &data_copy);
+ if (str == NULL)
+ return NULL;
+ err = svn_cstring_atoi64(&val, str);
+ if (err)
+ {
+ svn_error_clear(err);
+ return NULL;
+ }
+ pvt->offset = (apr_off_t)val;
+ }
+ else if (str[0] == 't')
+ {
+ /* This is a transaction type ID */
+ pvt->txn_id = str + 1;
+ pvt->rev = SVN_INVALID_REVNUM;
+ pvt->offset = -1;
+ }
+ else
+ return NULL;
+
+ return id;
+}
+
+/* (de-)serialization support */
+
+/* Serialization of the PVT sub-structure within the CONTEXT.
+ */
+static void
+serialize_id_private(svn_temp_serializer__context_t *context,
+ const id_private_t * const *pvt)
+{
+ const id_private_t *private = *pvt;
+
+ /* serialize the pvt data struct itself */
+ svn_temp_serializer__push(context,
+ (const void * const *)pvt,
+ sizeof(*private));
+
+ /* append the referenced strings */
+ svn_temp_serializer__add_string(context, &private->node_id);
+ svn_temp_serializer__add_string(context, &private->copy_id);
+ svn_temp_serializer__add_string(context, &private->txn_id);
+
+ /* return to caller's nesting level */
+ svn_temp_serializer__pop(context);
+}
+
+/* Serialize an ID within the serialization CONTEXT.
+ */
+void
+svn_fs_fs__id_serialize(svn_temp_serializer__context_t *context,
+ const struct svn_fs_id_t * const *id)
+{
+ /* nothing to do for NULL ids */
+ if (*id == NULL)
+ return;
+
+ /* serialize the id data struct itself */
+ svn_temp_serializer__push(context,
+ (const void * const *)id,
+ sizeof(**id));
+
+ /* serialize the id_private_t data sub-struct */
+ serialize_id_private(context,
+ (const id_private_t * const *)&(*id)->fsap_data);
+
+ /* return to caller's nesting level */
+ svn_temp_serializer__pop(context);
+}
+
+/* Deserialization of the PVT sub-structure in BUFFER.
+ */
+static void
+deserialize_id_private(void *buffer, id_private_t **pvt)
+{
+ /* fixup the reference to the only sub-structure */
+ id_private_t *private;
+ svn_temp_deserializer__resolve(buffer, (void**)pvt);
+
+ /* fixup the sub-structure itself */
+ private = *pvt;
+ svn_temp_deserializer__resolve(private, (void**)&private->node_id);
+ svn_temp_deserializer__resolve(private, (void**)&private->copy_id);
+ svn_temp_deserializer__resolve(private, (void**)&private->txn_id);
+}
+
+/* Deserialize an ID inside the BUFFER.
+ */
+void
+svn_fs_fs__id_deserialize(void *buffer, svn_fs_id_t **id)
+{
+ /* The id maybe all what is in the whole buffer.
+ * Don't try to fixup the pointer in that case*/
+ if (*id != buffer)
+ svn_temp_deserializer__resolve(buffer, (void**)id);
+
+ /* no id, no sub-structure fixup necessary */
+ if (*id == NULL)
+ return;
+
+ /* the stored vtable is bogus at best -> set the right one */
+ (*id)->vtable = &id_vtable;
+
+ /* handle sub-structures */
+ deserialize_id_private(*id, (id_private_t **)&(*id)->fsap_data);
+}
+
OpenPOWER on IntegriCloud