Mark many merge tests as skip-against-old-server.
[svn.git] / subversion / libsvn_fs_base / util / fs_skels.c
blob705c8b0a6b5a748c8fcf155078696b0542b7d993
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 * ====================================================================
18 #include <string.h>
19 #include "svn_error.h"
20 #include "svn_string.h"
21 #include "svn_types.h"
22 #include "svn_time.h"
23 #include "fs_skels.h"
24 #include "skel.h"
25 #include "../id.h"
28 static svn_error_t *
29 skel_err(const char *skel_type)
31 return svn_error_createf(SVN_ERR_FS_MALFORMED_SKEL, NULL,
32 "Malformed%s%s skeleton",
33 skel_type ? " " : "",
34 skel_type ? skel_type : "");
39 /*** Validity Checking ***/
41 static svn_boolean_t
42 is_valid_checksum_skel(skel_t *skel)
44 if (svn_fs_base__list_length(skel) != 2)
45 return FALSE;
47 if (svn_fs_base__matches_atom(skel->children, "md5")
48 && skel->children->next->is_atom)
49 return TRUE;
51 return FALSE;
55 static svn_boolean_t
56 is_valid_proplist_skel(skel_t *skel)
58 int len = svn_fs_base__list_length(skel);
60 if ((len >= 0) && (len & 1) == 0)
62 skel_t *elt;
64 for (elt = skel->children; elt; elt = elt->next)
65 if (! elt->is_atom)
66 return FALSE;
68 return TRUE;
71 return FALSE;
75 static svn_boolean_t
76 is_valid_revision_skel(skel_t *skel)
78 int len = svn_fs_base__list_length(skel);
80 if ((len == 2)
81 && svn_fs_base__matches_atom(skel->children, "revision")
82 && skel->children->next->is_atom)
83 return TRUE;
85 return FALSE;
89 static svn_boolean_t
90 is_valid_transaction_skel(skel_t *skel, transaction_kind_t *kind)
92 int len = svn_fs_base__list_length(skel);
94 if (len != 5)
95 return FALSE;
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;
104 else
105 return FALSE;
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))
111 return TRUE;
113 return FALSE;
117 static svn_boolean_t
118 is_valid_rep_delta_chunk_skel(skel_t *skel)
120 int len;
121 skel_t *window;
122 skel_t *diff;
124 /* check the delta skel. */
125 if ((svn_fs_base__list_length(skel) != 2)
126 || (! skel->children->is_atom))
127 return FALSE;
129 /* check the window. */
130 window = skel->children->next;
131 len = svn_fs_base__list_length(window);
132 if ((len < 3) || (len > 4))
133 return FALSE;
134 if (! ((! window->children->is_atom)
135 && (window->children->next->is_atom)
136 && (window->children->next->next->is_atom)))
137 return FALSE;
138 if ((len == 4)
139 && (! window->children->next->next->next->is_atom))
140 return FALSE;
142 /* check the diff. ### currently we support only svndiff version
143 0 delta data. */
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))
150 return TRUE;
152 return FALSE;
156 static svn_boolean_t
157 is_valid_representation_skel(skel_t *skel)
159 int len = svn_fs_base__list_length(skel);
160 skel_t *header;
161 int header_len;
163 /* the rep has at least two items in it, a HEADER list, and at least
164 one piece of kind-specific data. */
165 if (len < 2)
166 return FALSE;
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)))))
179 return FALSE;
181 /* check for fulltext rep. */
182 if ((len == 2)
183 && (svn_fs_base__matches_atom(header->children, "fulltext")))
184 return TRUE;
186 /* check for delta rep. */
187 if ((len >= 2)
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. */
194 while (chunk)
196 if (! is_valid_rep_delta_chunk_skel(chunk))
197 return FALSE;
198 chunk = chunk->next;
201 /* all good on this delta rep. */
202 return TRUE;
205 return FALSE;
209 static svn_boolean_t
210 is_valid_node_revision_header_skel(skel_t *skel, skel_t **kind_p)
212 int len = svn_fs_base__list_length(skel);
214 if (len < 2)
215 return FALSE;
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)))
222 return FALSE;
224 /* got mergeinfo stuff? */
225 if ((len > 4)
226 && (! (skel->children->next->next->next->next->is_atom
227 && skel->children->next->next->next->next->next->is_atom)))
228 return FALSE;
230 /* got predecessor count? */
231 if ((len > 3)
232 && (! skel->children->next->next->next->is_atom))
233 return FALSE;
235 /* got predecessor? */
236 if ((len > 2)
237 && (! skel->children->next->next->is_atom))
238 return FALSE;
240 /* got the basics? */
241 if (! (skel->children->is_atom
242 && skel->children->next->is_atom
243 && (skel->children->next->data[0] == '/')))
244 return FALSE;
246 return TRUE;
250 static svn_boolean_t
251 is_valid_node_revision_skel(skel_t *skel)
253 int len = svn_fs_base__list_length(skel);
255 if (len >= 1)
257 skel_t *header = skel->children;
258 skel_t *kind;
260 if (is_valid_node_revision_header_skel(header, &kind))
262 if (svn_fs_base__matches_atom(kind, "dir")
263 && len == 3
264 && header->next->is_atom
265 && header->next->next->is_atom)
266 return TRUE;
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))
274 return FALSE;
275 return TRUE;
280 return FALSE;
284 static svn_boolean_t
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);
296 static svn_boolean_t
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"))
312 if (kind)
313 *kind = svn_fs_path_change_reset;
314 return TRUE;
316 if (svn_fs_base__matches_atom(kind_skel, "add"))
318 if (kind)
319 *kind = svn_fs_path_change_add;
320 return TRUE;
322 if (svn_fs_base__matches_atom(kind_skel, "delete"))
324 if (kind)
325 *kind = svn_fs_path_change_delete;
326 return TRUE;
328 if (svn_fs_base__matches_atom(kind_skel, "replace"))
330 if (kind)
331 *kind = svn_fs_path_change_replace;
332 return TRUE;
334 if (svn_fs_base__matches_atom(kind_skel, "modify"))
336 if (kind)
337 *kind = svn_fs_path_change_modify;
338 return TRUE;
341 return FALSE;
345 static svn_boolean_t
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)
357 return TRUE;
359 return FALSE;
364 /*** Parsing (conversion from skeleton to native FS type) ***/
366 svn_error_t *
367 svn_fs_base__parse_proplist_skel(apr_hash_t **proplist_p,
368 skel_t *skel,
369 apr_pool_t *pool)
371 apr_hash_t *proplist = NULL;
372 skel_t *elt;
374 /* Validate the skel. */
375 if (! is_valid_proplist_skel(skel))
376 return skel_err("proplist");
378 /* Create the returned structure */
379 if (skel->children)
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),
387 elt->len,
388 value);
391 /* Return the structure. */
392 *proplist_p = proplist;
393 return SVN_NO_ERROR;
397 svn_error_t *
398 svn_fs_base__parse_revision_skel(revision_t **revision_p,
399 skel_t *skel,
400 apr_pool_t *pool)
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;
415 return SVN_NO_ERROR;
419 svn_error_t *
420 svn_fs_base__parse_transaction_skel(transaction_t **transaction_p,
421 skel_t *skel,
422 apr_pool_t *pool)
424 transaction_t *transaction;
425 transaction_kind_t kind;
426 skel_t *root_id, *base_id_or_rev, *proplist, *copies;
427 int len;
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));
441 /* KIND */
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");
455 else
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);
463 /* ROOT-ID */
464 transaction->root_id = svn_fs_base__id_parse(root_id->data,
465 root_id->len, pool);
467 /* PROPLIST */
468 SVN_ERR(svn_fs_base__parse_proplist_skel(&(transaction->proplist),
469 proplist, pool));
471 /* COPIES */
472 if ((len = svn_fs_base__list_length(copies)))
474 const char *copy_id;
475 apr_array_header_t *txncopies;
476 skel_t *cpy = copies->children;
478 txncopies = apr_array_make(pool, len, sizeof(copy_id));
479 while (cpy)
481 copy_id = apr_pstrmemdup(pool, cpy->data, cpy->len);
482 APR_ARRAY_PUSH(txncopies, const char *) = copy_id;
483 cpy = cpy->next;
485 transaction->copies = txncopies;
488 /* Return the structure. */
489 *transaction_p = transaction;
490 return SVN_NO_ERROR;
494 svn_error_t *
495 svn_fs_base__parse_representation_skel(representation_t **rep_p,
496 skel_t *skel,
497 apr_pool_t *pool)
499 representation_t *rep;
500 skel_t *header_skel;
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));
510 /* KIND */
511 if (svn_fs_base__matches_atom(header_skel->children, "fulltext"))
512 rep->kind = rep_kind_fulltext;
513 else
514 rep->kind = rep_kind_delta;
516 /* TXN */
517 rep->txn_id = apr_pstrmemdup(pool, header_skel->children->next->data,
518 header_skel->children->next->len);
520 /* CHECKSUM */
521 if (header_skel->children->next->next)
523 memcpy(rep->checksum,
524 header_skel->children->next->next->children->next->data,
525 APR_MD5_DIGESTSIZE);
527 else
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);
542 else
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,
551 sizeof(chunk));
553 /* Process the chunks. */
554 while (chunk_skel)
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 */
563 chunk->version
564 = (apr_byte_t)atoi(apr_pstrmemdup
565 (pool,
566 diff_skel->children->next->data,
567 diff_skel->children->next->len));
568 chunk->string_key
569 = apr_pstrmemdup(pool,
570 diff_skel->children->next->next->data,
571 diff_skel->children->next->next->len);
572 chunk->size
573 = atoi(apr_pstrmemdup(pool,
574 window_skel->children->next->data,
575 window_skel->children->next->len));
576 chunk->rep_key
577 = apr_pstrmemdup(pool,
578 window_skel->children->next->next->data,
579 window_skel->children->next->next->len);
580 chunk->offset =
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;
588 /* Next... */
589 chunk_skel = chunk_skel->next;
592 /* Add the chunks array to the representation. */
593 rep->contents.delta.chunks = chunks;
596 /* Return the structure. */
597 *rep_p = rep;
598 return SVN_NO_ERROR;
602 svn_error_t *
603 svn_fs_base__parse_node_revision_skel(node_revision_t **noderev_p,
604 skel_t *skel,
605 apr_pool_t *pool)
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));
618 /* KIND */
619 if (svn_fs_base__matches_atom(header_skel->children, "dir"))
620 noderev->kind = svn_node_dir;
621 else
622 noderev->kind = svn_node_file;
624 /* CREATED-PATH */
625 noderev->created_path = apr_pstrmemdup(pool,
626 header_skel->children->next->data,
627 header_skel->children->next->len);
629 /* PREDECESSOR-ID */
630 if (header_skel->children->next->next)
632 cur_skel = header_skel->children->next->next;
633 if (cur_skel->len)
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;
639 if (cur_skel->next)
641 cur_skel = cur_skel->next;
642 if (cur_skel->len)
643 noderev->predecessor_count = atoi(apr_pstrmemdup(pool,
644 cur_skel->data,
645 cur_skel->len));
647 /* HAS-MERGEINFO and MERGEINFO-COUNT */
648 if (cur_skel->next)
650 cur_skel = cur_skel->next;
651 noderev->has_mergeinfo = atoi(apr_pstrmemdup(pool,
652 cur_skel->data,
653 cur_skel->len))
654 ? TRUE : FALSE;
655 noderev->mergeinfo_count =
656 apr_atoi64(apr_pstrmemdup(pool,
657 cur_skel->next->data,
658 cur_skel->next->len));
663 /* PROP-KEY */
664 if (skel->children->next->len)
665 noderev->prop_key = apr_pstrmemdup(pool, skel->children->next->data,
666 skel->children->next->len);
668 /* DATA-KEY */
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)
677 noderev->edit_key
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;
683 return SVN_NO_ERROR;
687 svn_error_t *
688 svn_fs_base__parse_copy_skel(copy_t **copy_p,
689 skel_t *skel,
690 apr_pool_t *pool)
692 copy_t *copy;
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));
701 /* KIND */
702 if (svn_fs_base__matches_atom(skel->children, "soft-copy"))
703 copy->kind = copy_kind_soft;
704 else
705 copy->kind = copy_kind_real;
707 /* SRC-PATH */
708 copy->src_path = apr_pstrmemdup(pool,
709 skel->children->next->data,
710 skel->children->next->len);
712 /* SRC-TXN-ID */
713 copy->src_txn_id = apr_pstrmemdup(pool,
714 skel->children->next->next->data,
715 skel->children->next->next->len);
717 /* DST-NODE-ID */
718 copy->dst_noderev_id
719 = svn_fs_base__id_parse(skel->children->next->next->next->data,
720 skel->children->next->next->next->len, pool);
722 /* Return the structure. */
723 *copy_p = copy;
724 return SVN_NO_ERROR;
728 svn_error_t *
729 svn_fs_base__parse_entries_skel(apr_hash_t **entries_p,
730 skel_t *skel,
731 apr_pool_t *pool)
733 apr_hash_t *entries = NULL;
734 int len = svn_fs_base__list_length(skel);
735 skel_t *elt;
737 if (! (len >= 0))
738 return skel_err("entries");
740 if (len > 0)
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)
748 const char *name;
749 svn_fs_id_t *id;
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,
757 elt->children->len);
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;
768 return SVN_NO_ERROR;
772 svn_error_t *
773 svn_fs_base__parse_change_skel(change_t **change_p,
774 skel_t *skel,
775 apr_pool_t *pool)
777 change_t *change;
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));
787 /* PATH */
788 change->path = apr_pstrmemdup(pool, skel->children->next->data,
789 skel->children->next->len);
791 /* NODE-REV-ID */
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,
795 pool);
797 /* KIND */
798 change->kind = kind;
800 /* TEXT-MOD */
801 if (skel->children->next->next->next->next->len)
802 change->text_mod = TRUE;
804 /* PROP-MOD */
805 if (skel->children->next->next->next->next->next->len)
806 change->prop_mod = TRUE;
808 /* Return the structure. */
809 *change_p = change;
810 return SVN_NO_ERROR;
814 svn_error_t *
815 svn_fs_base__parse_lock_skel(svn_lock_t **lock_p,
816 skel_t *skel,
817 apr_pool_t *pool)
819 svn_lock_t *lock;
820 const char *timestr;
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));
829 /* PATH */
830 lock->path = apr_pstrmemdup(pool, skel->children->next->data,
831 skel->children->next->len);
833 /* LOCK-TOKEN */
834 lock->token = apr_pstrmemdup(pool,
835 skel->children->next->next->data,
836 skel->children->next->next->len);
838 /* OWNER */
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)
845 lock->comment =
846 apr_pstrmemdup(pool,
847 skel->children->next->next->next->next->data,
848 skel->children->next->next->next->next->len);
850 /* XML_P */
851 if (svn_fs_base__matches_atom
852 (skel->children->next->next->next->next->next, "1"))
853 lock->is_dav_comment = TRUE;
854 else
855 lock->is_dav_comment = FALSE;
857 /* CREATION-DATE */
858 timestr = apr_pstrmemdup
859 (pool,
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),
863 timestr, pool));
865 /* EXPIRATION-DATE (could be just an empty atom) */
866 if (skel->children->next->next->next->next->next->next->next->len)
868 timestr =
869 apr_pstrmemdup
870 (pool,
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),
874 timestr, pool));
877 /* Return the structure. */
878 *lock_p = lock;
879 return SVN_NO_ERROR;
884 /*** Unparsing (conversion from native FS type to skeleton) ***/
886 svn_error_t *
887 svn_fs_base__unparse_proplist_skel(skel_t **skel_p,
888 apr_hash_t *proplist,
889 apr_pool_t *pool)
891 skel_t *skel = svn_fs_base__make_empty_list(pool);
892 apr_hash_index_t *hi;
894 /* Create the skel. */
895 if (proplist)
897 /* Loop over hash entries */
898 for (hi = apr_hash_first(pool, proplist); hi; hi = apr_hash_next(hi))
900 const void *key;
901 void *val;
902 apr_ssize_t klen;
903 svn_string_t *value;
905 apr_hash_this(hi, &key, &klen, &val);
906 value = val;
908 /* VALUE */
909 svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
910 value->len, pool),
911 skel);
913 /* NAME */
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");
921 *skel_p = skel;
922 return SVN_NO_ERROR;
926 svn_error_t *
927 svn_fs_base__unparse_revision_skel(skel_t **skel_p,
928 const revision_t *revision,
929 apr_pool_t *pool)
931 skel_t *skel;
933 /* Create the skel. */
934 skel = svn_fs_base__make_empty_list(pool);
936 /* TXN_ID */
937 svn_fs_base__prepend(svn_fs_base__str_atom(revision->txn_id, pool), skel);
939 /* "revision" */
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");
945 *skel_p = skel;
946 return SVN_NO_ERROR;
950 svn_error_t *
951 svn_fs_base__unparse_transaction_skel(skel_t **skel_p,
952 const transaction_t *transaction,
953 apr_pool_t *pool)
955 skel_t *skel;
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");
970 break;
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");
976 break;
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");
982 break;
983 default:
984 return skel_err("transaction");
988 /* COPIES */
989 copies_skel = svn_fs_base__make_empty_list(pool);
990 if (transaction->copies && transaction->copies->nelts)
992 int i;
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),
998 copies_skel);
1001 svn_fs_base__prepend(copies_skel, skel);
1003 /* PROPLIST */
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),
1015 skel);
1017 else
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,
1022 pool), skel);
1025 /* ROOT-ID */
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,
1028 pool), skel);
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");
1038 *skel_p = skel;
1039 return SVN_NO_ERROR;
1043 svn_error_t *
1044 svn_fs_base__unparse_representation_skel(skel_t **skel_p,
1045 const representation_t *rep,
1046 apr_pool_t *pool)
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. **/
1054 /* CHECKSUM */
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),
1059 checksum_skel);
1060 svn_fs_base__prepend(svn_fs_base__str_atom("md5", pool), checksum_skel);
1061 svn_fs_base__prepend(checksum_skel, header_skel);
1064 /* TXN */
1065 if (rep->txn_id)
1066 svn_fs_base__prepend(svn_fs_base__str_atom(rep->txn_id, pool),
1067 header_skel);
1068 else
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. ***/
1077 /* STRING-KEY */
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);
1081 else
1082 svn_fs_base__prepend(svn_fs_base__str_atom
1083 (rep->contents.fulltext.string_key, pool), skel);
1085 /* "fulltext" */
1086 svn_fs_base__prepend(svn_fs_base__str_atom("fulltext", pool),
1087 header_skel);
1089 /* header */
1090 svn_fs_base__prepend(header_skel, skel);
1092 else if (rep->kind == rep_kind_delta)
1094 /*** Delta Representation. ***/
1095 int i;
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 *);
1108 /* OFFSET */
1109 offset_str = apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT,
1110 chunk->offset);
1112 /* SIZE */
1113 size_str = apr_psprintf(pool, "%" APR_SIZE_T_FMT, chunk->size);
1115 /* VERSION */
1116 version_str = apr_psprintf(pool, "%d", chunk->version);
1118 /* DIFF */
1119 if ((! chunk->string_key) || (! *chunk->string_key))
1120 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool),
1121 diff_skel);
1122 else
1123 svn_fs_base__prepend(svn_fs_base__str_atom(chunk->string_key,
1124 pool), diff_skel);
1125 svn_fs_base__prepend(svn_fs_base__str_atom(version_str, pool),
1126 diff_skel);
1127 svn_fs_base__prepend(svn_fs_base__str_atom("svndiff", pool),
1128 diff_skel);
1130 /* REP-KEY */
1131 if ((! chunk->rep_key) || (! *(chunk->rep_key)))
1132 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool),
1133 window_skel);
1134 else
1135 svn_fs_base__prepend(svn_fs_base__str_atom(chunk->rep_key,
1136 pool),
1137 window_skel);
1138 svn_fs_base__prepend(svn_fs_base__str_atom(size_str, pool),
1139 window_skel);
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),
1145 chunk_skel);
1147 /* Add this window item to the main skel. */
1148 svn_fs_base__prepend(chunk_skel, skel);
1151 /* "delta" */
1152 svn_fs_base__prepend(svn_fs_base__str_atom("delta", pool),
1153 header_skel);
1155 /* header */
1156 svn_fs_base__prepend(header_skel, skel);
1158 else /* unknown kind */
1159 abort();
1161 /* Validate and return the skel. */
1162 if (! is_valid_representation_skel(skel))
1163 return skel_err("representation");
1164 *skel_p = skel;
1165 return SVN_NO_ERROR;
1169 svn_error_t *
1170 svn_fs_base__unparse_node_revision_skel(skel_t **skel_p,
1171 const node_revision_t *noderev,
1172 int format,
1173 apr_pool_t *pool)
1175 skel_t *skel;
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);
1191 /* HAS-MERGEINFO */
1192 svn_fs_base__prepend(svn_fs_base__mem_atom(noderev->has_mergeinfo
1193 ? "1" : "0",
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),
1201 header_skel);
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),
1211 header_skel);
1214 /* PREDECESSOR-ID */
1215 if (noderev->predecessor_id)
1217 svn_string_t *id_str = svn_fs_base__id_unparse(noderev->predecessor_id,
1218 pool);
1219 svn_fs_base__prepend(svn_fs_base__mem_atom(id_str->data, id_str->len,
1220 pool),
1221 header_skel);
1223 else
1225 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), header_skel);
1228 /* CREATED-PATH */
1229 svn_fs_base__prepend(svn_fs_base__str_atom(noderev->created_path, pool),
1230 header_skel);
1232 /* KIND */
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);
1237 else
1238 abort();
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),
1246 skel);
1248 /* DATA-KEY */
1249 if ((noderev->data_key) && (*noderev->data_key))
1250 svn_fs_base__prepend(svn_fs_base__str_atom(noderev->data_key, pool),
1251 skel);
1252 else
1253 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1255 /* PROP-KEY */
1256 if ((noderev->prop_key) && (*noderev->prop_key))
1257 svn_fs_base__prepend(svn_fs_base__str_atom(noderev->prop_key, pool),
1258 skel);
1259 else
1260 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1262 /* HEADER */
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");
1268 *skel_p = skel;
1269 return SVN_NO_ERROR;
1273 svn_error_t *
1274 svn_fs_base__unparse_copy_skel(skel_t **skel_p,
1275 const copy_t *copy,
1276 apr_pool_t *pool)
1278 skel_t *skel;
1279 svn_string_t *tmp_str;
1281 /* Create the skel. */
1282 skel = svn_fs_base__make_empty_list(pool);
1284 /* DST-NODE-ID */
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,
1287 pool), skel);
1289 /* SRC-TXN-ID */
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),
1292 skel);
1293 else
1294 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1296 /* SRC-PATH */
1297 if ((copy->src_path) && (*copy->src_path))
1298 svn_fs_base__prepend(svn_fs_base__str_atom(copy->src_path, pool), skel);
1299 else
1300 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1302 /* "copy" */
1303 if (copy->kind == copy_kind_real)
1304 svn_fs_base__prepend(svn_fs_base__str_atom("copy", pool), skel);
1305 else
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");
1311 *skel_p = skel;
1312 return SVN_NO_ERROR;
1316 svn_error_t *
1317 svn_fs_base__unparse_entries_skel(skel_t **skel_p,
1318 apr_hash_t *entries,
1319 apr_pool_t *pool)
1321 skel_t *skel = svn_fs_base__make_empty_list(pool);
1322 apr_hash_index_t *hi;
1324 /* Create the skel. */
1325 if (entries)
1327 /* Loop over hash entries */
1328 for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
1330 const void *key;
1331 void *val;
1332 apr_ssize_t klen;
1333 svn_fs_id_t *value;
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);
1338 value = val;
1340 /* VALUE */
1341 id_str = svn_fs_base__id_unparse(value, pool);
1342 svn_fs_base__prepend(svn_fs_base__mem_atom(id_str->data,
1343 id_str->len, pool),
1344 entry_skel);
1346 /* NAME */
1347 svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool),
1348 entry_skel);
1350 /* Add entry to the entries skel. */
1351 svn_fs_base__prepend(entry_skel, skel);
1355 /* Return the skel. */
1356 *skel_p = skel;
1357 return SVN_NO_ERROR;
1361 svn_error_t *
1362 svn_fs_base__unparse_change_skel(skel_t **skel_p,
1363 const change_t *change,
1364 apr_pool_t *pool)
1366 skel_t *skel;
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);
1373 /* PROP-MOD */
1374 if (change->prop_mod)
1375 svn_fs_base__prepend(svn_fs_base__str_atom("1", pool), skel);
1376 else
1377 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1379 /* TEXT-MOD */
1380 if (change->text_mod)
1381 svn_fs_base__prepend(svn_fs_base__str_atom("1", pool), skel);
1382 else
1383 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1385 /* KIND */
1386 switch (change->kind)
1388 case svn_fs_path_change_reset:
1389 svn_fs_base__prepend(svn_fs_base__str_atom("reset", pool), skel);
1390 break;
1391 case svn_fs_path_change_add:
1392 svn_fs_base__prepend(svn_fs_base__str_atom("add", pool), skel);
1393 break;
1394 case svn_fs_path_change_delete:
1395 svn_fs_base__prepend(svn_fs_base__str_atom("delete", pool), skel);
1396 break;
1397 case svn_fs_path_change_replace:
1398 svn_fs_base__prepend(svn_fs_base__str_atom("replace", pool), skel);
1399 break;
1400 case svn_fs_path_change_modify:
1401 default:
1402 svn_fs_base__prepend(svn_fs_base__str_atom("modify", pool), skel);
1403 break;
1406 /* NODE-REV-ID */
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),
1412 skel);
1414 else
1416 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1419 /* PATH */
1420 svn_fs_base__prepend(svn_fs_base__str_atom(change->path, pool), skel);
1422 /* "change" */
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");
1430 *skel_p = skel;
1431 return SVN_NO_ERROR;
1435 svn_error_t *
1436 svn_fs_base__unparse_lock_skel(skel_t **skel_p,
1437 const svn_lock_t *lock,
1438 apr_pool_t *pool)
1440 skel_t *skel;
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);
1450 else
1451 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1453 /* CREATION-DATE */
1454 svn_fs_base__prepend
1455 (svn_fs_base__str_atom
1456 (svn_time_to_cstring(lock->creation_date, pool), pool), skel);
1458 /* XML_P */
1459 if (lock->is_dav_comment)
1460 svn_fs_base__prepend(svn_fs_base__str_atom("1", pool), skel);
1461 else
1462 svn_fs_base__prepend(svn_fs_base__str_atom("0", pool), skel);
1464 /* COMMENT */
1465 if (lock->comment)
1466 svn_fs_base__prepend(svn_fs_base__str_atom(lock->comment, pool), skel);
1467 else
1468 svn_fs_base__prepend(svn_fs_base__mem_atom(NULL, 0, pool), skel);
1470 /* OWNER */
1471 svn_fs_base__prepend(svn_fs_base__str_atom(lock->owner, pool), skel);
1473 /* LOCK-TOKEN */
1474 svn_fs_base__prepend(svn_fs_base__str_atom(lock->token, pool), skel);
1476 /* PATH */
1477 svn_fs_base__prepend(svn_fs_base__str_atom(lock->path, pool), skel);
1479 /* "lock" */
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");
1486 *skel_p = skel;
1487 return SVN_NO_ERROR;