1 /* fs_skels.c --- conversion between fs native types and skeletons
3 * ====================================================================
4 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
6 * This software is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at http://subversion.tigris.org/license-1.html.
9 * If newer versions of this license are posted there, you may use a
10 * newer version instead, at your option.
12 * This software consists of voluntary contributions made by many
13 * individuals. For exact contribution history, see the revision
14 * history and logs, available at http://subversion.tigris.org/.
15 * ====================================================================
19 #include "svn_error.h"
20 #include "svn_string.h"
21 #include "svn_types.h"
29 skel_err(const char *skel_type
)
31 return svn_error_createf(SVN_ERR_FS_MALFORMED_SKEL
, NULL
,
32 "Malformed%s%s skeleton",
34 skel_type
? skel_type
: "");
39 /*** Validity Checking ***/
42 is_valid_checksum_skel(skel_t
*skel
)
44 if (svn_fs_base__list_length(skel
) != 2)
47 if (svn_fs_base__matches_atom(skel
->children
, "md5")
48 && skel
->children
->next
->is_atom
)
56 is_valid_proplist_skel(skel_t
*skel
)
58 int len
= svn_fs_base__list_length(skel
);
60 if ((len
>= 0) && (len
& 1) == 0)
64 for (elt
= skel
->children
; elt
; elt
= elt
->next
)
76 is_valid_revision_skel(skel_t
*skel
)
78 int len
= svn_fs_base__list_length(skel
);
81 && svn_fs_base__matches_atom(skel
->children
, "revision")
82 && skel
->children
->next
->is_atom
)
90 is_valid_transaction_skel(skel_t
*skel
, transaction_kind_t
*kind
)
92 int len
= svn_fs_base__list_length(skel
);
97 /* Determine (and verify) the kind. */
98 if (svn_fs_base__matches_atom(skel
->children
, "transaction"))
99 *kind
= transaction_kind_normal
;
100 else if (svn_fs_base__matches_atom(skel
->children
, "committed"))
101 *kind
= transaction_kind_committed
;
102 else if (svn_fs_base__matches_atom(skel
->children
, "dead"))
103 *kind
= transaction_kind_dead
;
107 if (skel
->children
->next
->is_atom
108 && skel
->children
->next
->next
->is_atom
109 && (! skel
->children
->next
->next
->next
->is_atom
)
110 && (! skel
->children
->next
->next
->next
->next
->is_atom
))
118 is_valid_rep_delta_chunk_skel(skel_t
*skel
)
124 /* check the delta skel. */
125 if ((svn_fs_base__list_length(skel
) != 2)
126 || (! skel
->children
->is_atom
))
129 /* check the window. */
130 window
= skel
->children
->next
;
131 len
= svn_fs_base__list_length(window
);
132 if ((len
< 3) || (len
> 4))
134 if (! ((! window
->children
->is_atom
)
135 && (window
->children
->next
->is_atom
)
136 && (window
->children
->next
->next
->is_atom
)))
139 && (! window
->children
->next
->next
->next
->is_atom
))
142 /* check the diff. ### currently we support only svndiff version
144 diff
= window
->children
;
145 if ((svn_fs_base__list_length(diff
) == 3)
146 && (svn_fs_base__matches_atom(diff
->children
, "svndiff"))
147 && ((svn_fs_base__matches_atom(diff
->children
->next
, "0"))
148 || (svn_fs_base__matches_atom(diff
->children
->next
, "1")))
149 && (diff
->children
->next
->next
->is_atom
))
157 is_valid_representation_skel(skel_t
*skel
)
159 int len
= svn_fs_base__list_length(skel
);
163 /* the rep has at least two items in it, a HEADER list, and at least
164 one piece of kind-specific data. */
168 /* check the header. it must have KIND and TXN atoms, and
169 optionally a CHECKSUM (which is a list form). */
170 header
= skel
->children
;
171 header_len
= svn_fs_base__list_length(header
);
172 if (! (((header_len
== 2) /* 2 means old repository, checksum absent */
173 && (header
->children
->is_atom
)
174 && (header
->children
->next
->is_atom
))
175 || ((header_len
== 3) /* 3 means checksum present */
176 && (header
->children
->is_atom
)
177 && (header
->children
->next
->is_atom
)
178 && (is_valid_checksum_skel(header
->children
->next
->next
)))))
181 /* check for fulltext rep. */
183 && (svn_fs_base__matches_atom(header
->children
, "fulltext")))
186 /* check for delta rep. */
188 && (svn_fs_base__matches_atom(header
->children
, "delta")))
190 /* it's a delta rep. check the validity. */
191 skel_t
*chunk
= skel
->children
->next
;
193 /* loop over chunks, checking each one. */
196 if (! is_valid_rep_delta_chunk_skel(chunk
))
201 /* all good on this delta rep. */
210 is_valid_node_revision_header_skel(skel_t
*skel
, skel_t
**kind_p
)
212 int len
= svn_fs_base__list_length(skel
);
217 /* set the *KIND_P pointer. */
218 *kind_p
= skel
->children
;
220 /* check for valid lengths. */
221 if (! ((len
== 2) || (len
== 3) || (len
== 4) || (len
== 6)))
224 /* got mergeinfo stuff? */
226 && (! (skel
->children
->next
->next
->next
->next
->is_atom
227 && skel
->children
->next
->next
->next
->next
->next
->is_atom
)))
230 /* got predecessor count? */
232 && (! skel
->children
->next
->next
->next
->is_atom
))
235 /* got predecessor? */
237 && (! skel
->children
->next
->next
->is_atom
))
240 /* got the basics? */
241 if (! (skel
->children
->is_atom
242 && skel
->children
->next
->is_atom
243 && (skel
->children
->next
->data
[0] == '/')))
251 is_valid_node_revision_skel(skel_t
*skel
)
253 int len
= svn_fs_base__list_length(skel
);
257 skel_t
*header
= skel
->children
;
260 if (is_valid_node_revision_header_skel(header
, &kind
))
262 if (svn_fs_base__matches_atom(kind
, "dir")
264 && header
->next
->is_atom
265 && header
->next
->next
->is_atom
)
268 if (svn_fs_base__matches_atom(kind
, "file")
269 && ((len
== 3) || (len
== 4))
270 && header
->next
->is_atom
271 && header
->next
->next
->is_atom
)
273 if ((len
== 4) && (! header
->next
->next
->next
->is_atom
))
285 is_valid_copy_skel(skel_t
*skel
)
287 return (((svn_fs_base__list_length(skel
) == 4)
288 && (svn_fs_base__matches_atom(skel
->children
, "copy")
289 || svn_fs_base__matches_atom(skel
->children
, "soft-copy"))
290 && skel
->children
->next
->is_atom
291 && skel
->children
->next
->next
->is_atom
292 && skel
->children
->next
->next
->next
->is_atom
) ? TRUE
: FALSE
);
297 is_valid_change_skel(skel_t
*skel
, svn_fs_path_change_kind_t
*kind
)
299 if ((svn_fs_base__list_length(skel
) == 6)
300 && svn_fs_base__matches_atom(skel
->children
, "change")
301 && skel
->children
->next
->is_atom
302 && skel
->children
->next
->next
->is_atom
303 && skel
->children
->next
->next
->next
->is_atom
304 && skel
->children
->next
->next
->next
->next
->is_atom
305 && skel
->children
->next
->next
->next
->next
->next
->is_atom
)
307 skel_t
*kind_skel
= skel
->children
->next
->next
->next
;
309 /* check the kind (and return it) */
310 if (svn_fs_base__matches_atom(kind_skel
, "reset"))
313 *kind
= svn_fs_path_change_reset
;
316 if (svn_fs_base__matches_atom(kind_skel
, "add"))
319 *kind
= svn_fs_path_change_add
;
322 if (svn_fs_base__matches_atom(kind_skel
, "delete"))
325 *kind
= svn_fs_path_change_delete
;
328 if (svn_fs_base__matches_atom(kind_skel
, "replace"))
331 *kind
= svn_fs_path_change_replace
;
334 if (svn_fs_base__matches_atom(kind_skel
, "modify"))
337 *kind
= svn_fs_path_change_modify
;
346 is_valid_lock_skel(skel_t
*skel
)
348 if ((svn_fs_base__list_length(skel
) == 8)
349 && svn_fs_base__matches_atom(skel
->children
, "lock")
350 && skel
->children
->next
->is_atom
351 && skel
->children
->next
->next
->is_atom
352 && skel
->children
->next
->next
->next
->is_atom
353 && skel
->children
->next
->next
->next
->next
->is_atom
354 && skel
->children
->next
->next
->next
->next
->next
->is_atom
355 && skel
->children
->next
->next
->next
->next
->next
->next
->is_atom
356 && skel
->children
->next
->next
->next
->next
->next
->next
->next
->is_atom
)
364 /*** Parsing (conversion from skeleton to native FS type) ***/
367 svn_fs_base__parse_proplist_skel(apr_hash_t
**proplist_p
,
371 apr_hash_t
*proplist
= NULL
;
374 /* Validate the skel. */
375 if (! is_valid_proplist_skel(skel
))
376 return skel_err("proplist");
378 /* Create the returned structure */
380 proplist
= apr_hash_make(pool
);
381 for (elt
= skel
->children
; elt
; elt
= elt
->next
->next
)
383 svn_string_t
*value
= svn_string_ncreate(elt
->next
->data
,
384 elt
->next
->len
, pool
);
385 apr_hash_set(proplist
,
386 apr_pstrmemdup(pool
, elt
->data
, elt
->len
),
391 /* Return the structure. */
392 *proplist_p
= proplist
;
398 svn_fs_base__parse_revision_skel(revision_t
**revision_p
,
402 revision_t
*revision
;
404 /* Validate the skel. */
405 if (! is_valid_revision_skel(skel
))
406 return skel_err("revision");
408 /* Create the returned structure */
409 revision
= apr_pcalloc(pool
, sizeof(*revision
));
410 revision
->txn_id
= apr_pstrmemdup(pool
, skel
->children
->next
->data
,
411 skel
->children
->next
->len
);
413 /* Return the structure. */
414 *revision_p
= revision
;
420 svn_fs_base__parse_transaction_skel(transaction_t
**transaction_p
,
424 transaction_t
*transaction
;
425 transaction_kind_t kind
;
426 skel_t
*root_id
, *base_id_or_rev
, *proplist
, *copies
;
429 /* Validate the skel. */
430 if (! is_valid_transaction_skel(skel
, &kind
))
431 return skel_err("transaction");
433 root_id
= skel
->children
->next
;
434 base_id_or_rev
= skel
->children
->next
->next
;
435 proplist
= skel
->children
->next
->next
->next
;
436 copies
= skel
->children
->next
->next
->next
->next
;
438 /* Create the returned structure */
439 transaction
= apr_pcalloc(pool
, sizeof(*transaction
));
442 transaction
->kind
= kind
;
444 /* REVISION or BASE-ID */
445 if (kind
== transaction_kind_committed
)
447 /* Committed transactions have a revision number... */
448 transaction
->base_id
= NULL
;
449 transaction
->revision
= atoi(apr_pstrmemdup(pool
, base_id_or_rev
->data
,
450 base_id_or_rev
->len
));
451 if (! SVN_IS_VALID_REVNUM(transaction
->revision
))
452 return skel_err("transaction");
457 /* ...where unfinished transactions have a base node-revision-id. */
458 transaction
->revision
= SVN_INVALID_REVNUM
;
459 transaction
->base_id
= svn_fs_base__id_parse(base_id_or_rev
->data
,
460 base_id_or_rev
->len
, pool
);
464 transaction
->root_id
= svn_fs_base__id_parse(root_id
->data
,
468 SVN_ERR(svn_fs_base__parse_proplist_skel(&(transaction
->proplist
),
472 if ((len
= svn_fs_base__list_length(copies
)))
475 apr_array_header_t
*txncopies
;
476 skel_t
*cpy
= copies
->children
;
478 txncopies
= apr_array_make(pool
, len
, sizeof(copy_id
));
481 copy_id
= apr_pstrmemdup(pool
, cpy
->data
, cpy
->len
);
482 APR_ARRAY_PUSH(txncopies
, const char *) = copy_id
;
485 transaction
->copies
= txncopies
;
488 /* Return the structure. */
489 *transaction_p
= transaction
;
495 svn_fs_base__parse_representation_skel(representation_t
**rep_p
,
499 representation_t
*rep
;
502 /* Validate the skel. */
503 if (! is_valid_representation_skel(skel
))
504 return skel_err("representation");
505 header_skel
= skel
->children
;
507 /* Create the returned structure */
508 rep
= apr_pcalloc(pool
, sizeof(*rep
));
511 if (svn_fs_base__matches_atom(header_skel
->children
, "fulltext"))
512 rep
->kind
= rep_kind_fulltext
;
514 rep
->kind
= rep_kind_delta
;
517 rep
->txn_id
= apr_pstrmemdup(pool
, header_skel
->children
->next
->data
,
518 header_skel
->children
->next
->len
);
521 if (header_skel
->children
->next
->next
)
523 memcpy(rep
->checksum
,
524 header_skel
->children
->next
->next
->children
->next
->data
,
529 /* Older repository, no checksum, so manufacture an all-zero checksum */
530 memset(rep
->checksum
, 0, APR_MD5_DIGESTSIZE
);
533 /* KIND-SPECIFIC stuff */
534 if (rep
->kind
== rep_kind_fulltext
)
536 /* "fulltext"-specific. */
537 rep
->contents
.fulltext
.string_key
538 = apr_pstrmemdup(pool
,
539 skel
->children
->next
->data
,
540 skel
->children
->next
->len
);
544 /* "delta"-specific. */
545 skel_t
*chunk_skel
= skel
->children
->next
;
546 rep_delta_chunk_t
*chunk
;
547 apr_array_header_t
*chunks
;
549 /* Alloc the chunk array. */
550 chunks
= apr_array_make(pool
, svn_fs_base__list_length(skel
) - 1,
553 /* Process the chunks. */
556 skel_t
*window_skel
= chunk_skel
->children
->next
;
557 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 */
564 = (apr_byte_t
)atoi(apr_pstrmemdup
566 diff_skel
->children
->next
->data
,
567 diff_skel
->children
->next
->len
));
569 = apr_pstrmemdup(pool
,
570 diff_skel
->children
->next
->next
->data
,
571 diff_skel
->children
->next
->next
->len
);
573 = atoi(apr_pstrmemdup(pool
,
574 window_skel
->children
->next
->data
,
575 window_skel
->children
->next
->len
));
577 = apr_pstrmemdup(pool
,
578 window_skel
->children
->next
->next
->data
,
579 window_skel
->children
->next
->next
->len
);
581 svn__atoui64(apr_pstrmemdup(pool
,
582 chunk_skel
->children
->data
,
583 chunk_skel
->children
->len
));
585 /* Add this chunk to the array. */
586 APR_ARRAY_PUSH(chunks
, rep_delta_chunk_t
*) = chunk
;
589 chunk_skel
= chunk_skel
->next
;
592 /* Add the chunks array to the representation. */
593 rep
->contents
.delta
.chunks
= chunks
;
596 /* Return the structure. */
603 svn_fs_base__parse_node_revision_skel(node_revision_t
**noderev_p
,
607 node_revision_t
*noderev
;
608 skel_t
*header_skel
, *cur_skel
;
610 /* Validate the skel. */
611 if (! is_valid_node_revision_skel(skel
))
612 return skel_err("node-revision");
613 header_skel
= skel
->children
;
615 /* Create the returned structure */
616 noderev
= apr_pcalloc(pool
, sizeof(*noderev
));
619 if (svn_fs_base__matches_atom(header_skel
->children
, "dir"))
620 noderev
->kind
= svn_node_dir
;
622 noderev
->kind
= svn_node_file
;
625 noderev
->created_path
= apr_pstrmemdup(pool
,
626 header_skel
->children
->next
->data
,
627 header_skel
->children
->next
->len
);
630 if (header_skel
->children
->next
->next
)
632 cur_skel
= header_skel
->children
->next
->next
;
634 noderev
->predecessor_id
= svn_fs_base__id_parse(cur_skel
->data
,
635 cur_skel
->len
, pool
);
637 /* PREDECESSOR-COUNT */
638 noderev
->predecessor_count
= -1;
641 cur_skel
= cur_skel
->next
;
643 noderev
->predecessor_count
= atoi(apr_pstrmemdup(pool
,
647 /* HAS-MERGEINFO and MERGEINFO-COUNT */
650 cur_skel
= cur_skel
->next
;
651 noderev
->has_mergeinfo
= atoi(apr_pstrmemdup(pool
,
655 noderev
->mergeinfo_count
=
656 apr_atoi64(apr_pstrmemdup(pool
,
657 cur_skel
->next
->data
,
658 cur_skel
->next
->len
));
664 if (skel
->children
->next
->len
)
665 noderev
->prop_key
= apr_pstrmemdup(pool
, skel
->children
->next
->data
,
666 skel
->children
->next
->len
);
669 if (skel
->children
->next
->next
->len
)
670 noderev
->data_key
= apr_pstrmemdup(pool
, skel
->children
->next
->next
->data
,
671 skel
->children
->next
->next
->len
);
673 /* EDIT-DATA-KEY (optional, files only) */
674 if ((noderev
->kind
== svn_node_file
)
675 && skel
->children
->next
->next
->next
676 && skel
->children
->next
->next
->next
->len
)
678 = apr_pstrmemdup(pool
, skel
->children
->next
->next
->next
->data
,
679 skel
->children
->next
->next
->next
->len
);
681 /* Return the structure. */
682 *noderev_p
= noderev
;
688 svn_fs_base__parse_copy_skel(copy_t
**copy_p
,
694 /* Validate the skel. */
695 if (! is_valid_copy_skel(skel
))
696 return skel_err("copy");
698 /* Create the returned structure */
699 copy
= apr_pcalloc(pool
, sizeof(*copy
));
702 if (svn_fs_base__matches_atom(skel
->children
, "soft-copy"))
703 copy
->kind
= copy_kind_soft
;
705 copy
->kind
= copy_kind_real
;
708 copy
->src_path
= apr_pstrmemdup(pool
,
709 skel
->children
->next
->data
,
710 skel
->children
->next
->len
);
713 copy
->src_txn_id
= apr_pstrmemdup(pool
,
714 skel
->children
->next
->next
->data
,
715 skel
->children
->next
->next
->len
);
719 = svn_fs_base__id_parse(skel
->children
->next
->next
->next
->data
,
720 skel
->children
->next
->next
->next
->len
, pool
);
722 /* Return the structure. */
729 svn_fs_base__parse_entries_skel(apr_hash_t
**entries_p
,
733 apr_hash_t
*entries
= NULL
;
734 int len
= svn_fs_base__list_length(skel
);
738 return skel_err("entries");
742 /* Else, allocate a hash and populate it. */
743 entries
= apr_hash_make(pool
);
745 /* Check entries are well-formed as we go along. */
746 for (elt
= skel
->children
; elt
; elt
= elt
->next
)
751 /* ENTRY must be a list of two elements. */
752 if (svn_fs_base__list_length(elt
) != 2)
753 return skel_err("entries");
755 /* Get the entry's name and ID. */
756 name
= apr_pstrmemdup(pool
, elt
->children
->data
,
758 id
= svn_fs_base__id_parse(elt
->children
->next
->data
,
759 elt
->children
->next
->len
, pool
);
761 /* Add the entry to the hash. */
762 apr_hash_set(entries
, name
, elt
->children
->len
, id
);
766 /* Return the structure. */
767 *entries_p
= entries
;
773 svn_fs_base__parse_change_skel(change_t
**change_p
,
778 svn_fs_path_change_kind_t kind
;
780 /* Validate the skel. */
781 if (! is_valid_change_skel(skel
, &kind
))
782 return skel_err("change");
784 /* Create the returned structure */
785 change
= apr_pcalloc(pool
, sizeof(*change
));
788 change
->path
= apr_pstrmemdup(pool
, skel
->children
->next
->data
,
789 skel
->children
->next
->len
);
792 if (skel
->children
->next
->next
->len
)
793 change
->noderev_id
= svn_fs_base__id_parse
794 (skel
->children
->next
->next
->data
, skel
->children
->next
->next
->len
,
801 if (skel
->children
->next
->next
->next
->next
->len
)
802 change
->text_mod
= TRUE
;
805 if (skel
->children
->next
->next
->next
->next
->next
->len
)
806 change
->prop_mod
= TRUE
;
808 /* Return the structure. */
815 svn_fs_base__parse_lock_skel(svn_lock_t
**lock_p
,
822 /* Validate the skel. */
823 if (! is_valid_lock_skel(skel
))
824 return skel_err("lock");
826 /* Create the returned structure */
827 lock
= apr_pcalloc(pool
, sizeof(*lock
));
830 lock
->path
= apr_pstrmemdup(pool
, skel
->children
->next
->data
,
831 skel
->children
->next
->len
);
834 lock
->token
= apr_pstrmemdup(pool
,
835 skel
->children
->next
->next
->data
,
836 skel
->children
->next
->next
->len
);
839 lock
->owner
= apr_pstrmemdup(pool
,
840 skel
->children
->next
->next
->next
->data
,
841 skel
->children
->next
->next
->next
->len
);
843 /* COMMENT (could be just an empty atom) */
844 if (skel
->children
->next
->next
->next
->next
->len
)
847 skel
->children
->next
->next
->next
->next
->data
,
848 skel
->children
->next
->next
->next
->next
->len
);
851 if (svn_fs_base__matches_atom
852 (skel
->children
->next
->next
->next
->next
->next
, "1"))
853 lock
->is_dav_comment
= TRUE
;
855 lock
->is_dav_comment
= FALSE
;
858 timestr
= apr_pstrmemdup
860 skel
->children
->next
->next
->next
->next
->next
->next
->data
,
861 skel
->children
->next
->next
->next
->next
->next
->next
->len
);
862 SVN_ERR(svn_time_from_cstring(&(lock
->creation_date
),
865 /* EXPIRATION-DATE (could be just an empty atom) */
866 if (skel
->children
->next
->next
->next
->next
->next
->next
->next
->len
)
871 skel
->children
->next
->next
->next
->next
->next
->next
->next
->data
,
872 skel
->children
->next
->next
->next
->next
->next
->next
->next
->len
);
873 SVN_ERR(svn_time_from_cstring(&(lock
->expiration_date
),
877 /* Return the structure. */
884 /*** Unparsing (conversion from native FS type to skeleton) ***/
887 svn_fs_base__unparse_proplist_skel(skel_t
**skel_p
,
888 apr_hash_t
*proplist
,
891 skel_t
*skel
= svn_fs_base__make_empty_list(pool
);
892 apr_hash_index_t
*hi
;
894 /* Create the skel. */
897 /* Loop over hash entries */
898 for (hi
= apr_hash_first(pool
, proplist
); hi
; hi
= apr_hash_next(hi
))
905 apr_hash_this(hi
, &key
, &klen
, &val
);
909 svn_fs_base__prepend(svn_fs_base__mem_atom(value
->data
,
914 svn_fs_base__prepend(svn_fs_base__mem_atom(key
, klen
, pool
), skel
);
918 /* Validate and return the skel. */
919 if (! is_valid_proplist_skel(skel
))
920 return skel_err("proplist");
927 svn_fs_base__unparse_revision_skel(skel_t
**skel_p
,
928 const revision_t
*revision
,
933 /* Create the skel. */
934 skel
= svn_fs_base__make_empty_list(pool
);
937 svn_fs_base__prepend(svn_fs_base__str_atom(revision
->txn_id
, pool
), skel
);
940 svn_fs_base__prepend(svn_fs_base__str_atom("revision", pool
), skel
);
942 /* Validate and return the skel. */
943 if (! is_valid_revision_skel(skel
))
944 return skel_err("revision");
951 svn_fs_base__unparse_transaction_skel(skel_t
**skel_p
,
952 const transaction_t
*transaction
,
956 skel_t
*proplist_skel
, *copies_skel
, *header_skel
;
957 svn_string_t
*id_str
;
958 transaction_kind_t kind
;
960 /* Create the skel. */
961 skel
= svn_fs_base__make_empty_list(pool
);
963 switch (transaction
->kind
)
965 case transaction_kind_committed
:
966 header_skel
= svn_fs_base__str_atom("committed", pool
);
967 if ((transaction
->base_id
)
968 || (! SVN_IS_VALID_REVNUM(transaction
->revision
)))
969 return skel_err("transaction");
971 case transaction_kind_dead
:
972 header_skel
= svn_fs_base__str_atom("dead", pool
);
973 if ((! transaction
->base_id
)
974 || (SVN_IS_VALID_REVNUM(transaction
->revision
)))
975 return skel_err("transaction");
977 case transaction_kind_normal
:
978 header_skel
= svn_fs_base__str_atom("transaction", pool
);
979 if ((! transaction
->base_id
)
980 || (SVN_IS_VALID_REVNUM(transaction
->revision
)))
981 return skel_err("transaction");
984 return skel_err("transaction");
989 copies_skel
= svn_fs_base__make_empty_list(pool
);
990 if (transaction
->copies
&& transaction
->copies
->nelts
)
993 for (i
= transaction
->copies
->nelts
- 1; i
>= 0; i
--)
995 svn_fs_base__prepend(svn_fs_base__str_atom
996 (APR_ARRAY_IDX(transaction
->copies
, i
,
997 const char *), pool
),
1001 svn_fs_base__prepend(copies_skel
, skel
);
1004 SVN_ERR(svn_fs_base__unparse_proplist_skel(&proplist_skel
,
1005 transaction
->proplist
, pool
));
1006 svn_fs_base__prepend(proplist_skel
, skel
);
1008 /* REVISION or BASE-ID */
1009 if (transaction
->kind
== transaction_kind_committed
)
1011 /* Committed transactions have a revision number... */
1012 svn_fs_base__prepend(svn_fs_base__str_atom
1013 (apr_psprintf(pool
, "%ld",
1014 transaction
->revision
), pool
),
1019 /* ...where other transactions have a base node revision ID. */
1020 id_str
= svn_fs_base__id_unparse(transaction
->base_id
, pool
);
1021 svn_fs_base__prepend(svn_fs_base__mem_atom(id_str
->data
, id_str
->len
,
1026 id_str
= svn_fs_base__id_unparse(transaction
->root_id
, pool
);
1027 svn_fs_base__prepend(svn_fs_base__mem_atom(id_str
->data
, id_str
->len
,
1030 /* KIND (see above) */
1031 svn_fs_base__prepend(header_skel
, skel
);
1033 /* Validate and return the skel. */
1034 if (! is_valid_transaction_skel(skel
, &kind
))
1035 return skel_err("transaction");
1036 if (kind
!= transaction
->kind
)
1037 return skel_err("transaction");
1039 return SVN_NO_ERROR
;
1044 svn_fs_base__unparse_representation_skel(skel_t
**skel_p
,
1045 const representation_t
*rep
,
1048 skel_t
*skel
= svn_fs_base__make_empty_list(pool
);
1049 skel_t
*header_skel
= svn_fs_base__make_empty_list(pool
);
1051 /** Some parts of the header are common to all representations; do
1052 those parts first. **/
1056 skel_t
*checksum_skel
= svn_fs_base__make_empty_list(pool
);
1057 svn_fs_base__prepend(svn_fs_base__mem_atom
1058 (rep
->checksum
, APR_MD5_DIGESTSIZE
, pool
),
1060 svn_fs_base__prepend(svn_fs_base__str_atom("md5", pool
), checksum_skel
);
1061 svn_fs_base__prepend(checksum_skel
, header_skel
);
1066 svn_fs_base__prepend(svn_fs_base__str_atom(rep
->txn_id
, pool
),
1069 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), header_skel
);
1071 /** Do the kind-specific stuff. **/
1073 if (rep
->kind
== rep_kind_fulltext
)
1075 /*** Fulltext Representation. ***/
1078 if ((! rep
->contents
.fulltext
.string_key
)
1079 || (! *rep
->contents
.fulltext
.string_key
))
1080 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1082 svn_fs_base__prepend(svn_fs_base__str_atom
1083 (rep
->contents
.fulltext
.string_key
, pool
), skel
);
1086 svn_fs_base__prepend(svn_fs_base__str_atom("fulltext", pool
),
1090 svn_fs_base__prepend(header_skel
, skel
);
1092 else if (rep
->kind
== rep_kind_delta
)
1094 /*** Delta Representation. ***/
1096 apr_array_header_t
*chunks
= rep
->contents
.delta
.chunks
;
1098 /* Loop backwards through the windows, creating and prepending skels. */
1099 for (i
= chunks
->nelts
; i
> 0; i
--)
1101 skel_t
*window_skel
= svn_fs_base__make_empty_list(pool
);
1102 skel_t
*chunk_skel
= svn_fs_base__make_empty_list(pool
);
1103 skel_t
*diff_skel
= svn_fs_base__make_empty_list(pool
);
1104 const char *size_str
, *offset_str
, *version_str
;
1105 rep_delta_chunk_t
*chunk
= APR_ARRAY_IDX(chunks
, i
- 1,
1106 rep_delta_chunk_t
*);
1109 offset_str
= apr_psprintf(pool
, "%" SVN_FILESIZE_T_FMT
,
1113 size_str
= apr_psprintf(pool
, "%" APR_SIZE_T_FMT
, chunk
->size
);
1116 version_str
= apr_psprintf(pool
, "%d", chunk
->version
);
1119 if ((! chunk
->string_key
) || (! *chunk
->string_key
))
1120 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
),
1123 svn_fs_base__prepend(svn_fs_base__str_atom(chunk
->string_key
,
1125 svn_fs_base__prepend(svn_fs_base__str_atom(version_str
, pool
),
1127 svn_fs_base__prepend(svn_fs_base__str_atom("svndiff", pool
),
1131 if ((! chunk
->rep_key
) || (! *(chunk
->rep_key
)))
1132 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
),
1135 svn_fs_base__prepend(svn_fs_base__str_atom(chunk
->rep_key
,
1138 svn_fs_base__prepend(svn_fs_base__str_atom(size_str
, pool
),
1140 svn_fs_base__prepend(diff_skel
, window_skel
);
1142 /* window header. */
1143 svn_fs_base__prepend(window_skel
, chunk_skel
);
1144 svn_fs_base__prepend(svn_fs_base__str_atom(offset_str
, pool
),
1147 /* Add this window item to the main skel. */
1148 svn_fs_base__prepend(chunk_skel
, skel
);
1152 svn_fs_base__prepend(svn_fs_base__str_atom("delta", pool
),
1156 svn_fs_base__prepend(header_skel
, skel
);
1158 else /* unknown kind */
1161 /* Validate and return the skel. */
1162 if (! is_valid_representation_skel(skel
))
1163 return skel_err("representation");
1165 return SVN_NO_ERROR
;
1170 svn_fs_base__unparse_node_revision_skel(skel_t
**skel_p
,
1171 const node_revision_t
*noderev
,
1176 skel_t
*header_skel
;
1177 const char *num_str
;
1179 /* Create the skel. */
1180 skel
= svn_fs_base__make_empty_list(pool
);
1181 header_skel
= svn_fs_base__make_empty_list(pool
);
1183 /* Store mergeinfo stuffs only if the schema level supports it. */
1184 if (format
>= SVN_FS_BASE__MIN_MERGEINFO_FORMAT
)
1186 /* MERGEINFO-COUNT */
1187 num_str
= apr_psprintf(pool
, "%" APR_INT64_T_FMT
,
1188 noderev
->mergeinfo_count
);
1189 svn_fs_base__prepend(svn_fs_base__str_atom(num_str
, pool
), header_skel
);
1192 svn_fs_base__prepend(svn_fs_base__mem_atom(noderev
->has_mergeinfo
1194 1, pool
), header_skel
);
1196 /* PREDECESSOR-COUNT padding (only if we *don't* have a valid
1197 value; if we do, we'll pick that up below) */
1198 if (noderev
->predecessor_count
== -1)
1200 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
),
1205 /* PREDECESSOR-COUNT */
1206 if (noderev
->predecessor_count
!= -1)
1208 const char *count_str
= apr_psprintf(pool
, "%d",
1209 noderev
->predecessor_count
);
1210 svn_fs_base__prepend(svn_fs_base__str_atom(count_str
, pool
),
1214 /* PREDECESSOR-ID */
1215 if (noderev
->predecessor_id
)
1217 svn_string_t
*id_str
= svn_fs_base__id_unparse(noderev
->predecessor_id
,
1219 svn_fs_base__prepend(svn_fs_base__mem_atom(id_str
->data
, id_str
->len
,
1225 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), header_skel
);
1229 svn_fs_base__prepend(svn_fs_base__str_atom(noderev
->created_path
, pool
),
1233 if (noderev
->kind
== svn_node_file
)
1234 svn_fs_base__prepend(svn_fs_base__str_atom("file", pool
), header_skel
);
1235 else if (noderev
->kind
== svn_node_dir
)
1236 svn_fs_base__prepend(svn_fs_base__str_atom("dir", pool
), header_skel
);
1240 /* ### do we really need to check *node->FOO_key ? if a key doesn't
1241 ### exist, then the field should be NULL ... */
1243 /* EDIT-DATA-KEY (optional) */
1244 if ((noderev
->edit_key
) && (*noderev
->edit_key
))
1245 svn_fs_base__prepend(svn_fs_base__str_atom(noderev
->edit_key
, pool
),
1249 if ((noderev
->data_key
) && (*noderev
->data_key
))
1250 svn_fs_base__prepend(svn_fs_base__str_atom(noderev
->data_key
, pool
),
1253 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1256 if ((noderev
->prop_key
) && (*noderev
->prop_key
))
1257 svn_fs_base__prepend(svn_fs_base__str_atom(noderev
->prop_key
, pool
),
1260 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1263 svn_fs_base__prepend(header_skel
, skel
);
1265 /* Validate and return the skel. */
1266 if (! is_valid_node_revision_skel(skel
))
1267 return skel_err("node-revision");
1269 return SVN_NO_ERROR
;
1274 svn_fs_base__unparse_copy_skel(skel_t
**skel_p
,
1279 svn_string_t
*tmp_str
;
1281 /* Create the skel. */
1282 skel
= svn_fs_base__make_empty_list(pool
);
1285 tmp_str
= svn_fs_base__id_unparse(copy
->dst_noderev_id
, pool
);
1286 svn_fs_base__prepend(svn_fs_base__mem_atom(tmp_str
->data
, tmp_str
->len
,
1290 if ((copy
->src_txn_id
) && (*copy
->src_txn_id
))
1291 svn_fs_base__prepend(svn_fs_base__str_atom(copy
->src_txn_id
, pool
),
1294 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1297 if ((copy
->src_path
) && (*copy
->src_path
))
1298 svn_fs_base__prepend(svn_fs_base__str_atom(copy
->src_path
, pool
), skel
);
1300 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1303 if (copy
->kind
== copy_kind_real
)
1304 svn_fs_base__prepend(svn_fs_base__str_atom("copy", pool
), skel
);
1306 svn_fs_base__prepend(svn_fs_base__str_atom("soft-copy", pool
), skel
);
1308 /* Validate and return the skel. */
1309 if (! is_valid_copy_skel(skel
))
1310 return skel_err("copy");
1312 return SVN_NO_ERROR
;
1317 svn_fs_base__unparse_entries_skel(skel_t
**skel_p
,
1318 apr_hash_t
*entries
,
1321 skel_t
*skel
= svn_fs_base__make_empty_list(pool
);
1322 apr_hash_index_t
*hi
;
1324 /* Create the skel. */
1327 /* Loop over hash entries */
1328 for (hi
= apr_hash_first(pool
, entries
); hi
; hi
= apr_hash_next(hi
))
1334 svn_string_t
*id_str
;
1335 skel_t
*entry_skel
= svn_fs_base__make_empty_list(pool
);
1337 apr_hash_this(hi
, &key
, &klen
, &val
);
1341 id_str
= svn_fs_base__id_unparse(value
, pool
);
1342 svn_fs_base__prepend(svn_fs_base__mem_atom(id_str
->data
,
1347 svn_fs_base__prepend(svn_fs_base__mem_atom(key
, klen
, pool
),
1350 /* Add entry to the entries skel. */
1351 svn_fs_base__prepend(entry_skel
, skel
);
1355 /* Return the skel. */
1357 return SVN_NO_ERROR
;
1362 svn_fs_base__unparse_change_skel(skel_t
**skel_p
,
1363 const change_t
*change
,
1367 svn_string_t
*tmp_str
;
1368 svn_fs_path_change_kind_t kind
;
1370 /* Create the skel. */
1371 skel
= svn_fs_base__make_empty_list(pool
);
1374 if (change
->prop_mod
)
1375 svn_fs_base__prepend(svn_fs_base__str_atom("1", pool
), skel
);
1377 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1380 if (change
->text_mod
)
1381 svn_fs_base__prepend(svn_fs_base__str_atom("1", pool
), skel
);
1383 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1386 switch (change
->kind
)
1388 case svn_fs_path_change_reset
:
1389 svn_fs_base__prepend(svn_fs_base__str_atom("reset", pool
), skel
);
1391 case svn_fs_path_change_add
:
1392 svn_fs_base__prepend(svn_fs_base__str_atom("add", pool
), skel
);
1394 case svn_fs_path_change_delete
:
1395 svn_fs_base__prepend(svn_fs_base__str_atom("delete", pool
), skel
);
1397 case svn_fs_path_change_replace
:
1398 svn_fs_base__prepend(svn_fs_base__str_atom("replace", pool
), skel
);
1400 case svn_fs_path_change_modify
:
1402 svn_fs_base__prepend(svn_fs_base__str_atom("modify", pool
), skel
);
1407 if (change
->noderev_id
)
1409 tmp_str
= svn_fs_base__id_unparse(change
->noderev_id
, pool
);
1410 svn_fs_base__prepend(svn_fs_base__mem_atom(tmp_str
->data
,
1411 tmp_str
->len
, pool
),
1416 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1420 svn_fs_base__prepend(svn_fs_base__str_atom(change
->path
, pool
), skel
);
1423 svn_fs_base__prepend(svn_fs_base__str_atom("change", pool
), skel
);
1425 /* Validate and return the skel. */
1426 if (! is_valid_change_skel(skel
, &kind
))
1427 return skel_err("change");
1428 if (kind
!= change
->kind
)
1429 return skel_err("change");
1431 return SVN_NO_ERROR
;
1436 svn_fs_base__unparse_lock_skel(skel_t
**skel_p
,
1437 const svn_lock_t
*lock
,
1442 /* Create the skel. */
1443 skel
= svn_fs_base__make_empty_list(pool
);
1445 /* EXP-DATE is optional. If not present, just use an empty atom. */
1446 if (lock
->expiration_date
)
1447 svn_fs_base__prepend
1448 (svn_fs_base__str_atom
1449 (svn_time_to_cstring(lock
->expiration_date
, pool
), pool
), skel
);
1451 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1454 svn_fs_base__prepend
1455 (svn_fs_base__str_atom
1456 (svn_time_to_cstring(lock
->creation_date
, pool
), pool
), skel
);
1459 if (lock
->is_dav_comment
)
1460 svn_fs_base__prepend(svn_fs_base__str_atom("1", pool
), skel
);
1462 svn_fs_base__prepend(svn_fs_base__str_atom("0", pool
), skel
);
1466 svn_fs_base__prepend(svn_fs_base__str_atom(lock
->comment
, pool
), skel
);
1468 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL
, 0, pool
), skel
);
1471 svn_fs_base__prepend(svn_fs_base__str_atom(lock
->owner
, pool
), skel
);
1474 svn_fs_base__prepend(svn_fs_base__str_atom(lock
->token
, pool
), skel
);
1477 svn_fs_base__prepend(svn_fs_base__str_atom(lock
->path
, pool
), skel
);
1480 svn_fs_base__prepend(svn_fs_base__str_atom("lock", pool
), skel
);
1482 /* Validate and return the skel. */
1483 if (! is_valid_lock_skel(skel
))
1484 return skel_err("lock");
1487 return SVN_NO_ERROR
;