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