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" 27289180Speter#include "index.h" 28289180Speter 29251881Speter#include "../libsvn_fs/fs-loader.h" 30251881Speter#include "private/svn_temp_serializer.h" 31251881Speter#include "private/svn_string_private.h" 32251881Speter 33251881Speter 34289180Spetertypedef struct fs_fs__id_t 35289180Speter{ 36289180Speter /* API visible part */ 37289180Speter svn_fs_id_t generic_id; 38251881Speter 39289180Speter /* private members */ 40289180Speter struct 41289180Speter { 42289180Speter svn_fs_fs__id_part_t node_id; 43289180Speter svn_fs_fs__id_part_t copy_id; 44289180Speter svn_fs_fs__id_part_t txn_id; 45289180Speter svn_fs_fs__id_part_t rev_item; 46289180Speter } private_id; 47289180Speter} fs_fs__id_t; 48289180Speter 49251881Speter 50251881Speter 51289180Speter/** Like strtol but with a fixed base of 10, locale independent and limited 52289180Speter * to non-negative values. Overflows are indicated by a FALSE return value 53289180Speter * in which case *RESULT_P will not be modified. 54289180Speter * 55289180Speter * This allows the compiler to generate massively faster code. 56289180Speter * (E.g. Avoiding locale specific processing). ID parsing is one of the 57289180Speter * most CPU consuming parts of FSFS data access. Better be quick. 58289180Speter */ 59289180Speterstatic svn_boolean_t 60289180Speterlocale_independent_strtol(long *result_p, 61289180Speter const char* buffer, 62289180Speter const char** end) 63251881Speter{ 64289180Speter /* We allow positive values only. We use unsigned arithmetics to get 65289180Speter * well-defined overflow behavior. It also happens to allow for a wider 66289180Speter * range of compiler-side optimizations. */ 67289180Speter unsigned long result = 0; 68289180Speter while (1) 69289180Speter { 70289180Speter unsigned long c = (unsigned char)*buffer - (unsigned char)'0'; 71289180Speter unsigned long next; 72251881Speter 73289180Speter /* This implies the NUL check. */ 74289180Speter if (c > 9) 75289180Speter break; 76289180Speter 77289180Speter /* Overflow check. Passing this, NEXT can be no more than ULONG_MAX+9 78289180Speter * before being truncated to ULONG but it still covers 0 .. ULONG_MAX. 79289180Speter */ 80289180Speter if (result > ULONG_MAX / 10) 81289180Speter return FALSE; 82289180Speter 83289180Speter next = result * 10 + c; 84289180Speter 85362181Sdim /* Overflow check. In case of an overflow, NEXT is 0..9 and RESULT 86362181Sdim * is much larger than 10. We will then return FALSE. 87362181Sdim * 88362181Sdim * In the non-overflow case, NEXT is >= 10 * RESULT but never smaller. 89362181Sdim * We will continue the loop in that case. */ 90289180Speter if (next < result) 91289180Speter return FALSE; 92289180Speter 93289180Speter result = next; 94289180Speter ++buffer; 95289180Speter } 96289180Speter 97289180Speter *end = buffer; 98289180Speter if (result > LONG_MAX) 99289180Speter return FALSE; 100289180Speter 101289180Speter *result_p = (long)result; 102289180Speter 103289180Speter return TRUE; 104251881Speter} 105251881Speter 106289180Speter/* Parse the NUL-terminated ID part at DATA and write the result into *PART. 107289180Speter * Return TRUE if no errors were detected. */ 108289180Speterstatic svn_boolean_t 109289180Speterpart_parse(svn_fs_fs__id_part_t *part, 110289180Speter const char *data) 111289180Speter{ 112289180Speter const char *end; 113251881Speter 114289180Speter /* special case: ID inside some transaction */ 115289180Speter if (data[0] == '_') 116289180Speter { 117289180Speter part->revision = SVN_INVALID_REVNUM; 118289180Speter part->number = svn__base36toui64(&data, data + 1); 119289180Speter return *data == '\0'; 120289180Speter } 121289180Speter 122289180Speter /* special case: 0 / default ID */ 123289180Speter if (data[0] == '0' && data[1] == '\0') 124289180Speter { 125289180Speter part->revision = 0; 126289180Speter part->number = 0; 127289180Speter return TRUE; 128289180Speter } 129289180Speter 130289180Speter /* read old style / new style ID */ 131289180Speter part->number = svn__base36toui64(&data, data); 132289180Speter if (data[0] != '-') 133289180Speter { 134289180Speter part->revision = 0; 135289180Speter return *data == '\0'; 136289180Speter } 137289180Speter 138289180Speter return locale_independent_strtol(&part->revision, data+1, &end); 139289180Speter} 140289180Speter 141289180Speter/* Parse the transaction id in DATA and store the result in *TXN_ID. 142289180Speter * Return FALSE if there was some problem. 143289180Speter */ 144289180Speterstatic svn_boolean_t 145289180Spetertxn_id_parse(svn_fs_fs__id_part_t *txn_id, 146289180Speter const char *data) 147251881Speter{ 148289180Speter const char *end; 149289180Speter if (!locale_independent_strtol(&txn_id->revision, data, &end)) 150289180Speter return FALSE; 151251881Speter 152289180Speter data = end; 153289180Speter if (*data != '-') 154289180Speter return FALSE; 155289180Speter 156289180Speter ++data; 157289180Speter txn_id->number = svn__base36toui64(&data, data); 158289180Speter return *data == '\0'; 159251881Speter} 160251881Speter 161289180Speter/* Write the textual representation of *PART into P and return a pointer 162289180Speter * to the first position behind that string. 163289180Speter */ 164289180Speterstatic char * 165289180Speterunparse_id_part(char *p, 166289180Speter const svn_fs_fs__id_part_t *part) 167289180Speter{ 168289180Speter if (SVN_IS_VALID_REVNUM(part->revision)) 169289180Speter { 170289180Speter /* ordinary old style / new style ID */ 171289180Speter p += svn__ui64tobase36(p, part->number); 172289180Speter if (part->revision > 0) 173289180Speter { 174289180Speter *(p++) = '-'; 175289180Speter p += svn__i64toa(p, part->revision); 176289180Speter } 177289180Speter } 178289180Speter else 179289180Speter { 180289180Speter /* in txn: mark with "_" prefix */ 181289180Speter *(p++) = '_'; 182289180Speter p += svn__ui64tobase36(p, part->number); 183289180Speter } 184251881Speter 185289180Speter *(p++) = '.'; 186289180Speter 187289180Speter return p; 188289180Speter} 189289180Speter 190289180Speter 191289180Speter 192289180Speter/* Operations on ID parts */ 193289180Speter 194289180Spetersvn_boolean_t 195289180Spetersvn_fs_fs__id_part_is_root(const svn_fs_fs__id_part_t* part) 196289180Speter{ 197289180Speter return part->revision == 0 && part->number == 0; 198289180Speter} 199289180Speter 200289180Spetersvn_boolean_t 201289180Spetersvn_fs_fs__id_part_eq(const svn_fs_fs__id_part_t *lhs, 202289180Speter const svn_fs_fs__id_part_t *rhs) 203289180Speter{ 204289180Speter return lhs->revision == rhs->revision && lhs->number == rhs->number; 205289180Speter} 206289180Speter 207289180Spetersvn_boolean_t 208289180Spetersvn_fs_fs__id_txn_used(const svn_fs_fs__id_part_t *txn_id) 209289180Speter{ 210289180Speter return SVN_IS_VALID_REVNUM(txn_id->revision) || (txn_id->number != 0); 211289180Speter} 212289180Speter 213289180Spetervoid 214289180Spetersvn_fs_fs__id_txn_reset(svn_fs_fs__id_part_t *txn_id) 215289180Speter{ 216289180Speter txn_id->revision = SVN_INVALID_REVNUM; 217289180Speter txn_id->number = 0; 218289180Speter} 219289180Speter 220289180Spetersvn_error_t * 221289180Spetersvn_fs_fs__id_txn_parse(svn_fs_fs__id_part_t *txn_id, 222289180Speter const char *data) 223289180Speter{ 224289180Speter if (! txn_id_parse(txn_id, data)) 225289180Speter return svn_error_createf(SVN_ERR_FS_MALFORMED_TXN_ID, NULL, 226289180Speter "malformed txn id '%s'", data); 227289180Speter 228289180Speter return SVN_NO_ERROR; 229289180Speter} 230289180Speter 231251881Speterconst char * 232289180Spetersvn_fs_fs__id_txn_unparse(const svn_fs_fs__id_part_t *txn_id, 233289180Speter apr_pool_t *pool) 234251881Speter{ 235289180Speter char string[2 * SVN_INT64_BUFFER_SIZE + 1]; 236289180Speter char *p = string; 237251881Speter 238289180Speter p += svn__i64toa(p, txn_id->revision); 239289180Speter *(p++) = '-'; 240289180Speter p += svn__ui64tobase36(p, txn_id->number); 241289180Speter 242289180Speter return apr_pstrmemdup(pool, string, p - string); 243251881Speter} 244251881Speter 245289180Speter 246251881Speter 247289180Speter/* Accessing ID Pieces. */ 248289180Speter 249289180Speterconst svn_fs_fs__id_part_t * 250289180Spetersvn_fs_fs__id_node_id(const svn_fs_id_t *fs_id) 251289180Speter{ 252289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 253289180Speter 254289180Speter return &id->private_id.node_id; 255289180Speter} 256289180Speter 257289180Speter 258289180Speterconst svn_fs_fs__id_part_t * 259289180Spetersvn_fs_fs__id_copy_id(const svn_fs_id_t *fs_id) 260289180Speter{ 261289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 262289180Speter 263289180Speter return &id->private_id.copy_id; 264289180Speter} 265289180Speter 266289180Speter 267289180Speterconst svn_fs_fs__id_part_t * 268289180Spetersvn_fs_fs__id_txn_id(const svn_fs_id_t *fs_id) 269289180Speter{ 270289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 271289180Speter 272289180Speter return &id->private_id.txn_id; 273289180Speter} 274289180Speter 275289180Speter 276289180Speterconst svn_fs_fs__id_part_t * 277289180Spetersvn_fs_fs__id_rev_item(const svn_fs_id_t *fs_id) 278289180Speter{ 279289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 280289180Speter 281289180Speter return &id->private_id.rev_item; 282289180Speter} 283289180Speter 284251881Spetersvn_revnum_t 285289180Spetersvn_fs_fs__id_rev(const svn_fs_id_t *fs_id) 286251881Speter{ 287289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 288251881Speter 289289180Speter return id->private_id.rev_item.revision; 290251881Speter} 291251881Speter 292289180Speterapr_uint64_t 293289180Spetersvn_fs_fs__id_item(const svn_fs_id_t *fs_id) 294289180Speter{ 295289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 296251881Speter 297289180Speter return id->private_id.rev_item.number; 298289180Speter} 299289180Speter 300289180Spetersvn_boolean_t 301289180Spetersvn_fs_fs__id_is_txn(const svn_fs_id_t *fs_id) 302251881Speter{ 303289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 304251881Speter 305289180Speter return svn_fs_fs__id_txn_used(&id->private_id.txn_id); 306251881Speter} 307251881Speter 308251881Spetersvn_string_t * 309289180Spetersvn_fs_fs__id_unparse(const svn_fs_id_t *fs_id, 310251881Speter apr_pool_t *pool) 311251881Speter{ 312289180Speter char string[6 * SVN_INT64_BUFFER_SIZE + 10]; 313289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)fs_id; 314251881Speter 315289180Speter char *p = unparse_id_part(string, &id->private_id.node_id); 316289180Speter p = unparse_id_part(p, &id->private_id.copy_id); 317289180Speter 318289180Speter if (svn_fs_fs__id_txn_used(&id->private_id.txn_id)) 319251881Speter { 320289180Speter *(p++) = 't'; 321289180Speter p += svn__i64toa(p, id->private_id.txn_id.revision); 322289180Speter *(p++) = '-'; 323289180Speter p += svn__ui64tobase36(p, id->private_id.txn_id.number); 324251881Speter } 325251881Speter else 326251881Speter { 327289180Speter *(p++) = 'r'; 328289180Speter p += svn__i64toa(p, id->private_id.rev_item.revision); 329289180Speter *(p++) = '/'; 330289180Speter p += svn__i64toa(p, id->private_id.rev_item.number); 331251881Speter } 332289180Speter 333289180Speter return svn_string_ncreate(string, p - string, pool); 334251881Speter} 335251881Speter 336251881Speter 337251881Speter/*** Comparing node IDs ***/ 338251881Speter 339251881Spetersvn_boolean_t 340251881Spetersvn_fs_fs__id_eq(const svn_fs_id_t *a, 341251881Speter const svn_fs_id_t *b) 342251881Speter{ 343289180Speter const fs_fs__id_t *id_a = (const fs_fs__id_t *)a; 344289180Speter const fs_fs__id_t *id_b = (const fs_fs__id_t *)b; 345251881Speter 346251881Speter if (a == b) 347251881Speter return TRUE; 348289180Speter 349289180Speter return svn_fs_fs__id_part_eq(&id_a->private_id.node_id, 350289180Speter &id_b->private_id.node_id) 351289180Speter && svn_fs_fs__id_part_eq(&id_a->private_id.copy_id, 352289180Speter &id_b->private_id.copy_id) 353289180Speter && svn_fs_fs__id_part_eq(&id_a->private_id.txn_id, 354289180Speter &id_b->private_id.txn_id) 355289180Speter && svn_fs_fs__id_part_eq(&id_a->private_id.rev_item, 356289180Speter &id_b->private_id.rev_item); 357251881Speter} 358251881Speter 359251881Speter 360251881Spetersvn_boolean_t 361251881Spetersvn_fs_fs__id_check_related(const svn_fs_id_t *a, 362251881Speter const svn_fs_id_t *b) 363251881Speter{ 364289180Speter const fs_fs__id_t *id_a = (const fs_fs__id_t *)a; 365289180Speter const fs_fs__id_t *id_b = (const fs_fs__id_t *)b; 366251881Speter 367251881Speter if (a == b) 368251881Speter return TRUE; 369289180Speter 370289180Speter /* If both node_ids have been created within _different_ transactions 371289180Speter (and are still uncommitted), then it is impossible for them to be 372289180Speter related. 373289180Speter 374289180Speter Due to our txn-local temporary IDs, however, they might have been 375289180Speter given the same temporary node ID. We need to detect that case. 376289180Speter */ 377289180Speter if ( id_a->private_id.node_id.revision == SVN_INVALID_REVNUM 378289180Speter && id_b->private_id.node_id.revision == SVN_INVALID_REVNUM) 379251881Speter { 380289180Speter if (!svn_fs_fs__id_part_eq(&id_a->private_id.txn_id, 381289180Speter &id_b->private_id.txn_id)) 382251881Speter return FALSE; 383289180Speter 384289180Speter /* At this point, matching node_ids implies relatedness. */ 385251881Speter } 386251881Speter 387289180Speter return svn_fs_fs__id_part_eq(&id_a->private_id.node_id, 388289180Speter &id_b->private_id.node_id); 389251881Speter} 390251881Speter 391251881Speter 392289180Spetersvn_fs_node_relation_t 393251881Spetersvn_fs_fs__id_compare(const svn_fs_id_t *a, 394251881Speter const svn_fs_id_t *b) 395251881Speter{ 396251881Speter if (svn_fs_fs__id_eq(a, b)) 397289180Speter return svn_fs_node_unchanged; 398289180Speter return (svn_fs_fs__id_check_related(a, b) ? svn_fs_node_common_ancestor 399289180Speter : svn_fs_node_unrelated); 400251881Speter} 401251881Speter 402289180Speterint 403289180Spetersvn_fs_fs__id_part_compare(const svn_fs_fs__id_part_t *a, 404289180Speter const svn_fs_fs__id_part_t *b) 405289180Speter{ 406289180Speter if (a->revision < b->revision) 407289180Speter return -1; 408289180Speter if (a->revision > b->revision) 409289180Speter return 1; 410251881Speter 411289180Speter return a->number < b->number ? -1 : a->number == b->number ? 0 : 1; 412289180Speter} 413289180Speter 414289180Speter 415251881Speter 416251881Speter/* Creating ID's. */ 417251881Speter 418251881Speterstatic id_vtable_t id_vtable = { 419251881Speter svn_fs_fs__id_unparse, 420251881Speter svn_fs_fs__id_compare 421251881Speter}; 422251881Speter 423251881Spetersvn_fs_id_t * 424289180Spetersvn_fs_fs__id_txn_create_root(const svn_fs_fs__id_part_t *txn_id, 425289180Speter apr_pool_t *pool) 426251881Speter{ 427289180Speter fs_fs__id_t *id = apr_pcalloc(pool, sizeof(*id)); 428251881Speter 429289180Speter /* node ID and copy ID are "0" */ 430251881Speter 431289180Speter id->private_id.txn_id = *txn_id; 432289180Speter id->private_id.rev_item.revision = SVN_INVALID_REVNUM; 433289180Speter 434289180Speter id->generic_id.vtable = &id_vtable; 435289180Speter id->generic_id.fsap_data = id; 436289180Speter 437289180Speter return (svn_fs_id_t *)id; 438251881Speter} 439251881Speter 440289180Spetersvn_fs_id_t *svn_fs_fs__id_create_root(const svn_revnum_t revision, 441289180Speter apr_pool_t *pool) 442289180Speter{ 443289180Speter fs_fs__id_t *id = apr_pcalloc(pool, sizeof(*id)); 444251881Speter 445289180Speter id->private_id.txn_id.revision = SVN_INVALID_REVNUM; 446289180Speter id->private_id.rev_item.revision = revision; 447289180Speter id->private_id.rev_item.number = SVN_FS_FS__ITEM_INDEX_ROOT_NODE; 448289180Speter 449289180Speter id->generic_id.vtable = &id_vtable; 450289180Speter id->generic_id.fsap_data = id; 451289180Speter 452289180Speter return (svn_fs_id_t *)id; 453289180Speter} 454289180Speter 455251881Spetersvn_fs_id_t * 456289180Spetersvn_fs_fs__id_txn_create(const svn_fs_fs__id_part_t *node_id, 457289180Speter const svn_fs_fs__id_part_t *copy_id, 458289180Speter const svn_fs_fs__id_part_t *txn_id, 459251881Speter apr_pool_t *pool) 460251881Speter{ 461289180Speter fs_fs__id_t *id = apr_pcalloc(pool, sizeof(*id)); 462251881Speter 463289180Speter id->private_id.node_id = *node_id; 464289180Speter id->private_id.copy_id = *copy_id; 465289180Speter id->private_id.txn_id = *txn_id; 466289180Speter id->private_id.rev_item.revision = SVN_INVALID_REVNUM; 467251881Speter 468289180Speter id->generic_id.vtable = &id_vtable; 469289180Speter id->generic_id.fsap_data = id; 470289180Speter 471289180Speter return (svn_fs_id_t *)id; 472251881Speter} 473251881Speter 474251881Speter 475251881Spetersvn_fs_id_t * 476289180Spetersvn_fs_fs__id_rev_create(const svn_fs_fs__id_part_t *node_id, 477289180Speter const svn_fs_fs__id_part_t *copy_id, 478289180Speter const svn_fs_fs__id_part_t *rev_item, 479289180Speter apr_pool_t *pool) 480251881Speter{ 481289180Speter fs_fs__id_t *id = apr_pcalloc(pool, sizeof(*id)); 482251881Speter 483289180Speter id->private_id.node_id = *node_id; 484289180Speter id->private_id.copy_id = *copy_id; 485289180Speter id->private_id.txn_id.revision = SVN_INVALID_REVNUM; 486289180Speter id->private_id.rev_item = *rev_item; 487251881Speter 488289180Speter id->generic_id.vtable = &id_vtable; 489289180Speter id->generic_id.fsap_data = id; 490289180Speter 491289180Speter return (svn_fs_id_t *)id; 492251881Speter} 493251881Speter 494251881Speter 495251881Spetersvn_fs_id_t * 496289180Spetersvn_fs_fs__id_copy(const svn_fs_id_t *source, apr_pool_t *pool) 497251881Speter{ 498289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)source; 499289180Speter fs_fs__id_t *new_id = apr_pmemdup(pool, id, sizeof(*new_id)); 500251881Speter 501289180Speter new_id->generic_id.fsap_data = new_id; 502251881Speter 503289180Speter return (svn_fs_id_t *)new_id; 504289180Speter} 505289180Speter 506289180Speter/* Return an ID resulting from parsing the string DATA, or NULL if DATA is 507289180Speter an invalid ID string. *DATA will be modified / invalidated by this call. */ 508289180Speterstatic svn_fs_id_t * 509289180Speterid_parse(char *data, 510289180Speter apr_pool_t *pool) 511289180Speter{ 512289180Speter fs_fs__id_t *id; 513289180Speter char *str; 514289180Speter 515251881Speter /* Alloc a new svn_fs_id_t structure. */ 516289180Speter id = apr_pcalloc(pool, sizeof(*id)); 517289180Speter id->generic_id.vtable = &id_vtable; 518289180Speter id->generic_id.fsap_data = id; 519251881Speter 520251881Speter /* Now, we basically just need to "split" this data on `.' 521251881Speter characters. We will use svn_cstring_tokenize, which will put 522251881Speter terminators where each of the '.'s used to be. Then our new 523251881Speter id field will reference string locations inside our duplicate 524251881Speter string.*/ 525251881Speter 526251881Speter /* Node Id */ 527289180Speter str = svn_cstring_tokenize(".", &data); 528251881Speter if (str == NULL) 529251881Speter return NULL; 530289180Speter if (! part_parse(&id->private_id.node_id, str)) 531289180Speter return NULL; 532251881Speter 533251881Speter /* Copy Id */ 534289180Speter str = svn_cstring_tokenize(".", &data); 535251881Speter if (str == NULL) 536251881Speter return NULL; 537289180Speter if (! part_parse(&id->private_id.copy_id, str)) 538289180Speter return NULL; 539251881Speter 540251881Speter /* Txn/Rev Id */ 541289180Speter str = svn_cstring_tokenize(".", &data); 542251881Speter if (str == NULL) 543251881Speter return NULL; 544251881Speter 545251881Speter if (str[0] == 'r') 546251881Speter { 547251881Speter apr_int64_t val; 548289180Speter const char *tmp; 549251881Speter svn_error_t *err; 550251881Speter 551251881Speter /* This is a revision type ID */ 552289180Speter id->private_id.txn_id.revision = SVN_INVALID_REVNUM; 553289180Speter id->private_id.txn_id.number = 0; 554251881Speter 555289180Speter data = str + 1; 556289180Speter str = svn_cstring_tokenize("/", &data); 557251881Speter if (str == NULL) 558251881Speter return NULL; 559289180Speter if (!locale_independent_strtol(&id->private_id.rev_item.revision, 560289180Speter str, &tmp)) 561289180Speter return NULL; 562251881Speter 563289180Speter err = svn_cstring_atoi64(&val, data); 564251881Speter if (err) 565251881Speter { 566251881Speter svn_error_clear(err); 567251881Speter return NULL; 568251881Speter } 569289180Speter id->private_id.rev_item.number = (apr_uint64_t)val; 570251881Speter } 571251881Speter else if (str[0] == 't') 572251881Speter { 573251881Speter /* This is a transaction type ID */ 574289180Speter id->private_id.rev_item.revision = SVN_INVALID_REVNUM; 575289180Speter id->private_id.rev_item.number = 0; 576289180Speter 577289180Speter if (! txn_id_parse(&id->private_id.txn_id, str + 1)) 578289180Speter return NULL; 579251881Speter } 580251881Speter else 581251881Speter return NULL; 582251881Speter 583289180Speter return (svn_fs_id_t *)id; 584251881Speter} 585251881Speter 586289180Spetersvn_error_t * 587289180Spetersvn_fs_fs__id_parse(const svn_fs_id_t **id_p, 588289180Speter char *data, 589289180Speter apr_pool_t *pool) 590251881Speter{ 591289180Speter svn_fs_id_t *id = id_parse(data, pool); 592289180Speter if (id == NULL) 593289180Speter return svn_error_createf(SVN_ERR_FS_MALFORMED_NODEREV_ID, NULL, 594362181Sdim "Malformed node revision ID string '%s'", 595362181Sdim data); 596251881Speter 597289180Speter *id_p = id; 598251881Speter 599289180Speter return SVN_NO_ERROR; 600251881Speter} 601251881Speter 602289180Speter/* (de-)serialization support */ 603289180Speter 604251881Speter/* Serialize an ID within the serialization CONTEXT. 605251881Speter */ 606251881Spetervoid 607251881Spetersvn_fs_fs__id_serialize(svn_temp_serializer__context_t *context, 608289180Speter const svn_fs_id_t * const *in) 609251881Speter{ 610289180Speter const fs_fs__id_t *id = (const fs_fs__id_t *)*in; 611289180Speter 612251881Speter /* nothing to do for NULL ids */ 613289180Speter if (id == NULL) 614251881Speter return; 615251881Speter 616362181Sdim /* Serialize the id data struct itself. 617362181Sdim * Note that the structure behind IN is actually larger than a mere 618362181Sdim * svn_fs_id_t . */ 619289180Speter svn_temp_serializer__add_leaf(context, 620289180Speter (const void * const *)in, 621289180Speter sizeof(fs_fs__id_t)); 622251881Speter} 623251881Speter 624251881Speter/* Deserialize an ID inside the BUFFER. 625251881Speter */ 626251881Spetervoid 627289180Spetersvn_fs_fs__id_deserialize(void *buffer, svn_fs_id_t **in_out) 628251881Speter{ 629289180Speter fs_fs__id_t *id; 630289180Speter 631251881Speter /* The id maybe all what is in the whole buffer. 632251881Speter * Don't try to fixup the pointer in that case*/ 633289180Speter if (*in_out != buffer) 634289180Speter svn_temp_deserializer__resolve(buffer, (void**)in_out); 635251881Speter 636289180Speter id = (fs_fs__id_t *)*in_out; 637289180Speter 638251881Speter /* no id, no sub-structure fixup necessary */ 639289180Speter if (id == NULL) 640251881Speter return; 641251881Speter 642251881Speter /* the stored vtable is bogus at best -> set the right one */ 643289180Speter id->generic_id.vtable = &id_vtable; 644289180Speter id->generic_id.fsap_data = id; 645251881Speter} 646251881Speter 647