1 /* fs_skels.c --- conversion between fs native types and skeletons
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
20 * ====================================================================
28 #include "svn_error.h"
29 #include "svn_string.h"
30 #include "svn_types.h"
33 #include "private/svn_skel.h"
34 #include "private/svn_dep_compat.h"
35 #include "private/svn_subr_private.h"
37 #include "svn_checksum.h"
43 skel_err(const char *skel_type)
45 return svn_error_createf(SVN_ERR_FS_MALFORMED_SKEL, NULL,
46 "Malformed%s%s skeleton",
48 skel_type ? skel_type : "");
53 /*** Validity Checking ***/
56 is_valid_checksum_skel(svn_skel_t *skel)
58 if (svn_skel__list_length(skel) != 2)
61 if (svn_skel__matches_atom(skel->children, "md5")
62 && skel->children->next->is_atom)
65 if (svn_skel__matches_atom(skel->children, "sha1")
66 && skel->children->next->is_atom)
74 is_valid_revision_skel(svn_skel_t *skel)
76 int len = svn_skel__list_length(skel);
79 && svn_skel__matches_atom(skel->children, "revision")
80 && skel->children->next->is_atom)
88 is_valid_transaction_skel(svn_skel_t *skel, transaction_kind_t *kind)
90 int len = svn_skel__list_length(skel);
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;
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))
116 is_valid_rep_delta_chunk_skel(svn_skel_t *skel)
122 /* check the delta skel. */
123 if ((svn_skel__list_length(skel) != 2)
124 || (! skel->children->is_atom))
127 /* check the window. */
128 window = skel->children->next;
129 len = svn_skel__list_length(window);
130 if ((len < 3) || (len > 4))
132 if (! ((! window->children->is_atom)
133 && (window->children->next->is_atom)
134 && (window->children->next->next->is_atom)))
137 && (! window->children->next->next->next->is_atom))
140 /* check the diff. ### currently we support only svndiff version
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))
155 is_valid_representation_skel(svn_skel_t *skel)
157 int len = svn_skel__list_length(skel);
161 /* the rep has at least two items in it, a HEADER list, and at least
162 one piece of kind-specific data. */
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)))))
184 /* check for fulltext rep. */
186 && (svn_skel__matches_atom(header->children, "fulltext")))
189 /* check for delta rep. */
191 && (svn_skel__matches_atom(header->children, "delta")))
193 /* it's a delta rep. check the validity. */
194 svn_skel_t *chunk = skel->children->next;
196 /* loop over chunks, checking each one. */
199 if (! is_valid_rep_delta_chunk_skel(chunk))
204 /* all good on this delta rep. */
213 is_valid_node_revision_header_skel(svn_skel_t *skel, svn_skel_t **kind_p)
215 int len = svn_skel__list_length(skel);
220 /* set the *KIND_P pointer. */
221 *kind_p = skel->children;
223 /* check for valid lengths. */
224 if (! ((len == 2) || (len == 3) || (len == 4) || (len == 6)))
227 /* got mergeinfo stuff? */
229 && (! (skel->children->next->next->next->next->is_atom
230 && skel->children->next->next->next->next->next->is_atom)))
233 /* got predecessor count? */
235 && (! skel->children->next->next->next->is_atom))
238 /* got predecessor? */
240 && (! skel->children->next->next->is_atom))
243 /* got the basics? */
244 if (! (skel->children->is_atom
245 && skel->children->next->is_atom
246 && (skel->children->next->data[0] == '/')))
254 is_valid_node_revision_skel(svn_skel_t *skel)
256 int len = svn_skel__list_length(skel);
257 svn_skel_t *header = skel->children;
263 if (! is_valid_node_revision_header_skel(header, &kind))
266 if (svn_skel__matches_atom(kind, "dir"))
269 && header->next->is_atom
270 && header->next->next->is_atom))
273 else if (svn_skel__matches_atom(kind, "file"))
278 if (! header->next->is_atom)
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)
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))
293 if ((len > 3) && (! header->next->next->next->is_atom))
305 is_valid_copy_skel(svn_skel_t *skel)
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);
317 is_valid_change_skel(svn_skel_t *skel, svn_fs_path_change_kind_t *kind)
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)
327 svn_skel_t *kind_skel = skel->children->next->next->next;
329 /* check the kind (and return it) */
330 if (svn_skel__matches_atom(kind_skel, "reset"))
333 *kind = svn_fs_path_change_reset;
336 if (svn_skel__matches_atom(kind_skel, "add"))
339 *kind = svn_fs_path_change_add;
342 if (svn_skel__matches_atom(kind_skel, "delete"))
345 *kind = svn_fs_path_change_delete;
348 if (svn_skel__matches_atom(kind_skel, "replace"))
351 *kind = svn_fs_path_change_replace;
354 if (svn_skel__matches_atom(kind_skel, "modify"))
357 *kind = svn_fs_path_change_modify;
366 is_valid_lock_skel(svn_skel_t *skel)
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)
384 /*** Parsing (conversion from skeleton to native FS type) ***/
387 svn_fs_base__parse_revision_skel(revision_t **revision_p,
391 revision_t *revision;
393 /* Validate the skel. */
394 if (! is_valid_revision_skel(skel))
395 return skel_err("revision");
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);
402 /* Return the structure. */
403 *revision_p = revision;
409 svn_fs_base__parse_transaction_skel(transaction_t **transaction_p,
413 transaction_t *transaction;
414 transaction_kind_t kind;
415 svn_skel_t *root_id, *base_id_or_rev, *proplist, *copies;
418 /* Validate the skel. */
419 if (! is_valid_transaction_skel(skel, &kind))
420 return skel_err("transaction");
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;
427 /* Create the returned structure */
428 transaction = apr_pcalloc(pool, sizeof(*transaction));
431 transaction->kind = kind;
433 /* REVISION or BASE-ID */
434 if (kind == transaction_kind_committed)
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");
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);
454 transaction->root_id = svn_fs_base__id_parse(root_id->data,
458 SVN_ERR(svn_skel__parse_proplist(&(transaction->proplist),
462 if ((len = svn_skel__list_length(copies)))
465 apr_array_header_t *txncopies;
466 svn_skel_t *cpy = copies->children;
468 txncopies = apr_array_make(pool, len, sizeof(copy_id));
471 copy_id = apr_pstrmemdup(pool, cpy->data, cpy->len);
472 APR_ARRAY_PUSH(txncopies, const char *) = copy_id;
475 transaction->copies = txncopies;
478 /* Return the structure. */
479 *transaction_p = transaction;
485 svn_fs_base__parse_representation_skel(representation_t **rep_p,
489 representation_t *rep;
490 svn_skel_t *header_skel;
492 /* Validate the skel. */
493 if (! is_valid_representation_skel(skel))
494 return skel_err("representation");
495 header_skel = skel->children;
497 /* Create the returned structure */
498 rep = apr_pcalloc(pool, sizeof(*rep));
501 if (svn_skel__matches_atom(header_skel->children, "fulltext"))
502 rep->kind = rep_kind_fulltext;
504 rep->kind = rep_kind_delta;
507 rep->txn_id = apr_pstrmemdup(pool, header_skel->children->next->data,
508 header_skel->children->next->len);
511 if (header_skel->children->next->next)
513 svn_skel_t *checksum_skel = header_skel->children->next->next;
515 svn_checksum__from_digest_md5((const unsigned char *)
516 (checksum_skel->children->next->data),
520 if (header_skel->children->next->next->next)
522 checksum_skel = header_skel->children->next->next->next;
524 svn_checksum__from_digest_sha1(
525 (const unsigned char *)(checksum_skel->children->next->data),
530 /* KIND-SPECIFIC stuff */
531 if (rep->kind == rep_kind_fulltext)
533 /* "fulltext"-specific. */
534 rep->contents.fulltext.string_key
535 = apr_pstrmemdup(pool,
536 skel->children->next->data,
537 skel->children->next->len);
541 /* "delta"-specific. */
542 svn_skel_t *chunk_skel = skel->children->next;
543 rep_delta_chunk_t *chunk;
544 apr_array_header_t *chunks;
546 /* Alloc the chunk array. */
547 chunks = apr_array_make(pool, svn_skel__list_length(skel) - 1,
550 /* Process the chunks. */
553 svn_skel_t *window_skel = chunk_skel->children->next;
554 svn_skel_t *diff_skel = window_skel->children;
559 /* Allocate a chunk and its window */
560 chunk = apr_palloc(pool, sizeof(*chunk));
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;
569 = apr_pstrmemdup(pool,
570 diff_skel->children->next->next->data,
571 diff_skel->children->next->next->len);
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;
579 = apr_pstrmemdup(pool,
580 window_skel->children->next->next->data,
581 window_skel->children->next->next->len);
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;
588 /* Add this chunk to the array. */
589 APR_ARRAY_PUSH(chunks, rep_delta_chunk_t *) = chunk;
592 chunk_skel = chunk_skel->next;
595 /* Add the chunks array to the representation. */
596 rep->contents.delta.chunks = chunks;
599 /* Return the structure. */
606 svn_fs_base__parse_node_revision_skel(node_revision_t **noderev_p,
610 node_revision_t *noderev;
611 svn_skel_t *header_skel, *cur_skel;
613 /* Validate the skel. */
614 if (! is_valid_node_revision_skel(skel))
615 return skel_err("node-revision");
616 header_skel = skel->children;
618 /* Create the returned structure */
619 noderev = apr_pcalloc(pool, sizeof(*noderev));
622 if (svn_skel__matches_atom(header_skel->children, "dir"))
623 noderev->kind = svn_node_dir;
625 noderev->kind = svn_node_file;
628 noderev->created_path = apr_pstrmemdup(pool,
629 header_skel->children->next->data,
630 header_skel->children->next->len);
633 if (header_skel->children->next->next)
635 cur_skel = header_skel->children->next->next;
637 noderev->predecessor_id = svn_fs_base__id_parse(cur_skel->data,
638 cur_skel->len, pool);
640 /* PREDECESSOR-COUNT */
641 noderev->predecessor_count = -1;
646 cur_skel = cur_skel->next;
649 str = apr_pstrmemdup(pool, cur_skel->data, cur_skel->len);
650 SVN_ERR(svn_cstring_atoi(&noderev->predecessor_count, str));
653 /* HAS-MERGEINFO and MERGEINFO-COUNT */
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);
663 str = apr_pstrmemdup(pool, cur_skel->next->data,
664 cur_skel->next->len);
665 SVN_ERR(svn_cstring_atoi64(&noderev->mergeinfo_count, str));
671 if (skel->children->next->len)
672 noderev->prop_key = apr_pstrmemdup(pool, skel->children->next->data,
673 skel->children->next->len);
676 if (skel->children->next->next->is_atom)
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;
687 /* This is a 2-tuple with a data rep key and a uniquifier. */
690 skel->children->next->next->children->data,
691 skel->children->next->next->children->len);
692 noderev->data_key_uniquifier =
694 skel->children->next->next->children->next->data,
695 skel->children->next->next->children->next->len);
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)
703 = apr_pstrmemdup(pool, skel->children->next->next->next->data,
704 skel->children->next->next->next->len);
706 /* Return the structure. */
707 *noderev_p = noderev;
713 svn_fs_base__parse_copy_skel(copy_t **copy_p,
719 /* Validate the skel. */
720 if (! is_valid_copy_skel(skel))
721 return skel_err("copy");
723 /* Create the returned structure */
724 copy = apr_pcalloc(pool, sizeof(*copy));
727 if (svn_skel__matches_atom(skel->children, "soft-copy"))
728 copy->kind = copy_kind_soft;
730 copy->kind = copy_kind_real;
733 copy->src_path = apr_pstrmemdup(pool,
734 skel->children->next->data,
735 skel->children->next->len);
738 copy->src_txn_id = apr_pstrmemdup(pool,
739 skel->children->next->next->data,
740 skel->children->next->next->len);
744 = svn_fs_base__id_parse(skel->children->next->next->next->data,
745 skel->children->next->next->next->len, pool);
747 /* Return the structure. */
754 svn_fs_base__parse_entries_skel(apr_hash_t **entries_p,
758 apr_hash_t *entries = NULL;
759 int len = svn_skel__list_length(skel);
763 return skel_err("entries");
767 /* Else, allocate a hash and populate it. */
768 entries = apr_hash_make(pool);
770 /* Check entries are well-formed as we go along. */
771 for (elt = skel->children; elt; elt = elt->next)
776 /* ENTRY must be a list of two elements. */
777 if (svn_skel__list_length(elt) != 2)
778 return skel_err("entries");
780 /* Get the entry's name and ID. */
781 name = apr_pstrmemdup(pool, elt->children->data,
783 id = svn_fs_base__id_parse(elt->children->next->data,
784 elt->children->next->len, pool);
786 /* Add the entry to the hash. */
787 apr_hash_set(entries, name, elt->children->len, id);
791 /* Return the structure. */
792 *entries_p = entries;
798 svn_fs_base__parse_change_skel(change_t **change_p,
803 svn_fs_path_change_kind_t kind;
805 /* Validate the skel. */
806 if (! is_valid_change_skel(skel, &kind))
807 return skel_err("change");
809 /* Create the returned structure */
810 change = apr_pcalloc(pool, sizeof(*change));
813 change->path = apr_pstrmemdup(pool, skel->children->next->data,
814 skel->children->next->len);
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,
826 if (skel->children->next->next->next->next->len)
827 change->text_mod = TRUE;
830 if (skel->children->next->next->next->next->next->len)
831 change->prop_mod = TRUE;
833 /* Return the structure. */
840 svn_fs_base__parse_lock_skel(svn_lock_t **lock_p,
847 /* Validate the skel. */
848 if (! is_valid_lock_skel(skel))
849 return skel_err("lock");
851 /* Create the returned structure */
852 lock = apr_pcalloc(pool, sizeof(*lock));
855 lock->path = apr_pstrmemdup(pool, skel->children->next->data,
856 skel->children->next->len);
859 lock->token = apr_pstrmemdup(pool,
860 skel->children->next->next->data,
861 skel->children->next->next->len);
864 lock->owner = apr_pstrmemdup(pool,
865 skel->children->next->next->next->data,
866 skel->children->next->next->next->len);
868 /* COMMENT (could be just an empty atom) */
869 if (skel->children->next->next->next->next->len)
872 skel->children->next->next->next->next->data,
873 skel->children->next->next->next->next->len);
876 if (svn_skel__matches_atom
877 (skel->children->next->next->next->next->next, "1"))
878 lock->is_dav_comment = TRUE;
880 lock->is_dav_comment = FALSE;
883 timestr = apr_pstrmemdup
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),
890 /* EXPIRATION-DATE (could be just an empty atom) */
891 if (skel->children->next->next->next->next->next->next->next->len)
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),
902 /* Return the structure. */
909 /*** Unparsing (conversion from native FS type to skeleton) ***/
912 svn_fs_base__unparse_revision_skel(svn_skel_t **skel_p,
913 const revision_t *revision,
918 /* Create the skel. */
919 skel = svn_skel__make_empty_list(pool);
922 svn_skel__prepend(svn_skel__str_atom(revision->txn_id, pool), skel);
925 svn_skel__prepend(svn_skel__str_atom("revision", pool), skel);
927 /* Validate and return the skel. */
928 if (! is_valid_revision_skel(skel))
929 return skel_err("revision");
936 svn_fs_base__unparse_transaction_skel(svn_skel_t **skel_p,
937 const transaction_t *transaction,
941 svn_skel_t *proplist_skel, *copies_skel, *header_skel;
942 svn_string_t *id_str;
943 transaction_kind_t kind;
945 /* Create the skel. */
946 skel = svn_skel__make_empty_list(pool);
948 switch (transaction->kind)
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");
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");
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");
969 return skel_err("transaction");
974 copies_skel = svn_skel__make_empty_list(pool);
975 if (transaction->copies && transaction->copies->nelts)
978 for (i = transaction->copies->nelts - 1; i >= 0; i--)
980 svn_skel__prepend(svn_skel__str_atom(
981 APR_ARRAY_IDX(transaction->copies, i,
987 svn_skel__prepend(copies_skel, skel);
990 SVN_ERR(svn_skel__unparse_proplist(&proplist_skel,
991 transaction->proplist, pool));
992 svn_skel__prepend(proplist_skel, skel);
994 /* REVISION or BASE-ID */
995 if (transaction->kind == transaction_kind_committed)
997 /* Committed transactions have a revision number... */
998 svn_skel__prepend(svn_skel__str_atom(apr_psprintf(pool, "%ld",
999 transaction->revision),
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),
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);
1014 /* KIND (see above) */
1015 svn_skel__prepend(header_skel, skel);
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");
1023 return SVN_NO_ERROR;
1027 /* Construct a skel representing CHECKSUM, allocated in POOL, and prepend
1028 * it onto the existing skel SKEL. */
1029 static svn_error_t *
1030 prepend_checksum(svn_skel_t *skel,
1031 svn_checksum_t *checksum,
1034 svn_skel_t *checksum_skel = svn_skel__make_empty_list(pool);
1036 switch (checksum->kind)
1038 case svn_checksum_md5:
1039 svn_skel__prepend(svn_skel__mem_atom(checksum->digest,
1040 APR_MD5_DIGESTSIZE, pool),
1042 svn_skel__prepend(svn_skel__str_atom("md5", pool), checksum_skel);
1045 case svn_checksum_sha1:
1046 svn_skel__prepend(svn_skel__mem_atom(checksum->digest,
1047 APR_SHA1_DIGESTSIZE, pool),
1049 svn_skel__prepend(svn_skel__str_atom("sha1", pool), checksum_skel);
1053 return skel_err("checksum");
1055 svn_skel__prepend(checksum_skel, skel);
1057 return SVN_NO_ERROR;
1062 svn_fs_base__unparse_representation_skel(svn_skel_t **skel_p,
1063 const representation_t *rep,
1067 svn_skel_t *skel = svn_skel__make_empty_list(pool);
1068 svn_skel_t *header_skel = svn_skel__make_empty_list(pool);
1070 /** Some parts of the header are common to all representations; do
1071 those parts first. **/
1074 if ((format >= SVN_FS_BASE__MIN_REP_SHARING_FORMAT) && rep->sha1_checksum)
1075 SVN_ERR(prepend_checksum(header_skel, rep->sha1_checksum, pool));
1079 svn_checksum_t *md5_checksum = rep->md5_checksum;
1081 md5_checksum = svn_checksum_create(svn_checksum_md5, pool);
1082 SVN_ERR(prepend_checksum(header_skel, md5_checksum, pool));
1087 svn_skel__prepend(svn_skel__str_atom(rep->txn_id, pool), header_skel);
1089 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
1091 /** Do the kind-specific stuff. **/
1093 if (rep->kind == rep_kind_fulltext)
1095 /*** Fulltext Representation. ***/
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);
1102 svn_skel__prepend(svn_skel__str_atom(rep->contents.fulltext.string_key,
1106 svn_skel__prepend(svn_skel__str_atom("fulltext", pool), header_skel);
1109 svn_skel__prepend(header_skel, skel);
1111 else if (rep->kind == rep_kind_delta)
1113 /*** Delta Representation. ***/
1115 apr_array_header_t *chunks = rep->contents.delta.chunks;
1117 /* Loop backwards through the windows, creating and prepending skels. */
1118 for (i = chunks->nelts; i > 0; i--)
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 *);
1128 offset_str = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT,
1132 size_str = apr_psprintf(pool, "%" APR_SIZE_T_FMT, chunk->size);
1135 version_str = apr_psprintf(pool, "%d", chunk->version);
1138 if ((! chunk->string_key) || (! *chunk->string_key))
1139 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), diff_skel);
1141 svn_skel__prepend(svn_skel__str_atom(chunk->string_key, pool),
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);
1147 if ((! chunk->rep_key) || (! *(chunk->rep_key)))
1148 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool),
1151 svn_skel__prepend(svn_skel__str_atom(chunk->rep_key, pool),
1153 svn_skel__prepend(svn_skel__str_atom(size_str, pool), window_skel);
1154 svn_skel__prepend(diff_skel, window_skel);
1156 /* window header. */
1157 svn_skel__prepend(window_skel, chunk_skel);
1158 svn_skel__prepend(svn_skel__str_atom(offset_str, pool),
1161 /* Add this window item to the main skel. */
1162 svn_skel__prepend(chunk_skel, skel);
1166 svn_skel__prepend(svn_skel__str_atom("delta", pool), header_skel);
1169 svn_skel__prepend(header_skel, skel);
1171 else /* unknown kind */
1172 SVN_ERR_MALFUNCTION();
1174 /* Validate and return the skel. */
1175 if (! is_valid_representation_skel(skel))
1176 return skel_err("representation");
1178 return SVN_NO_ERROR;
1183 svn_fs_base__unparse_node_revision_skel(svn_skel_t **skel_p,
1184 const node_revision_t *noderev,
1189 svn_skel_t *header_skel;
1190 const char *num_str;
1192 /* Create the skel. */
1193 skel = svn_skel__make_empty_list(pool);
1194 header_skel = svn_skel__make_empty_list(pool);
1196 /* Store mergeinfo stuffs only if the schema level supports it. */
1197 if (format >= SVN_FS_BASE__MIN_MERGEINFO_FORMAT)
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);
1205 svn_skel__prepend(svn_skel__mem_atom(noderev->has_mergeinfo ? "1" : "0",
1206 1, pool), header_skel);
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)
1212 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
1216 /* PREDECESSOR-COUNT */
1217 if (noderev->predecessor_count != -1)
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);
1224 /* PREDECESSOR-ID */
1225 if (noderev->predecessor_id)
1227 svn_string_t *id_str = svn_fs_base__id_unparse(noderev->predecessor_id,
1229 svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len, pool),
1234 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), header_skel);
1238 svn_skel__prepend(svn_skel__str_atom(noderev->created_path, pool),
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);
1247 SVN_ERR_MALFUNCTION();
1249 /* ### do we really need to check *node->FOO_key ? if a key doesn't
1250 ### exist, then the field should be NULL ... */
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);
1256 /* DATA-KEY | (DATA-KEY DATA-KEY-UNIQID) */
1257 if ((noderev->data_key_uniquifier) && (*noderev->data_key_uniquifier))
1259 /* Build a 2-tuple with a rep key and uniquifier. */
1260 svn_skel_t *data_key_skel = svn_skel__make_empty_list(pool);
1262 /* DATA-KEY-UNIQID */
1263 svn_skel__prepend(svn_skel__str_atom(noderev->data_key_uniquifier,
1268 if ((noderev->data_key) && (*noderev->data_key))
1269 svn_skel__prepend(svn_skel__str_atom(noderev->data_key, pool),
1272 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), data_key_skel);
1274 /* Add our 2-tuple to the main skel. */
1275 svn_skel__prepend(data_key_skel, skel);
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);
1283 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1287 if ((noderev->prop_key) && (*noderev->prop_key))
1288 svn_skel__prepend(svn_skel__str_atom(noderev->prop_key, pool), skel);
1290 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1293 svn_skel__prepend(header_skel, skel);
1295 /* Validate and return the skel. */
1296 if (! is_valid_node_revision_skel(skel))
1297 return skel_err("node-revision");
1299 return SVN_NO_ERROR;
1304 svn_fs_base__unparse_copy_skel(svn_skel_t **skel_p,
1309 svn_string_t *tmp_str;
1311 /* Create the skel. */
1312 skel = svn_skel__make_empty_list(pool);
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),
1320 if ((copy->src_txn_id) && (*copy->src_txn_id))
1321 svn_skel__prepend(svn_skel__str_atom(copy->src_txn_id, pool), skel);
1323 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1326 if ((copy->src_path) && (*copy->src_path))
1327 svn_skel__prepend(svn_skel__str_atom(copy->src_path, pool), skel);
1329 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1332 if (copy->kind == copy_kind_real)
1333 svn_skel__prepend(svn_skel__str_atom("copy", pool), skel);
1335 svn_skel__prepend(svn_skel__str_atom("soft-copy", pool), skel);
1337 /* Validate and return the skel. */
1338 if (! is_valid_copy_skel(skel))
1339 return skel_err("copy");
1341 return SVN_NO_ERROR;
1346 svn_fs_base__unparse_entries_skel(svn_skel_t **skel_p,
1347 apr_hash_t *entries,
1350 svn_skel_t *skel = svn_skel__make_empty_list(pool);
1351 apr_hash_index_t *hi;
1353 /* Create the skel. */
1356 /* Loop over hash entries */
1357 for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
1363 svn_string_t *id_str;
1364 svn_skel_t *entry_skel = svn_skel__make_empty_list(pool);
1366 apr_hash_this(hi, &key, &klen, &val);
1370 id_str = svn_fs_base__id_unparse(value, pool);
1371 svn_skel__prepend(svn_skel__mem_atom(id_str->data, id_str->len,
1376 svn_skel__prepend(svn_skel__mem_atom(key, klen, pool), entry_skel);
1378 /* Add entry to the entries skel. */
1379 svn_skel__prepend(entry_skel, skel);
1383 /* Return the skel. */
1385 return SVN_NO_ERROR;
1390 svn_fs_base__unparse_change_skel(svn_skel_t **skel_p,
1391 const change_t *change,
1395 svn_string_t *tmp_str;
1396 svn_fs_path_change_kind_t kind;
1398 /* Create the skel. */
1399 skel = svn_skel__make_empty_list(pool);
1402 if (change->prop_mod)
1403 svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
1405 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1408 if (change->text_mod)
1409 svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
1411 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1414 switch (change->kind)
1416 case svn_fs_path_change_reset:
1417 svn_skel__prepend(svn_skel__str_atom("reset", pool), skel);
1419 case svn_fs_path_change_add:
1420 svn_skel__prepend(svn_skel__str_atom("add", pool), skel);
1422 case svn_fs_path_change_delete:
1423 svn_skel__prepend(svn_skel__str_atom("delete", pool), skel);
1425 case svn_fs_path_change_replace:
1426 svn_skel__prepend(svn_skel__str_atom("replace", pool), skel);
1428 case svn_fs_path_change_modify:
1430 svn_skel__prepend(svn_skel__str_atom("modify", pool), skel);
1435 if (change->noderev_id)
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),
1443 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1447 svn_skel__prepend(svn_skel__str_atom(change->path, pool), skel);
1450 svn_skel__prepend(svn_skel__str_atom("change", pool), skel);
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");
1458 return SVN_NO_ERROR;
1463 svn_fs_base__unparse_lock_skel(svn_skel_t **skel_p,
1464 const svn_lock_t *lock,
1469 /* Create the skel. */
1470 skel = svn_skel__make_empty_list(pool);
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),
1478 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1481 svn_skel__prepend(svn_skel__str_atom(
1482 svn_time_to_cstring(lock->creation_date, pool),
1486 if (lock->is_dav_comment)
1487 svn_skel__prepend(svn_skel__str_atom("1", pool), skel);
1489 svn_skel__prepend(svn_skel__str_atom("0", pool), skel);
1493 svn_skel__prepend(svn_skel__str_atom(lock->comment, pool), skel);
1495 svn_skel__prepend(svn_skel__mem_atom(NULL, 0, pool), skel);
1498 svn_skel__prepend(svn_skel__str_atom(lock->owner, pool), skel);
1501 svn_skel__prepend(svn_skel__str_atom(lock->token, pool), skel);
1504 svn_skel__prepend(svn_skel__str_atom(lock->path, pool), skel);
1507 svn_skel__prepend(svn_skel__str_atom("lock", pool), skel);
1509 /* Validate and return the skel. */
1510 if (! is_valid_lock_skel(skel))
1511 return skel_err("lock");
1514 return SVN_NO_ERROR;