1251881Speter/* id.c : operations on node-revision IDs
2251881Speter *
3251881Speter * ====================================================================
4251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
5251881Speter *    or more contributor license agreements.  See the NOTICE file
6251881Speter *    distributed with this work for additional information
7251881Speter *    regarding copyright ownership.  The ASF licenses this file
8251881Speter *    to you under the Apache License, Version 2.0 (the
9251881Speter *    "License"); you may not use this file except in compliance
10251881Speter *    with the License.  You may obtain a copy of the License at
11251881Speter *
12251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
13251881Speter *
14251881Speter *    Unless required by applicable law or agreed to in writing,
15251881Speter *    software distributed under the License is distributed on an
16251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17251881Speter *    KIND, either express or implied.  See the License for the
18251881Speter *    specific language governing permissions and limitations
19251881Speter *    under the License.
20251881Speter * ====================================================================
21251881Speter */
22251881Speter
23251881Speter#include <string.h>
24251881Speter#include <stdlib.h>
25251881Speter
26251881Speter#include "id.h"
27251881Speter#include "../libsvn_fs/fs-loader.h"
28251881Speter#include "private/svn_temp_serializer.h"
29251881Speter#include "private/svn_string_private.h"
30251881Speter
31251881Speter
32251881Spetertypedef struct id_private_t {
33251881Speter  const char *node_id;
34251881Speter  const char *copy_id;
35251881Speter  const char *txn_id;
36251881Speter  svn_revnum_t rev;
37251881Speter  apr_off_t offset;
38251881Speter} id_private_t;
39251881Speter
40251881Speter
41251881Speter/* Accessing ID Pieces.  */
42251881Speter
43251881Speterconst char *
44251881Spetersvn_fs_fs__id_node_id(const svn_fs_id_t *id)
45251881Speter{
46251881Speter  id_private_t *pvt = id->fsap_data;
47251881Speter
48251881Speter  return pvt->node_id;
49251881Speter}
50251881Speter
51251881Speter
52251881Speterconst char *
53251881Spetersvn_fs_fs__id_copy_id(const svn_fs_id_t *id)
54251881Speter{
55251881Speter  id_private_t *pvt = id->fsap_data;
56251881Speter
57251881Speter  return pvt->copy_id;
58251881Speter}
59251881Speter
60251881Speter
61251881Speterconst char *
62251881Spetersvn_fs_fs__id_txn_id(const svn_fs_id_t *id)
63251881Speter{
64251881Speter  id_private_t *pvt = id->fsap_data;
65251881Speter
66251881Speter  return pvt->txn_id;
67251881Speter}
68251881Speter
69251881Speter
70251881Spetersvn_revnum_t
71251881Spetersvn_fs_fs__id_rev(const svn_fs_id_t *id)
72251881Speter{
73251881Speter  id_private_t *pvt = id->fsap_data;
74251881Speter
75251881Speter  return pvt->rev;
76251881Speter}
77251881Speter
78251881Speter
79251881Speterapr_off_t
80251881Spetersvn_fs_fs__id_offset(const svn_fs_id_t *id)
81251881Speter{
82251881Speter  id_private_t *pvt = id->fsap_data;
83251881Speter
84251881Speter  return pvt->offset;
85251881Speter}
86251881Speter
87251881Speter
88251881Spetersvn_string_t *
89251881Spetersvn_fs_fs__id_unparse(const svn_fs_id_t *id,
90251881Speter                      apr_pool_t *pool)
91251881Speter{
92251881Speter  id_private_t *pvt = id->fsap_data;
93251881Speter
94251881Speter  if ((! pvt->txn_id))
95251881Speter    {
96251881Speter      char rev_string[SVN_INT64_BUFFER_SIZE];
97251881Speter      char offset_string[SVN_INT64_BUFFER_SIZE];
98251881Speter
99251881Speter      svn__i64toa(rev_string, pvt->rev);
100251881Speter      svn__i64toa(offset_string, pvt->offset);
101251881Speter      return svn_string_createf(pool, "%s.%s.r%s/%s",
102251881Speter                                pvt->node_id, pvt->copy_id,
103251881Speter                                rev_string, offset_string);
104251881Speter    }
105251881Speter  else
106251881Speter    {
107251881Speter      return svn_string_createf(pool, "%s.%s.t%s",
108251881Speter                                pvt->node_id, pvt->copy_id,
109251881Speter                                pvt->txn_id);
110251881Speter    }
111251881Speter}
112251881Speter
113251881Speter
114251881Speter/*** Comparing node IDs ***/
115251881Speter
116251881Spetersvn_boolean_t
117251881Spetersvn_fs_fs__id_eq(const svn_fs_id_t *a,
118251881Speter                 const svn_fs_id_t *b)
119251881Speter{
120251881Speter  id_private_t *pvta = a->fsap_data, *pvtb = b->fsap_data;
121251881Speter
122251881Speter  if (a == b)
123251881Speter    return TRUE;
124251881Speter  if (strcmp(pvta->node_id, pvtb->node_id) != 0)
125251881Speter     return FALSE;
126251881Speter  if (strcmp(pvta->copy_id, pvtb->copy_id) != 0)
127251881Speter    return FALSE;
128251881Speter  if ((pvta->txn_id == NULL) != (pvtb->txn_id == NULL))
129251881Speter    return FALSE;
130251881Speter  if (pvta->txn_id && pvtb->txn_id && strcmp(pvta->txn_id, pvtb->txn_id) != 0)
131251881Speter    return FALSE;
132251881Speter  if (pvta->rev != pvtb->rev)
133251881Speter    return FALSE;
134251881Speter  if (pvta->offset != pvtb->offset)
135251881Speter    return FALSE;
136251881Speter  return TRUE;
137251881Speter}
138251881Speter
139251881Speter
140251881Spetersvn_boolean_t
141251881Spetersvn_fs_fs__id_check_related(const svn_fs_id_t *a,
142251881Speter                            const svn_fs_id_t *b)
143251881Speter{
144251881Speter  id_private_t *pvta = a->fsap_data, *pvtb = b->fsap_data;
145251881Speter
146251881Speter  if (a == b)
147251881Speter    return TRUE;
148251881Speter  /* If both node_ids start with _ and they have differing transaction
149251881Speter     IDs, then it is impossible for them to be related. */
150251881Speter  if (pvta->node_id[0] == '_')
151251881Speter    {
152251881Speter      if (pvta->txn_id && pvtb->txn_id &&
153251881Speter          (strcmp(pvta->txn_id, pvtb->txn_id) != 0))
154251881Speter        return FALSE;
155251881Speter    }
156251881Speter
157251881Speter  return (strcmp(pvta->node_id, pvtb->node_id) == 0);
158251881Speter}
159251881Speter
160251881Speter
161251881Speterint
162251881Spetersvn_fs_fs__id_compare(const svn_fs_id_t *a,
163251881Speter                      const svn_fs_id_t *b)
164251881Speter{
165251881Speter  if (svn_fs_fs__id_eq(a, b))
166251881Speter    return 0;
167251881Speter  return (svn_fs_fs__id_check_related(a, b) ? 1 : -1);
168251881Speter}
169251881Speter
170251881Speter
171251881Speter
172251881Speter/* Creating ID's.  */
173251881Speter
174251881Speterstatic id_vtable_t id_vtable = {
175251881Speter  svn_fs_fs__id_unparse,
176251881Speter  svn_fs_fs__id_compare
177251881Speter};
178251881Speter
179251881Speter
180251881Spetersvn_fs_id_t *
181251881Spetersvn_fs_fs__id_txn_create(const char *node_id,
182251881Speter                         const char *copy_id,
183251881Speter                         const char *txn_id,
184251881Speter                         apr_pool_t *pool)
185251881Speter{
186251881Speter  svn_fs_id_t *id = apr_palloc(pool, sizeof(*id));
187251881Speter  id_private_t *pvt = apr_palloc(pool, sizeof(*pvt));
188251881Speter
189251881Speter  pvt->node_id = apr_pstrdup(pool, node_id);
190251881Speter  pvt->copy_id = apr_pstrdup(pool, copy_id);
191251881Speter  pvt->txn_id = apr_pstrdup(pool, txn_id);
192251881Speter  pvt->rev = SVN_INVALID_REVNUM;
193251881Speter  pvt->offset = -1;
194251881Speter
195251881Speter  id->vtable = &id_vtable;
196251881Speter  id->fsap_data = pvt;
197251881Speter  return id;
198251881Speter}
199251881Speter
200251881Speter
201251881Spetersvn_fs_id_t *
202251881Spetersvn_fs_fs__id_rev_create(const char *node_id,
203251881Speter                         const char *copy_id,
204251881Speter                         svn_revnum_t rev,
205251881Speter                         apr_off_t offset,
206251881Speter                         apr_pool_t *pool)
207251881Speter{
208251881Speter  svn_fs_id_t *id = apr_palloc(pool, sizeof(*id));
209251881Speter  id_private_t *pvt = apr_palloc(pool, sizeof(*pvt));
210251881Speter
211251881Speter  pvt->node_id = apr_pstrdup(pool, node_id);
212251881Speter  pvt->copy_id = apr_pstrdup(pool, copy_id);
213251881Speter  pvt->txn_id = NULL;
214251881Speter  pvt->rev = rev;
215251881Speter  pvt->offset = offset;
216251881Speter
217251881Speter  id->vtable = &id_vtable;
218251881Speter  id->fsap_data = pvt;
219251881Speter  return id;
220251881Speter}
221251881Speter
222251881Speter
223251881Spetersvn_fs_id_t *
224251881Spetersvn_fs_fs__id_copy(const svn_fs_id_t *id, apr_pool_t *pool)
225251881Speter{
226251881Speter  svn_fs_id_t *new_id = apr_palloc(pool, sizeof(*new_id));
227251881Speter  id_private_t *new_pvt = apr_palloc(pool, sizeof(*new_pvt));
228251881Speter  id_private_t *pvt = id->fsap_data;
229251881Speter
230251881Speter  new_pvt->node_id = apr_pstrdup(pool, pvt->node_id);
231251881Speter  new_pvt->copy_id = apr_pstrdup(pool, pvt->copy_id);
232251881Speter  new_pvt->txn_id = pvt->txn_id ? apr_pstrdup(pool, pvt->txn_id) : NULL;
233251881Speter  new_pvt->rev = pvt->rev;
234251881Speter  new_pvt->offset = pvt->offset;
235251881Speter
236251881Speter  new_id->vtable = &id_vtable;
237251881Speter  new_id->fsap_data = new_pvt;
238251881Speter  return new_id;
239251881Speter}
240251881Speter
241251881Speter
242251881Spetersvn_fs_id_t *
243251881Spetersvn_fs_fs__id_parse(const char *data,
244251881Speter                    apr_size_t len,
245251881Speter                    apr_pool_t *pool)
246251881Speter{
247251881Speter  svn_fs_id_t *id;
248251881Speter  id_private_t *pvt;
249251881Speter  char *data_copy, *str;
250251881Speter
251251881Speter  /* Dup the ID data into POOL.  Our returned ID will have references
252251881Speter     into this memory. */
253251881Speter  data_copy = apr_pstrmemdup(pool, data, len);
254251881Speter
255251881Speter  /* Alloc a new svn_fs_id_t structure. */
256251881Speter  id = apr_palloc(pool, sizeof(*id));
257251881Speter  pvt = apr_palloc(pool, sizeof(*pvt));
258251881Speter  id->vtable = &id_vtable;
259251881Speter  id->fsap_data = pvt;
260251881Speter
261251881Speter  /* Now, we basically just need to "split" this data on `.'
262251881Speter     characters.  We will use svn_cstring_tokenize, which will put
263251881Speter     terminators where each of the '.'s used to be.  Then our new
264251881Speter     id field will reference string locations inside our duplicate
265251881Speter     string.*/
266251881Speter
267251881Speter  /* Node Id */
268251881Speter  str = svn_cstring_tokenize(".", &data_copy);
269251881Speter  if (str == NULL)
270251881Speter    return NULL;
271251881Speter  pvt->node_id = str;
272251881Speter
273251881Speter  /* Copy Id */
274251881Speter  str = svn_cstring_tokenize(".", &data_copy);
275251881Speter  if (str == NULL)
276251881Speter    return NULL;
277251881Speter  pvt->copy_id = str;
278251881Speter
279251881Speter  /* Txn/Rev Id */
280251881Speter  str = svn_cstring_tokenize(".", &data_copy);
281251881Speter  if (str == NULL)
282251881Speter    return NULL;
283251881Speter
284251881Speter  if (str[0] == 'r')
285251881Speter    {
286251881Speter      apr_int64_t val;
287251881Speter      svn_error_t *err;
288251881Speter
289251881Speter      /* This is a revision type ID */
290251881Speter      pvt->txn_id = NULL;
291251881Speter
292251881Speter      data_copy = str + 1;
293251881Speter      str = svn_cstring_tokenize("/", &data_copy);
294251881Speter      if (str == NULL)
295251881Speter        return NULL;
296251881Speter      pvt->rev = SVN_STR_TO_REV(str);
297251881Speter
298251881Speter      str = svn_cstring_tokenize("/", &data_copy);
299251881Speter      if (str == NULL)
300251881Speter        return NULL;
301251881Speter      err = svn_cstring_atoi64(&val, str);
302251881Speter      if (err)
303251881Speter        {
304251881Speter          svn_error_clear(err);
305251881Speter          return NULL;
306251881Speter        }
307251881Speter      pvt->offset = (apr_off_t)val;
308251881Speter    }
309251881Speter  else if (str[0] == 't')
310251881Speter    {
311251881Speter      /* This is a transaction type ID */
312251881Speter      pvt->txn_id = str + 1;
313251881Speter      pvt->rev = SVN_INVALID_REVNUM;
314251881Speter      pvt->offset = -1;
315251881Speter    }
316251881Speter  else
317251881Speter    return NULL;
318251881Speter
319251881Speter  return id;
320251881Speter}
321251881Speter
322251881Speter/* (de-)serialization support */
323251881Speter
324251881Speter/* Serialization of the PVT sub-structure within the CONTEXT.
325251881Speter */
326251881Speterstatic void
327251881Speterserialize_id_private(svn_temp_serializer__context_t *context,
328251881Speter                     const id_private_t * const *pvt)
329251881Speter{
330251881Speter  const id_private_t *private = *pvt;
331251881Speter
332251881Speter  /* serialize the pvt data struct itself */
333251881Speter  svn_temp_serializer__push(context,
334251881Speter                            (const void * const *)pvt,
335251881Speter                            sizeof(*private));
336251881Speter
337251881Speter  /* append the referenced strings */
338251881Speter  svn_temp_serializer__add_string(context, &private->node_id);
339251881Speter  svn_temp_serializer__add_string(context, &private->copy_id);
340251881Speter  svn_temp_serializer__add_string(context, &private->txn_id);
341251881Speter
342251881Speter  /* return to caller's nesting level */
343251881Speter  svn_temp_serializer__pop(context);
344251881Speter}
345251881Speter
346251881Speter/* Serialize an ID within the serialization CONTEXT.
347251881Speter */
348251881Spetervoid
349251881Spetersvn_fs_fs__id_serialize(svn_temp_serializer__context_t *context,
350251881Speter                        const struct svn_fs_id_t * const *id)
351251881Speter{
352251881Speter  /* nothing to do for NULL ids */
353251881Speter  if (*id == NULL)
354251881Speter    return;
355251881Speter
356251881Speter  /* serialize the id data struct itself */
357251881Speter  svn_temp_serializer__push(context,
358251881Speter                            (const void * const *)id,
359251881Speter                            sizeof(**id));
360251881Speter
361251881Speter  /* serialize the id_private_t data sub-struct */
362251881Speter  serialize_id_private(context,
363251881Speter                       (const id_private_t * const *)&(*id)->fsap_data);
364251881Speter
365251881Speter  /* return to caller's nesting level */
366251881Speter  svn_temp_serializer__pop(context);
367251881Speter}
368251881Speter
369251881Speter/* Deserialization of the PVT sub-structure in BUFFER.
370251881Speter */
371251881Speterstatic void
372251881Speterdeserialize_id_private(void *buffer, id_private_t **pvt)
373251881Speter{
374251881Speter  /* fixup the reference to the only sub-structure */
375251881Speter  id_private_t *private;
376251881Speter  svn_temp_deserializer__resolve(buffer, (void**)pvt);
377251881Speter
378251881Speter  /* fixup the sub-structure itself */
379251881Speter  private = *pvt;
380251881Speter  svn_temp_deserializer__resolve(private, (void**)&private->node_id);
381251881Speter  svn_temp_deserializer__resolve(private, (void**)&private->copy_id);
382251881Speter  svn_temp_deserializer__resolve(private, (void**)&private->txn_id);
383251881Speter}
384251881Speter
385251881Speter/* Deserialize an ID inside the BUFFER.
386251881Speter */
387251881Spetervoid
388251881Spetersvn_fs_fs__id_deserialize(void *buffer, svn_fs_id_t **id)
389251881Speter{
390251881Speter  /* The id maybe all what is in the whole buffer.
391251881Speter   * Don't try to fixup the pointer in that case*/
392251881Speter  if (*id != buffer)
393251881Speter    svn_temp_deserializer__resolve(buffer, (void**)id);
394251881Speter
395251881Speter  /* no id, no sub-structure fixup necessary */
396251881Speter  if (*id == NULL)
397251881Speter    return;
398251881Speter
399251881Speter  /* the stored vtable is bogus at best -> set the right one */
400251881Speter  (*id)->vtable = &id_vtable;
401251881Speter
402251881Speter  /* handle sub-structures */
403251881Speter  deserialize_id_private(*id, (id_private_t **)&(*id)->fsap_data);
404251881Speter}
405251881Speter
406