1/* fs_skels.c --- conversion between fs native types and skeletons 2 * 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 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 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 19 * under the License. 20 * ==================================================================== 21 */ 22 23#include <string.h> 24 25#include <apr_md5.h> 26#include <apr_sha1.h> 27 28#include "svn_error.h" 29#include "svn_string.h" 30#include "svn_types.h" 31#include "svn_time.h" 32 33#include "private/svn_skel.h" 34#include "private/svn_dep_compat.h" 35#include "private/svn_subr_private.h" 36 37#include "svn_checksum.h" 38#include "fs_skels.h" 39#include "../id.h" 40 41 42static svn_error_t * 43skel_err(const char *skel_type) 44{ 45 return svn_error_createf(SVN_ERR_FS_MALFORMED_SKEL, NULL, 46 "Malformed%s%s skeleton", 47 skel_type ? " " : "", 48 skel_type ? skel_type : ""); 49} 50 51 52 53/*** Validity Checking ***/ 54 55static svn_boolean_t 56is_valid_checksum_skel(svn_skel_t *skel) 57{ 58 if (svn_skel__list_length(skel) != 2) 59 return FALSE; 60 61 if (svn_skel__matches_atom(skel->children, "md5") 62 && skel->children->next->is_atom) 63 return TRUE; 64 65 if (svn_skel__matches_atom(skel->children, "sha1") 66 && skel->children->next->is_atom) 67 return TRUE; 68 69 return FALSE; 70} 71 72 73static svn_boolean_t 74is_valid_revision_skel(svn_skel_t *skel) 75{ 76 int len = svn_skel__list_length(skel); 77 78 if ((len == 2) 79 && svn_skel__matches_atom(skel->children, "revision") 80 && skel->children->next->is_atom) 81 return TRUE; 82 83 return FALSE; 84} 85 86 87static svn_boolean_t 88is_valid_transaction_skel(svn_skel_t *skel, transaction_kind_t *kind) 89{ 90 int len = svn_skel__list_length(skel); 91 92 if (len != 5) 93 return FALSE; 94 95 /* Determine (and verify) the kind. */ 96 if (svn_skel__matches_atom(skel->children, "transaction")) 97 *kind = transaction_kind_normal; 98 else if (svn_skel__matches_atom(skel->children, "committed")) 99 *kind = transaction_kind_committed; 100 else if (svn_skel__matches_atom(skel->children, "dead")) 101 *kind = transaction_kind_dead; 102 else 103 return FALSE; 104 105 if (skel->children->next->is_atom 106 && skel->children->next->next->is_atom 107 && (! skel->children->next->next->next->is_atom) 108 && (! skel->children->next->next->next->next->is_atom)) 109 return TRUE; 110 111 return FALSE; 112} 113 114 115static svn_boolean_t 116is_valid_rep_delta_chunk_skel(svn_skel_t *skel) 117{ 118 int len; 119 svn_skel_t *window; 120 svn_skel_t *diff; 121 122 /* check the delta skel. */ 123 if ((svn_skel__list_length(skel) != 2) 124 || (! skel->children->is_atom)) 125 return FALSE; 126 127 /* check the window. */ 128 window = skel->children->next; 129 len = svn_skel__list_length(window); 130 if ((len < 3) || (len > 4)) 131 return FALSE; 132 if (! ((! window->children->is_atom) 133 && (window->children->next->is_atom) 134 && (window->children->next->next->is_atom))) 135 return FALSE; 136 if ((len == 4) 137 && (! window->children->next->next->next->is_atom)) 138 return FALSE; 139 140 /* check the diff. ### currently we support only svndiff version 141 0 delta data. */ 142 diff = window->children; 143 if ((svn_skel__list_length(diff) == 3) 144 && (svn_skel__matches_atom(diff->children, "svndiff")) 145 && ((svn_skel__matches_atom(diff->children->next, "0")) 146 || (svn_skel__matches_atom(diff->children->next, "1"))) 147 && (diff->children->next->next->is_atom)) 148 return TRUE; 149 150 return FALSE; 151} 152 153 154static svn_boolean_t 155is_valid_representation_skel(svn_skel_t *skel) 156{ 157 int len = svn_skel__list_length(skel); 158 svn_skel_t *header; 159 int header_len; 160 161 /* the rep has at least two items in it, a HEADER list, and at least 162 one piece of kind-specific data. */ 163 if (len < 2) 164 return FALSE; 165 166 /* check the header. it must have KIND and TXN atoms, and 167 optionally 1 or 2 checksums (which is a list form). */ 168 header = skel->children; 169 header_len = svn_skel__list_length(header); 170 if (! (((header_len == 2) /* 2 means old repository, checksum absent */ 171 && (header->children->is_atom) 172 && (header->children->next->is_atom)) 173 || ((header_len == 3) /* 3 means md5 checksum present */ 174 && (header->children->is_atom) 175 && (header->children->next->is_atom) 176 && (is_valid_checksum_skel(header->children->next->next))) 177 || ((header_len == 4) /* 3 means md5 and sha1 checksums present */ 178 && (header->children->is_atom) 179 && (header->children->next->is_atom) 180 && (is_valid_checksum_skel(header->children->next->next)) 181 && (is_valid_checksum_skel(header->children->next->next->next))))) 182 return FALSE; 183 184 /* check for fulltext rep. */ 185 if ((len == 2) 186 && (svn_skel__matches_atom(header->children, "fulltext"))) 187 return TRUE; 188 189 /* check for delta rep. */ 190 if ((len >= 2) 191 && (svn_skel__matches_atom(header->children, "delta"))) 192 { 193 /* it's a delta rep. check the validity. */ 194 svn_skel_t *chunk = skel->children->next; 195 196 /* loop over chunks, checking each one. */ 197 while (chunk) 198 { 199 if (! is_valid_rep_delta_chunk_skel(chunk)) 200 return FALSE; 201 chunk = chunk->next; 202 } 203 204 /* all good on this delta rep. */ 205 return TRUE; 206 } 207 208 return FALSE; 209} 210 211 212static svn_boolean_t 213is_valid_node_revision_header_skel(svn_skel_t *skel, svn_skel_t **kind_p) 214{ 215 int len = svn_skel__list_length(skel); 216 217 if (len < 2) 218 return FALSE; 219 220 /* set the *KIND_P pointer. */ 221 *kind_p = skel->children; 222 223 /* check for valid lengths. */ 224 if (! ((len == 2) || (len == 3) || (len == 4) || (len == 6))) 225 return FALSE; 226 227 /* got mergeinfo stuff? */ 228 if ((len > 4) 229 && (! (skel->children->next->next->next->next->is_atom 230 && skel->children->next->next->next->next->next->is_atom))) 231 return FALSE; 232 233 /* got predecessor count? */ 234 if ((len > 3) 235 && (! skel->children->next->next->next->is_atom)) 236 return FALSE; 237 238 /* got predecessor? */ 239 if ((len > 2) 240 && (! skel->children->next->next->is_atom)) 241 return FALSE; 242 243 /* got the basics? */ 244 if (! (skel->children->is_atom 245 && skel->children->next->is_atom 246 && (skel->children->next->data[0] == '/'))) 247 return FALSE; 248 249 return TRUE; 250} 251 252 253static svn_boolean_t 254is_valid_node_revision_skel(svn_skel_t *skel) 255{ 256 int len = svn_skel__list_length(skel); 257 svn_skel_t *header = skel->children; 258 svn_skel_t *kind; 259 260 if (len < 1) 261 return FALSE; 262 263 if (! is_valid_node_revision_header_skel(header, &kind)) 264 return FALSE; 265 266 if (svn_skel__matches_atom(kind, "dir")) 267 { 268 if (! ((len == 3) 269 && header->next->is_atom 270 && header->next->next->is_atom)) 271 return FALSE; 272 } 273 else if (svn_skel__matches_atom(kind, "file")) 274 { 275 if (len < 3) 276 return FALSE; 277 278 if (! header->next->is_atom) 279 return FALSE; 280 281 /* As of SVN_FS_BASE__MIN_REP_SHARING_FORMAT version, the 282 DATA-KEY slot can be a 2-tuple. */ 283 if (! header->next->next->is_atom) 284 { 285 if (! ((svn_skel__list_length(header->next->next) == 2) 286 && header->next->next->children->is_atom 287 && header->next->next->children->len 288 && header->next->next->children->next->is_atom 289 && header->next->next->children->next->len)) 290 return FALSE; 291 } 292 293 if ((len > 3) && (! header->next->next->next->is_atom)) 294 return FALSE; 295 296 if (len > 4) 297 return FALSE; 298 } 299 300 return TRUE; 301} 302 303 304static svn_boolean_t 305is_valid_copy_skel(svn_skel_t *skel) 306{ 307 return ((svn_skel__list_length(skel) == 4) 308 && (svn_skel__matches_atom(skel->children, "copy") 309 || svn_skel__matches_atom(skel->children, "soft-copy")) 310 && skel->children->next->is_atom 311 && skel->children->next->next->is_atom 312 && skel->children->next->next->next->is_atom); 313} 314 315 316static svn_boolean_t 317is_valid_change_skel(svn_skel_t *skel, svn_fs_path_change_kind_t *kind) 318{ 319 if ((svn_skel__list_length(skel) == 6) 320 && svn_skel__matches_atom(skel->children, "change") 321 && skel->children->next->is_atom 322 && skel->children->next->next->is_atom 323 && skel->children->next->next->next->is_atom 324 && skel->children->next->next->next->next->is_atom 325 && skel->children->next->next->next->next->next->is_atom) 326 { 327 svn_skel_t *kind_skel = skel->children->next->next->next; 328 329 /* check the kind (and return it) */ 330 if (svn_skel__matches_atom(kind_skel, "reset")) 331 { 332 if (kind) 333 *kind = svn_fs_path_change_reset; 334 return TRUE; 335 } 336 if (svn_skel__matches_atom(kind_skel, "add")) 337 { 338 if (kind) 339 *kind = svn_fs_path_change_add; 340 return TRUE; 341 } 342 if (svn_skel__matches_atom(kind_skel, "delete")) 343 { 344 if (kind) 345 *kind = svn_fs_path_change_delete; 346 return TRUE; 347 } 348 if (svn_skel__matches_atom(kind_skel, "replace")) 349 { 350 if (kind) 351 *kind = svn_fs_path_change_replace; 352 return TRUE; 353 } 354 if (svn_skel__matches_atom(kind_skel, "modify")) 355 { 356 if (kind) 357 *kind = svn_fs_path_change_modify; 358 return TRUE; 359 } 360 } 361 return FALSE; 362} 363 364 365static svn_boolean_t 366is_valid_lock_skel(svn_skel_t *skel) 367{ 368 if ((svn_skel__list_length(skel) == 8) 369 && svn_skel__matches_atom(skel->children, "lock") 370 && skel->children->next->is_atom 371 && skel->children->next->next->is_atom 372 && skel->children->next->next->next->is_atom 373 && skel->children->next->next->next->next->is_atom 374 && skel->children->next->next->next->next->next->is_atom 375 && skel->children->next->next->next->next->next->next->is_atom 376 && skel->children->next->next->next->next->next->next->next->is_atom) 377 return TRUE; 378 379 return FALSE; 380} 381 382 383 384/*** Parsing (conversion from skeleton to native FS type) ***/ 385 386svn_error_t * 387svn_fs_base__parse_revision_skel(revision_t **revision_p, 388 svn_skel_t *skel, 389 apr_pool_t *pool) 390{ 391 revision_t *revision; 392 393 /* Validate the skel. */ 394 if (! is_valid_revision_skel(skel)) 395 return skel_err("revision"); 396 397 /* Create the returned structure */ 398 revision = apr_pcalloc(pool, sizeof(*revision)); 399 revision->txn_id = apr_pstrmemdup(pool, skel->children->next->data, 400 skel->children->next->len); 401 402 /* Return the structure. */ 403 *revision_p = revision; 404 return SVN_NO_ERROR; 405} 406 407 408svn_error_t * 409svn_fs_base__parse_transaction_skel(transaction_t **transaction_p, 410 svn_skel_t *skel, 411 apr_pool_t *pool) 412{ 413 transaction_t *transaction; 414 transaction_kind_t kind; 415 svn_skel_t *root_id, *base_id_or_rev, *proplist, *copies; 416 int len; 417 418 /* Validate the skel. */ 419 if (! is_valid_transaction_skel(skel, &kind)) 420 return skel_err("transaction"); 421 422 root_id = skel->children->next; 423 base_id_or_rev = skel->children->next->next; 424 proplist = skel->children->next->next->next; 425 copies = skel->children->next->next->next->next; 426 427 /* Create the returned structure */ 428 transaction = apr_pcalloc(pool, sizeof(*transaction)); 429 430 /* KIND */ 431 transaction->kind = kind; 432 433 /* REVISION or BASE-ID */ 434 if (kind == transaction_kind_committed) 435 { 436 /* Committed transactions have a revision number... */ 437 transaction->base_id = NULL; 438 transaction->revision = 439 SVN_STR_TO_REV(apr_pstrmemdup(pool, base_id_or_rev->data, 440 base_id_or_rev->len)); 441 if (! SVN_IS_VALID_REVNUM(transaction->revision)) 442 return skel_err("transaction"); 443 444 } 445 else 446 { 447 /* ...where unfinished transactions have a base node-revision-id. */ 448 transaction->revision = SVN_INVALID_REVNUM; 449 transaction->base_id = svn_fs_base__id_parse(base_id_or_rev->data, 450 base_id_or_rev->len, pool); 451 } 452 453 /* ROOT-ID */ 454 transaction->root_id = svn_fs_base__id_parse(root_id->data, 455 root_id->len, pool); 456 457 /* PROPLIST */ 458 SVN_ERR(svn_skel__parse_proplist(&(transaction->proplist), 459 proplist, pool)); 460 461 /* COPIES */ 462 if ((len = svn_skel__list_length(copies))) 463 { 464 const char *copy_id; 465 apr_array_header_t *txncopies; 466 svn_skel_t *cpy = copies->children; 467 468 txncopies = apr_array_make(pool, len, sizeof(copy_id)); 469 while (cpy) 470 { 471 copy_id = apr_pstrmemdup(pool, cpy->data, cpy->len); 472 APR_ARRAY_PUSH(txncopies, const char *) = copy_id; 473 cpy = cpy->next; 474 } 475 transaction->copies = txncopies; 476 } 477 478 /* Return the structure. */ 479 *transaction_p = transaction; 480 return SVN_NO_ERROR; 481} 482 483 484svn_error_t * 485svn_fs_base__parse_representation_skel(representation_t **rep_p, 486 svn_skel_t *skel, 487 apr_pool_t *pool) 488{ 489 representation_t *rep; 490 svn_skel_t *header_skel; 491 492 /* Validate the skel. */ 493 if (! is_valid_representation_skel(skel)) 494 return skel_err("representation"); 495 header_skel = skel->children; 496 497 /* Create the returned structure */ 498 rep = apr_pcalloc(pool, sizeof(*rep)); 499 500 /* KIND */ 501 if (svn_skel__matches_atom(header_skel->children, "fulltext")) 502 rep->kind = rep_kind_fulltext; 503 else 504 rep->kind = rep_kind_delta; 505 506 /* TXN */ 507 rep->txn_id = apr_pstrmemdup(pool, header_skel->children->next->data, 508 header_skel->children->next->len); 509 510 /* MD5 */ 511 if (header_skel->children->next->next) 512 { 513 svn_skel_t *checksum_skel = header_skel->children->next->next; 514 rep->md5_checksum = 515 svn_checksum__from_digest_md5((const unsigned char *) 516 (checksum_skel->children->next->data), 517 pool); 518 519 /* SHA1 */ 520 if (header_skel->children->next->next->next) 521 { 522 checksum_skel = header_skel->children->next->next->next; 523 rep->sha1_checksum = 524 svn_checksum__from_digest_sha1( 525 (const unsigned char *)(checksum_skel->children->next->data), 526 pool); 527 } 528 } 529 530 /* KIND-SPECIFIC stuff */ 531 if (rep->kind == rep_kind_fulltext) 532 { 533 /* "fulltext"-specific. */ 534 rep->contents.fulltext.string_key 535 = apr_pstrmemdup(pool, 536 skel->children->next->data, 537 skel->children->next->len); 538 } 539 else 540 { 541 /* "delta"-specific. */ 542 svn_skel_t *chunk_skel = skel->children->next; 543 rep_delta_chunk_t *chunk; 544 apr_array_header_t *chunks; 545 546 /* Alloc the chunk array. */ 547 chunks = apr_array_make(pool, svn_skel__list_length(skel) - 1, 548 sizeof(chunk)); 549 550 /* Process the chunks. */ 551 while (chunk_skel) 552 { 553 svn_skel_t *window_skel = chunk_skel->children->next; 554 svn_skel_t *diff_skel = window_skel->children; 555 apr_int64_t val; 556 apr_uint64_t uval; 557 const char *str; 558 559 /* Allocate a chunk and its window */ 560 chunk = apr_palloc(pool, sizeof(*chunk)); 561 562 /* Populate the window */ 563 str = apr_pstrmemdup(pool, diff_skel->children->next->data, 564 diff_skel->children->next->len); 565 SVN_ERR(svn_cstring_strtoui64(&uval, str, 0, 255, 10)); 566 chunk->version = (apr_byte_t)uval; 567 568 chunk->string_key 569 = apr_pstrmemdup(pool, 570 diff_skel->children->next->next->data, 571 diff_skel->children->next->next->len); 572 573 str = apr_pstrmemdup(pool, window_skel->children->next->data, 574 window_skel->children->next->len); 575 SVN_ERR(svn_cstring_strtoui64(&uval, str, 0, APR_SIZE_MAX, 10)); 576 chunk->size = (apr_size_t)uval; 577 578 chunk->rep_key 579 = apr_pstrmemdup(pool, 580 window_skel->children->next->next->data, 581 window_skel->children->next->next->len); 582 583 str = apr_pstrmemdup(pool, chunk_skel->children->data, 584 chunk_skel->children->len); 585 SVN_ERR(svn_cstring_strtoi64(&val, str, 0, APR_INT64_MAX, 10)); 586 chunk->offset = (svn_filesize_t)val; 587 588 /* Add this chunk to the array. */ 589 APR_ARRAY_PUSH(chunks, rep_delta_chunk_t *) = chunk; 590 591 /* Next... */ 592 chunk_skel = chunk_skel->next; 593 } 594 595 /* Add the chunks array to the representation. */ 596 rep->contents.delta.chunks = chunks; 597 } 598 599 /* Return the structure. */ 600 *rep_p = rep; 601 return SVN_NO_ERROR; 602} 603 604 605svn_error_t * 606svn_fs_base__parse_node_revision_skel(node_revision_t **noderev_p, 607 svn_skel_t *skel, 608 apr_pool_t *pool) 609{ 610 node_revision_t *noderev; 611 svn_skel_t *header_skel, *cur_skel; 612 613 /* Validate the skel. */ 614 if (! is_valid_node_revision_skel(skel)) 615 return skel_err("node-revision"); 616 header_skel = skel->children; 617 618 /* Create the returned structure */ 619 noderev = apr_pcalloc(pool, sizeof(*noderev)); 620 621 /* KIND */ 622 if (svn_skel__matches_atom(header_skel->children, "dir")) 623 noderev->kind = svn_node_dir; 624 else 625 noderev->kind = svn_node_file; 626 627 /* CREATED-PATH */ 628 noderev->created_path = apr_pstrmemdup(pool, 629 header_skel->children->next->data, 630 header_skel->children->next->len); 631 632 /* PREDECESSOR-ID */ 633 if (header_skel->children->next->next) 634 { 635 cur_skel = header_skel->children->next->next; 636 if (cur_skel->len) 637 noderev->predecessor_id = svn_fs_base__id_parse(cur_skel->data, 638 cur_skel->len, pool); 639 640 /* PREDECESSOR-COUNT */ 641 noderev->predecessor_count = -1; 642 if (cur_skel->next) 643 { 644 const char *str; 645 646 cur_skel = cur_skel->next; 647 if (cur_skel->len) 648 { 649 str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len); 650 SVN_ERR(svn_cstring_atoi(&noderev->predecessor_count, str)); 651 } 652 653 /* HAS-MERGEINFO and MERGEINFO-COUNT */ 654 if (cur_skel->next) 655 { 656 int val; 657 658 cur_skel = cur_skel->next; 659 str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len); 660 SVN_ERR(svn_cstring_atoi(&val, str)); 661 noderev->has_mergeinfo = (val != 0); 662 663 str = apr_pstrmemdup(pool, cur_skel->next->data, 664 cur_skel->next->len); 665 SVN_ERR(svn_cstring_atoi64(&noderev->mergeinfo_count, str)); 666 } 667 } 668 } 669 670 /* PROP-KEY */ 671 if (skel->children->next->len) 672 noderev->prop_key = apr_pstrmemdup(pool, skel->children->next->data, 673 skel->children->next->len); 674 675 /* DATA-KEY */ 676 if (skel->children->next->next->is_atom) 677 { 678 /* This is a real data rep key. */ 679 if (skel->children->next->next->len) 680 noderev->data_key = apr_pstrmemdup(pool, 681 skel->children->next->next->data, 682 skel->children->next->next->len); 683 noderev->data_key_uniquifier = NULL; 684 } 685 else 686 { 687 /* This is a 2-tuple with a data rep key and a uniquifier. */ 688 noderev->data_key = 689 apr_pstrmemdup(pool, 690 skel->children->next->next->children->data, 691 skel->children->next->next->children->len); 692 noderev->data_key_uniquifier = 693 apr_pstrmemdup(pool, 694 skel->children->next->next->children->next->data, 695 skel->children->next->next->children->next->len); 696 } 697 698 /* EDIT-DATA-KEY (optional, files only) */ 699 if ((noderev->kind == svn_node_file) 700 && skel->children->next->next->next 701 && skel->children->next->next->next->len) 702 noderev->edit_key 703 = apr_pstrmemdup(pool, skel->children->next->next->next->data, 704 skel->children->next->next->next->len); 705 706 /* Return the structure. */ 707 *noderev_p = noderev; 708 return SVN_NO_ERROR; 709} 710 711 712svn_error_t * 713svn_fs_base__parse_copy_skel(copy_t **copy_p, 714 svn_skel_t *skel, 715 apr_pool_t *pool) 716{ 717 copy_t *copy; 718 719 /* Validate the skel. */ 720 if (! is_valid_copy_skel(skel)) 721 return skel_err("copy"); 722 723 /* Create the returned structure */ 724 copy = apr_pcalloc(pool, sizeof(*copy)); 725 726 /* KIND */ 727 if (svn_skel__matches_atom(skel->children, "soft-copy")) 728 copy->kind = copy_kind_soft; 729 else 730 copy->kind = copy_kind_real; 731 732 /* SRC-PATH */ 733 copy->src_path = apr_pstrmemdup(pool, 734 skel->children->next->data, 735 skel->children->next->len); 736 737 /* SRC-TXN-ID */ 738 copy->src_txn_id = apr_pstrmemdup(pool, 739 skel->children->next->next->data, 740 skel->children->next->next->len); 741 742 /* DST-NODE-ID */ 743 copy->dst_noderev_id 744 = svn_fs_base__id_parse(skel->children->next->next->next->data, 745 skel->children->next->next->next->len, pool); 746 747 /* Return the structure. */ 748 *copy_p = copy; 749 return SVN_NO_ERROR; 750} 751 752 753svn_error_t * 754svn_fs_base__parse_entries_skel(apr_hash_t **entries_p, 755 svn_skel_t *skel, 756 apr_pool_t *pool) 757{ 758 apr_hash_t *entries = NULL; 759 int len = svn_skel__list_length(skel); 760 svn_skel_t *elt; 761 762 if (! (len >= 0)) 763 return skel_err("entries"); 764 765 if (len > 0) 766 { 767 /* Else, allocate a hash and populate it. */ 768 entries = apr_hash_make(pool); 769 770 /* Check entries are well-formed as we go along. */ 771 for (elt = skel->children; elt; elt = elt->next) 772 { 773 const char *name; 774 svn_fs_id_t *id; 775 776 /* ENTRY must be a list of two elements. */ 777 if (svn_skel__list_length(elt) != 2) 778 return skel_err("entries"); 779 780 /* Get the entry's name and ID. */ 781 name = apr_pstrmemdup(pool, elt->children->data, 782 elt->children->len); 783 id = svn_fs_base__id_parse(elt->children->next->data, 784 elt->children->next->len, pool); 785 786 /* Add the entry to the hash. */ 787 apr_hash_set(entries, name, elt->children->len, id); 788 } 789 } 790 791 /* Return the structure. */ 792 *entries_p = entries; 793 return SVN_NO_ERROR; 794} 795 796 797svn_error_t * 798svn_fs_base__parse_change_skel(change_t **change_p, 799 svn_skel_t *skel, 800 apr_pool_t *pool) 801{ 802 change_t *change; 803 svn_fs_path_change_kind_t kind; 804 805 /* Validate the skel. */ 806 if (! is_valid_change_skel(skel, &kind)) 807 return skel_err("change"); 808 809 /* Create the returned structure */ 810 change = apr_pcalloc(pool, sizeof(*change)); 811 812 /* PATH */ 813 change->path = apr_pstrmemdup(pool, skel->children->next->data, 814 skel->children->next->len); 815 816 /* NODE-REV-ID */ 817 if (skel->children->next->next->len) 818 change->noderev_id = svn_fs_base__id_parse 819 (skel->children->next->next->data, skel->children->next->next->len, 820 pool); 821 822 /* KIND */ 823 change->kind = kind; 824 825 /* TEXT-MOD */ 826 if (skel->children->next->next->next->next->len) 827 change->text_mod = TRUE; 828 829 /* PROP-MOD */ 830 if (skel->children->next->next->next->next->next->len) 831 change->prop_mod = TRUE; 832 833 /* Return the structure. */ 834 *change_p = change; 835 return SVN_NO_ERROR; 836} 837 838 839svn_error_t * 840svn_fs_base__parse_lock_skel(svn_lock_t **lock_p, 841 svn_skel_t *skel, 842 apr_pool_t *pool) 843{ 844 svn_lock_t *lock; 845 const char *timestr; 846 847 /* Validate the skel. */ 848 if (! is_valid_lock_skel(skel)) 849 return skel_err("lock"); 850 851 /* Create the returned structure */ 852 lock = apr_pcalloc(pool, sizeof(*lock)); 853 854 /* PATH */ 855 lock->path = apr_pstrmemdup(pool, skel->children->next->data, 856 skel->children->next->len); 857 858 /* LOCK-TOKEN */ 859 lock->token = apr_pstrmemdup(pool, 860 skel->children->next->next->data, 861 skel->children->next->next->len); 862 863 /* OWNER */ 864 lock->owner = apr_pstrmemdup(pool, 865 skel->children->next->next->next->data, 866 skel->children->next->next->next->len); 867 868 /* COMMENT (could be just an empty atom) */ 869 if (skel->children->next->next->next->next->len) 870 lock->comment = 871 apr_pstrmemdup(pool, 872 skel->children->next->next->next->next->data, 873 skel->children->next->next->next->next->len); 874 875 /* XML_P */ 876 if (svn_skel__matches_atom 877 (skel->children->next->next->next->next->next, "1")) 878 lock->is_dav_comment = TRUE; 879 else 880 lock->is_dav_comment = FALSE; 881 882 /* CREATION-DATE */ 883 timestr = apr_pstrmemdup 884 (pool, 885 skel->children->next->next->next->next->next->next->data, 886 skel->children->next->next->next->next->next->next->len); 887 SVN_ERR(svn_time_from_cstring(&(lock->creation_date), 888 timestr, pool)); 889 890 /* EXPIRATION-DATE (could be just an empty atom) */ 891 if (skel->children->next->next->next->next->next->next->next->len) 892 { 893 timestr = 894 apr_pstrmemdup 895 (pool, 896 skel->children->next->next->next->next->next->next->next->data, 897 skel->children->next->next->next->next->next->next->next->len); 898 SVN_ERR(svn_time_from_cstring(&(lock->expiration_date), 899 timestr, pool)); 900 } 901 902 /* Return the structure. */ 903 *lock_p = lock; 904 return SVN_NO_ERROR; 905} 906 907 908 909/*** Unparsing (conversion from native FS type to skeleton) ***/ 910 911svn_error_t * 912svn_fs_base__unparse_revision_skel(svn_skel_t **skel_p, 913 const revision_t *revision, 914 apr_pool_t *pool) 915{ 916 svn_skel_t *skel; 917 918 /* Create the skel. */ 919 skel = svn_skel__make_empty_list(pool); 920 921 /* TXN_ID */ 922 svn_skel__prepend(svn_skel__str_atom(revision->txn_id, pool), skel); 923 924 /* "revision" */ 925 svn_skel__prepend(svn_skel__str_atom("revision", pool), skel); 926 927 /* Validate and return the skel. */ 928 if (! is_valid_revision_skel(skel)) 929 return skel_err("revision"); 930 *skel_p = skel; 931 return SVN_NO_ERROR; 932} 933 934 935svn_error_t * 936svn_fs_base__unparse_transaction_skel(svn_skel_t **skel_p, 937 const transaction_t *transaction, 938 apr_pool_t *pool) 939{ 940 svn_skel_t *skel; 941 svn_skel_t *proplist_skel, *copies_skel, *header_skel; 942 svn_string_t *id_str; 943 transaction_kind_t kind; 944 945 /* Create the skel. */ 946 skel = svn_skel__make_empty_list(pool); 947 948 switch (transaction->kind) 949 { 950 case transaction_kind_committed: 951 header_skel = svn_skel__str_atom("committed", pool); 952 if ((transaction->base_id) 953 || (! SVN_IS_VALID_REVNUM(transaction->revision))) 954 return skel_err("transaction"); 955 break; 956 case transaction_kind_dead: 957 header_skel = svn_skel__str_atom("dead", pool); 958 if ((! transaction->base_id) 959 || (SVN_IS_VALID_REVNUM(transaction->revision))) 960 return skel_err("transaction"); 961 break; 962 case transaction_kind_normal: 963 header_skel = svn_skel__str_atom("transaction", pool); 964 if ((! transaction->base_id) 965 || (SVN_IS_VALID_REVNUM(transaction->revision))) 966 return skel_err("transaction"); 967 break; 968 default: 969 return skel_err("transaction"); 970 } 971 972 973 /* COPIES */ 974 copies_skel = svn_skel__make_empty_list(pool); 975 if (transaction->copies && transaction->copies->nelts) 976 { 977 int i; 978 for (i = transaction->copies->nelts - 1; i >= 0; i--) 979 { 980 svn_skel__prepend(svn_skel__str_atom( 981 APR_ARRAY_IDX(transaction->copies, i, 982 const char *), 983 pool), 984 copies_skel); 985 } 986 } 987 svn_skel__prepend(copies_skel, skel); 988 989 /* PROPLIST */ 990 SVN_ERR(svn_skel__unparse_proplist(&proplist_skel, 991 transaction->proplist, pool)); 992 svn_skel__prepend(proplist_skel, skel); 993 994 /* REVISION or BASE-ID */ 995 if (transaction->kind == transaction_kind_committed) 996 { 997 /* Committed transactions have a revision number... */ 998 svn_skel__prepend(svn_skel__str_atom(apr_psprintf(pool, "%ld", 999 transaction->revision), 1000 pool), skel); 1001 } 1002 else 1003 { 1004 /* ...where other transactions have a base node revision ID. */ 1005 id_str = svn_fs_base__id_unparse(transaction->base_id, pool); 1006 svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool), 1007 skel); 1008 } 1009 1010 /* ROOT-ID */ 1011 id_str = svn_fs_base__id_unparse(transaction->root_id, pool); 1012 svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool), skel); 1013 1014 /* KIND (see above) */ 1015 svn_skel__prepend(header_skel, skel); 1016 1017 /* Validate and return the skel. */ 1018 if (! is_valid_transaction_skel(skel, &kind)) 1019 return skel_err("transaction"); 1020 if (kind != transaction->kind) 1021 return skel_err("transaction"); 1022 *skel_p = skel; 1023 return SVN_NO_ERROR; 1024} 1025 1026 1027/* Construct a skel representing CHECKSUM, allocated in POOL, and prepend 1028 * it onto the existing skel SKEL. */ 1029static svn_error_t * 1030prepend_checksum(svn_skel_t *skel, 1031 svn_checksum_t *checksum, 1032 apr_pool_t *pool) 1033{ 1034 svn_skel_t *checksum_skel = svn_skel__make_empty_list(pool); 1035 1036 switch (checksum->kind) 1037 { 1038 case svn_checksum_md5: 1039 svn_skel__prepend(svn_skel__mem_atom(checksum->digest, 1040 APR_MD5_DIGESTSIZE, pool), 1041 checksum_skel); 1042 svn_skel__prepend(svn_skel__str_atom("md5", pool), checksum_skel); 1043 break; 1044 1045 case svn_checksum_sha1: 1046 svn_skel__prepend(svn_skel__mem_atom(checksum->digest, 1047 APR_SHA1_DIGESTSIZE, pool), 1048 checksum_skel); 1049 svn_skel__prepend(svn_skel__str_atom("sha1", pool), checksum_skel); 1050 break; 1051 1052 default: 1053 return skel_err("checksum"); 1054 } 1055 svn_skel__prepend(checksum_skel, skel); 1056 1057 return SVN_NO_ERROR; 1058} 1059 1060 1061svn_error_t * 1062svn_fs_base__unparse_representation_skel(svn_skel_t **skel_p, 1063 const representation_t *rep, 1064 int format, 1065 apr_pool_t *pool) 1066{ 1067 svn_skel_t *skel = svn_skel__make_empty_list(pool); 1068 svn_skel_t *header_skel = svn_skel__make_empty_list(pool); 1069 1070 /** Some parts of the header are common to all representations; do 1071 those parts first. **/ 1072 1073 /* SHA1 */ 1074 if ((format >= SVN_FS_BASE__MIN_REP_SHARING_FORMAT) && rep->sha1_checksum) 1075 SVN_ERR(prepend_checksum(header_skel, rep->sha1_checksum, pool)); 1076 1077 /* MD5 */ 1078 { 1079 svn_checksum_t *md5_checksum = rep->md5_checksum; 1080 if (! md5_checksum) 1081 md5_checksum = svn_checksum_create(svn_checksum_md5, pool); 1082 SVN_ERR(prepend_checksum(header_skel, md5_checksum, pool)); 1083 } 1084 1085 /* TXN */ 1086 if (rep->txn_id) 1087 svn_skel__prepend(svn_skel__str_atom(rep->txn_id, pool), header_skel); 1088 else 1089 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel); 1090 1091 /** Do the kind-specific stuff. **/ 1092 1093 if (rep->kind == rep_kind_fulltext) 1094 { 1095 /*** Fulltext Representation. ***/ 1096 1097 /* STRING-KEY */ 1098 if ((! rep->contents.fulltext.string_key) 1099 || (! *rep->contents.fulltext.string_key)) 1100 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1101 else 1102 svn_skel__prepend(svn_skel__str_atom(rep->contents.fulltext.string_key, 1103 pool), skel); 1104 1105 /* "fulltext" */ 1106 svn_skel__prepend(svn_skel__str_atom("fulltext", pool), header_skel); 1107 1108 /* header */ 1109 svn_skel__prepend(header_skel, skel); 1110 } 1111 else if (rep->kind == rep_kind_delta) 1112 { 1113 /*** Delta Representation. ***/ 1114 int i; 1115 apr_array_header_t *chunks = rep->contents.delta.chunks; 1116 1117 /* Loop backwards through the windows, creating and prepending skels. */ 1118 for (i = chunks->nelts; i > 0; i--) 1119 { 1120 svn_skel_t *window_skel = svn_skel__make_empty_list(pool); 1121 svn_skel_t *chunk_skel = svn_skel__make_empty_list(pool); 1122 svn_skel_t *diff_skel = svn_skel__make_empty_list(pool); 1123 const char *size_str, *offset_str, *version_str; 1124 rep_delta_chunk_t *chunk = APR_ARRAY_IDX(chunks, i - 1, 1125 rep_delta_chunk_t *); 1126 1127 /* OFFSET */ 1128 offset_str = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT, 1129 chunk->offset); 1130 1131 /* SIZE */ 1132 size_str = apr_psprintf(pool, "%" APR_SIZE_T_FMT, chunk->size); 1133 1134 /* VERSION */ 1135 version_str = apr_psprintf(pool, "%d", chunk->version); 1136 1137 /* DIFF */ 1138 if ((! chunk->string_key) || (! *chunk->string_key)) 1139 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), diff_skel); 1140 else 1141 svn_skel__prepend(svn_skel__str_atom(chunk->string_key, pool), 1142 diff_skel); 1143 svn_skel__prepend(svn_skel__str_atom(version_str, pool), diff_skel); 1144 svn_skel__prepend(svn_skel__str_atom("svndiff", pool), diff_skel); 1145 1146 /* REP-KEY */ 1147 if ((! chunk->rep_key) || (! *(chunk->rep_key))) 1148 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), 1149 window_skel); 1150 else 1151 svn_skel__prepend(svn_skel__str_atom(chunk->rep_key, pool), 1152 window_skel); 1153 svn_skel__prepend(svn_skel__str_atom(size_str, pool), window_skel); 1154 svn_skel__prepend(diff_skel, window_skel); 1155 1156 /* window header. */ 1157 svn_skel__prepend(window_skel, chunk_skel); 1158 svn_skel__prepend(svn_skel__str_atom(offset_str, pool), 1159 chunk_skel); 1160 1161 /* Add this window item to the main skel. */ 1162 svn_skel__prepend(chunk_skel, skel); 1163 } 1164 1165 /* "delta" */ 1166 svn_skel__prepend(svn_skel__str_atom("delta", pool), header_skel); 1167 1168 /* header */ 1169 svn_skel__prepend(header_skel, skel); 1170 } 1171 else /* unknown kind */ 1172 SVN_ERR_MALFUNCTION(); 1173 1174 /* Validate and return the skel. */ 1175 if (! is_valid_representation_skel(skel)) 1176 return skel_err("representation"); 1177 *skel_p = skel; 1178 return SVN_NO_ERROR; 1179} 1180 1181 1182svn_error_t * 1183svn_fs_base__unparse_node_revision_skel(svn_skel_t **skel_p, 1184 const node_revision_t *noderev, 1185 int format, 1186 apr_pool_t *pool) 1187{ 1188 svn_skel_t *skel; 1189 svn_skel_t *header_skel; 1190 const char *num_str; 1191 1192 /* Create the skel. */ 1193 skel = svn_skel__make_empty_list(pool); 1194 header_skel = svn_skel__make_empty_list(pool); 1195 1196 /* Store mergeinfo stuffs only if the schema level supports it. */ 1197 if (format >= SVN_FS_BASE__MIN_MERGEINFO_FORMAT) 1198 { 1199 /* MERGEINFO-COUNT */ 1200 num_str = apr_psprintf(pool, "%" APR_INT64_T_FMT, 1201 noderev->mergeinfo_count); 1202 svn_skel__prepend(svn_skel__str_atom(num_str, pool), header_skel); 1203 1204 /* HAS-MERGEINFO */ 1205 svn_skel__prepend(svn_skel__mem_atom(noderev->has_mergeinfo ? "1" : "0", 1206 1, pool), header_skel); 1207 1208 /* PREDECESSOR-COUNT padding (only if we *don't* have a valid 1209 value; if we do, we'll pick that up below) */ 1210 if (noderev->predecessor_count == -1) 1211 { 1212 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel); 1213 } 1214 } 1215 1216 /* PREDECESSOR-COUNT */ 1217 if (noderev->predecessor_count != -1) 1218 { 1219 const char *count_str = apr_psprintf(pool, "%d", 1220 noderev->predecessor_count); 1221 svn_skel__prepend(svn_skel__str_atom(count_str, pool), header_skel); 1222 } 1223 1224 /* PREDECESSOR-ID */ 1225 if (noderev->predecessor_id) 1226 { 1227 svn_string_t *id_str = svn_fs_base__id_unparse(noderev->predecessor_id, 1228 pool); 1229 svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool), 1230 header_skel); 1231 } 1232 else 1233 { 1234 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel); 1235 } 1236 1237 /* CREATED-PATH */ 1238 svn_skel__prepend(svn_skel__str_atom(noderev->created_path, pool), 1239 header_skel); 1240 1241 /* KIND */ 1242 if (noderev->kind == svn_node_file) 1243 svn_skel__prepend(svn_skel__str_atom("file", pool), header_skel); 1244 else if (noderev->kind == svn_node_dir) 1245 svn_skel__prepend(svn_skel__str_atom("dir", pool), header_skel); 1246 else 1247 SVN_ERR_MALFUNCTION(); 1248 1249 /* ### do we really need to check *node->FOO_key ? if a key doesn't 1250 ### exist, then the field should be NULL ... */ 1251 1252 /* EDIT-DATA-KEY (optional) */ 1253 if ((noderev->edit_key) && (*noderev->edit_key)) 1254 svn_skel__prepend(svn_skel__str_atom(noderev->edit_key, pool), skel); 1255 1256 /* DATA-KEY | (DATA-KEY DATA-KEY-UNIQID) */ 1257 if ((noderev->data_key_uniquifier) && (*noderev->data_key_uniquifier)) 1258 { 1259 /* Build a 2-tuple with a rep key and uniquifier. */ 1260 svn_skel_t *data_key_skel = svn_skel__make_empty_list(pool); 1261 1262 /* DATA-KEY-UNIQID */ 1263 svn_skel__prepend(svn_skel__str_atom(noderev->data_key_uniquifier, 1264 pool), 1265 data_key_skel); 1266 1267 /* DATA-KEY */ 1268 if ((noderev->data_key) && (*noderev->data_key)) 1269 svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool), 1270 data_key_skel); 1271 else 1272 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), data_key_skel); 1273 1274 /* Add our 2-tuple to the main skel. */ 1275 svn_skel__prepend(data_key_skel, skel); 1276 } 1277 else 1278 { 1279 /* Just store the rep key (or empty placeholder) in the main skel. */ 1280 if ((noderev->data_key) && (*noderev->data_key)) 1281 svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool), skel); 1282 else 1283 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1284 } 1285 1286 /* PROP-KEY */ 1287 if ((noderev->prop_key) && (*noderev->prop_key)) 1288 svn_skel__prepend(svn_skel__str_atom(noderev->prop_key, pool), skel); 1289 else 1290 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1291 1292 /* HEADER */ 1293 svn_skel__prepend(header_skel, skel); 1294 1295 /* Validate and return the skel. */ 1296 if (! is_valid_node_revision_skel(skel)) 1297 return skel_err("node-revision"); 1298 *skel_p = skel; 1299 return SVN_NO_ERROR; 1300} 1301 1302 1303svn_error_t * 1304svn_fs_base__unparse_copy_skel(svn_skel_t **skel_p, 1305 const copy_t *copy, 1306 apr_pool_t *pool) 1307{ 1308 svn_skel_t *skel; 1309 svn_string_t *tmp_str; 1310 1311 /* Create the skel. */ 1312 skel = svn_skel__make_empty_list(pool); 1313 1314 /* DST-NODE-ID */ 1315 tmp_str = svn_fs_base__id_unparse(copy->dst_noderev_id, pool); 1316 svn_skel__prepend(svn_skel__mem_atom(tmp_str->data, tmp_str->len, pool), 1317 skel); 1318 1319 /* SRC-TXN-ID */ 1320 if ((copy->src_txn_id) && (*copy->src_txn_id)) 1321 svn_skel__prepend(svn_skel__str_atom(copy->src_txn_id, pool), skel); 1322 else 1323 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1324 1325 /* SRC-PATH */ 1326 if ((copy->src_path) && (*copy->src_path)) 1327 svn_skel__prepend(svn_skel__str_atom(copy->src_path, pool), skel); 1328 else 1329 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1330 1331 /* "copy" */ 1332 if (copy->kind == copy_kind_real) 1333 svn_skel__prepend(svn_skel__str_atom("copy", pool), skel); 1334 else 1335 svn_skel__prepend(svn_skel__str_atom("soft-copy", pool), skel); 1336 1337 /* Validate and return the skel. */ 1338 if (! is_valid_copy_skel(skel)) 1339 return skel_err("copy"); 1340 *skel_p = skel; 1341 return SVN_NO_ERROR; 1342} 1343 1344 1345svn_error_t * 1346svn_fs_base__unparse_entries_skel(svn_skel_t **skel_p, 1347 apr_hash_t *entries, 1348 apr_pool_t *pool) 1349{ 1350 svn_skel_t *skel = svn_skel__make_empty_list(pool); 1351 apr_hash_index_t *hi; 1352 1353 /* Create the skel. */ 1354 if (entries) 1355 { 1356 /* Loop over hash entries */ 1357 for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) 1358 { 1359 const void *key; 1360 void *val; 1361 apr_ssize_t klen; 1362 svn_fs_id_t *value; 1363 svn_string_t *id_str; 1364 svn_skel_t *entry_skel = svn_skel__make_empty_list(pool); 1365 1366 apr_hash_this(hi, &key, &klen, &val); 1367 value = val; 1368 1369 /* VALUE */ 1370 id_str = svn_fs_base__id_unparse(value, pool); 1371 svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, 1372 pool), 1373 entry_skel); 1374 1375 /* NAME */ 1376 svn_skel__prepend(svn_skel__mem_atom(key, klen, pool), entry_skel); 1377 1378 /* Add entry to the entries skel. */ 1379 svn_skel__prepend(entry_skel, skel); 1380 } 1381 } 1382 1383 /* Return the skel. */ 1384 *skel_p = skel; 1385 return SVN_NO_ERROR; 1386} 1387 1388 1389svn_error_t * 1390svn_fs_base__unparse_change_skel(svn_skel_t **skel_p, 1391 const change_t *change, 1392 apr_pool_t *pool) 1393{ 1394 svn_skel_t *skel; 1395 svn_string_t *tmp_str; 1396 svn_fs_path_change_kind_t kind; 1397 1398 /* Create the skel. */ 1399 skel = svn_skel__make_empty_list(pool); 1400 1401 /* PROP-MOD */ 1402 if (change->prop_mod) 1403 svn_skel__prepend(svn_skel__str_atom("1", pool), skel); 1404 else 1405 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1406 1407 /* TEXT-MOD */ 1408 if (change->text_mod) 1409 svn_skel__prepend(svn_skel__str_atom("1", pool), skel); 1410 else 1411 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1412 1413 /* KIND */ 1414 switch (change->kind) 1415 { 1416 case svn_fs_path_change_reset: 1417 svn_skel__prepend(svn_skel__str_atom("reset", pool), skel); 1418 break; 1419 case svn_fs_path_change_add: 1420 svn_skel__prepend(svn_skel__str_atom("add", pool), skel); 1421 break; 1422 case svn_fs_path_change_delete: 1423 svn_skel__prepend(svn_skel__str_atom("delete", pool), skel); 1424 break; 1425 case svn_fs_path_change_replace: 1426 svn_skel__prepend(svn_skel__str_atom("replace", pool), skel); 1427 break; 1428 case svn_fs_path_change_modify: 1429 default: 1430 svn_skel__prepend(svn_skel__str_atom("modify", pool), skel); 1431 break; 1432 } 1433 1434 /* NODE-REV-ID */ 1435 if (change->noderev_id) 1436 { 1437 tmp_str = svn_fs_base__id_unparse(change->noderev_id, pool); 1438 svn_skel__prepend(svn_skel__mem_atom(tmp_str->data, tmp_str->len, pool), 1439 skel); 1440 } 1441 else 1442 { 1443 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1444 } 1445 1446 /* PATH */ 1447 svn_skel__prepend(svn_skel__str_atom(change->path, pool), skel); 1448 1449 /* "change" */ 1450 svn_skel__prepend(svn_skel__str_atom("change", pool), skel); 1451 1452 /* Validate and return the skel. */ 1453 if (! is_valid_change_skel(skel, &kind)) 1454 return skel_err("change"); 1455 if (kind != change->kind) 1456 return skel_err("change"); 1457 *skel_p = skel; 1458 return SVN_NO_ERROR; 1459} 1460 1461 1462svn_error_t * 1463svn_fs_base__unparse_lock_skel(svn_skel_t **skel_p, 1464 const svn_lock_t *lock, 1465 apr_pool_t *pool) 1466{ 1467 svn_skel_t *skel; 1468 1469 /* Create the skel. */ 1470 skel = svn_skel__make_empty_list(pool); 1471 1472 /* EXP-DATE is optional. If not present, just use an empty atom. */ 1473 if (lock->expiration_date) 1474 svn_skel__prepend(svn_skel__str_atom( 1475 svn_time_to_cstring(lock->expiration_date, pool), 1476 pool), skel); 1477 else 1478 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1479 1480 /* CREATION-DATE */ 1481 svn_skel__prepend(svn_skel__str_atom( 1482 svn_time_to_cstring(lock->creation_date, pool), 1483 pool), skel); 1484 1485 /* XML_P */ 1486 if (lock->is_dav_comment) 1487 svn_skel__prepend(svn_skel__str_atom("1", pool), skel); 1488 else 1489 svn_skel__prepend(svn_skel__str_atom("0", pool), skel); 1490 1491 /* COMMENT */ 1492 if (lock->comment) 1493 svn_skel__prepend(svn_skel__str_atom(lock->comment, pool), skel); 1494 else 1495 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel); 1496 1497 /* OWNER */ 1498 svn_skel__prepend(svn_skel__str_atom(lock->owner, pool), skel); 1499 1500 /* LOCK-TOKEN */ 1501 svn_skel__prepend(svn_skel__str_atom(lock->token, pool), skel); 1502 1503 /* PATH */ 1504 svn_skel__prepend(svn_skel__str_atom(lock->path, pool), skel); 1505 1506 /* "lock" */ 1507 svn_skel__prepend(svn_skel__str_atom("lock", pool), skel); 1508 1509 /* Validate and return the skel. */ 1510 if (! is_valid_lock_skel(skel)) 1511 return skel_err("lock"); 1512 1513 *skel_p = skel; 1514 return SVN_NO_ERROR; 1515} 1516