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