1 /* id.c : operations on node-revision IDs
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
20 * ====================================================================
27 #include "../libsvn_fs/fs-loader.h"
28 #include "private/svn_temp_serializer.h"
29 #include "private/svn_string_private.h"
32 typedef struct id_private_t {
41 /* Accessing ID Pieces. */
44 svn_fs_fs__id_node_id(const svn_fs_id_t *id)
46 id_private_t *pvt = id->fsap_data;
53 svn_fs_fs__id_copy_id(const svn_fs_id_t *id)
55 id_private_t *pvt = id->fsap_data;
62 svn_fs_fs__id_txn_id(const svn_fs_id_t *id)
64 id_private_t *pvt = id->fsap_data;
71 svn_fs_fs__id_rev(const svn_fs_id_t *id)
73 id_private_t *pvt = id->fsap_data;
80 svn_fs_fs__id_offset(const svn_fs_id_t *id)
82 id_private_t *pvt = id->fsap_data;
89 svn_fs_fs__id_unparse(const svn_fs_id_t *id,
92 id_private_t *pvt = id->fsap_data;
96 char rev_string[SVN_INT64_BUFFER_SIZE];
97 char offset_string[SVN_INT64_BUFFER_SIZE];
99 svn__i64toa(rev_string, pvt->rev);
100 svn__i64toa(offset_string, pvt->offset);
101 return svn_string_createf(pool, "%s.%s.r%s/%s",
102 pvt->node_id, pvt->copy_id,
103 rev_string, offset_string);
107 return svn_string_createf(pool, "%s.%s.t%s",
108 pvt->node_id, pvt->copy_id,
114 /*** Comparing node IDs ***/
117 svn_fs_fs__id_eq(const svn_fs_id_t *a,
118 const svn_fs_id_t *b)
120 id_private_t *pvta = a->fsap_data, *pvtb = b->fsap_data;
124 if (strcmp(pvta->node_id, pvtb->node_id) != 0)
126 if (strcmp(pvta->copy_id, pvtb->copy_id) != 0)
128 if ((pvta->txn_id == NULL) != (pvtb->txn_id == NULL))
130 if (pvta->txn_id && pvtb->txn_id && strcmp(pvta->txn_id, pvtb->txn_id) != 0)
132 if (pvta->rev != pvtb->rev)
134 if (pvta->offset != pvtb->offset)
141 svn_fs_fs__id_check_related(const svn_fs_id_t *a,
142 const svn_fs_id_t *b)
144 id_private_t *pvta = a->fsap_data, *pvtb = b->fsap_data;
148 /* If both node_ids start with _ and they have differing transaction
149 IDs, then it is impossible for them to be related. */
150 if (pvta->node_id[0] == '_')
152 if (pvta->txn_id && pvtb->txn_id &&
153 (strcmp(pvta->txn_id, pvtb->txn_id) != 0))
157 return (strcmp(pvta->node_id, pvtb->node_id) == 0);
162 svn_fs_fs__id_compare(const svn_fs_id_t *a,
163 const svn_fs_id_t *b)
165 if (svn_fs_fs__id_eq(a, b))
167 return (svn_fs_fs__id_check_related(a, b) ? 1 : -1);
174 static id_vtable_t id_vtable = {
175 svn_fs_fs__id_unparse,
176 svn_fs_fs__id_compare
181 svn_fs_fs__id_txn_create(const char *node_id,
186 svn_fs_id_t *id = apr_palloc(pool, sizeof(*id));
187 id_private_t *pvt = apr_palloc(pool, sizeof(*pvt));
189 pvt->node_id = apr_pstrdup(pool, node_id);
190 pvt->copy_id = apr_pstrdup(pool, copy_id);
191 pvt->txn_id = apr_pstrdup(pool, txn_id);
192 pvt->rev = SVN_INVALID_REVNUM;
195 id->vtable = &id_vtable;
202 svn_fs_fs__id_rev_create(const char *node_id,
208 svn_fs_id_t *id = apr_palloc(pool, sizeof(*id));
209 id_private_t *pvt = apr_palloc(pool, sizeof(*pvt));
211 pvt->node_id = apr_pstrdup(pool, node_id);
212 pvt->copy_id = apr_pstrdup(pool, copy_id);
215 pvt->offset = offset;
217 id->vtable = &id_vtable;
224 svn_fs_fs__id_copy(const svn_fs_id_t *id, apr_pool_t *pool)
226 svn_fs_id_t *new_id = apr_palloc(pool, sizeof(*new_id));
227 id_private_t *new_pvt = apr_palloc(pool, sizeof(*new_pvt));
228 id_private_t *pvt = id->fsap_data;
230 new_pvt->node_id = apr_pstrdup(pool, pvt->node_id);
231 new_pvt->copy_id = apr_pstrdup(pool, pvt->copy_id);
232 new_pvt->txn_id = pvt->txn_id ? apr_pstrdup(pool, pvt->txn_id) : NULL;
233 new_pvt->rev = pvt->rev;
234 new_pvt->offset = pvt->offset;
236 new_id->vtable = &id_vtable;
237 new_id->fsap_data = new_pvt;
243 svn_fs_fs__id_parse(const char *data,
249 char *data_copy, *str;
251 /* Dup the ID data into POOL. Our returned ID will have references
253 data_copy = apr_pstrmemdup(pool, data, len);
255 /* Alloc a new svn_fs_id_t structure. */
256 id = apr_palloc(pool, sizeof(*id));
257 pvt = apr_palloc(pool, sizeof(*pvt));
258 id->vtable = &id_vtable;
261 /* Now, we basically just need to "split" this data on `.'
262 characters. We will use svn_cstring_tokenize, which will put
263 terminators where each of the '.'s used to be. Then our new
264 id field will reference string locations inside our duplicate
268 str = svn_cstring_tokenize(".", &data_copy);
274 str = svn_cstring_tokenize(".", &data_copy);
280 str = svn_cstring_tokenize(".", &data_copy);
289 /* This is a revision type ID */
293 str = svn_cstring_tokenize("/", &data_copy);
296 pvt->rev = SVN_STR_TO_REV(str);
298 str = svn_cstring_tokenize("/", &data_copy);
301 err = svn_cstring_atoi64(&val, str);
304 svn_error_clear(err);
307 pvt->offset = (apr_off_t)val;
309 else if (str[0] == 't')
311 /* This is a transaction type ID */
312 pvt->txn_id = str + 1;
313 pvt->rev = SVN_INVALID_REVNUM;
322 /* (de-)serialization support */
324 /* Serialization of the PVT sub-structure within the CONTEXT.
327 serialize_id_private(svn_temp_serializer__context_t *context,
328 const id_private_t * const *pvt)
330 const id_private_t *private = *pvt;
332 /* serialize the pvt data struct itself */
333 svn_temp_serializer__push(context,
334 (const void * const *)pvt,
337 /* append the referenced strings */
338 svn_temp_serializer__add_string(context, &private->node_id);
339 svn_temp_serializer__add_string(context, &private->copy_id);
340 svn_temp_serializer__add_string(context, &private->txn_id);
342 /* return to caller's nesting level */
343 svn_temp_serializer__pop(context);
346 /* Serialize an ID within the serialization CONTEXT.
349 svn_fs_fs__id_serialize(svn_temp_serializer__context_t *context,
350 const struct svn_fs_id_t * const *id)
352 /* nothing to do for NULL ids */
356 /* serialize the id data struct itself */
357 svn_temp_serializer__push(context,
358 (const void * const *)id,
361 /* serialize the id_private_t data sub-struct */
362 serialize_id_private(context,
363 (const id_private_t * const *)&(*id)->fsap_data);
365 /* return to caller's nesting level */
366 svn_temp_serializer__pop(context);
369 /* Deserialization of the PVT sub-structure in BUFFER.
372 deserialize_id_private(void *buffer, id_private_t **pvt)
374 /* fixup the reference to the only sub-structure */
375 id_private_t *private;
376 svn_temp_deserializer__resolve(buffer, (void**)pvt);
378 /* fixup the sub-structure itself */
380 svn_temp_deserializer__resolve(private, (void**)&private->node_id);
381 svn_temp_deserializer__resolve(private, (void**)&private->copy_id);
382 svn_temp_deserializer__resolve(private, (void**)&private->txn_id);
385 /* Deserialize an ID inside the BUFFER.
388 svn_fs_fs__id_deserialize(void *buffer, svn_fs_id_t **id)
390 /* The id maybe all what is in the whole buffer.
391 * Don't try to fixup the pointer in that case*/
393 svn_temp_deserializer__resolve(buffer, (void**)id);
395 /* no id, no sub-structure fixup necessary */
399 /* the stored vtable is bogus at best -> set the right one */
400 (*id)->vtable = &id_vtable;
402 /* handle sub-structures */
403 deserialize_id_private(*id, (id_private_t **)&(*id)->fsap_data);