1/**
2 * @copyright
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 * @endcopyright
22 *
23 * @file svn_element.h
24 * @brief Tree elements
25 *
26 * @since New in ???.
27 */
28
29#ifndef SVN_BRANCH_ELEMENT_H
30#define SVN_BRANCH_ELEMENT_H
31
32#include <apr_pools.h>
33#include <apr_tables.h>
34
35#include "svn_types.h"
36
37#ifdef __cplusplus
38extern "C" {
39#endif /* __cplusplus */
40
41
42/* ====================================================================== */
43
44/** Like apr_hash_get() but the hash key is an integer. */
45void *
46svn_eid__hash_get(apr_hash_t *ht,
47                  int key);
48
49/** Like apr_hash_set() but the hash key is an integer. */
50void
51svn_eid__hash_set(apr_hash_t *ht,
52                  int key,
53                  const void *val);
54
55/** Like apr_hash_this_key() but the hash key is an integer. */
56int
57svn_eid__hash_this_key(apr_hash_index_t *hi);
58
59struct svn_sort__item_t;
60
61/** A hash iterator for iterating over an array or a hash table in
62 * its natural order or in sorted order.
63 *
64 * For an array, the @a i and @a val members provide the index and value
65 * of the current item.
66 */
67typedef struct svn_eid__hash_iter_t
68{
69  /* private: an array of (svn_sort__item_t) hash items for sorted iteration */
70  const apr_array_header_t *array;
71
72  /* current element: iteration order index */
73  int i;
74  /* current element: key */
75  int eid;
76  /* current element: value */
77  void *val;
78} svn_eid__hash_iter_t;
79
80svn_eid__hash_iter_t *
81svn_eid__hash_sorted_first(apr_pool_t *pool,
82                           apr_hash_t *ht,
83                           int (*comparison_func)(const struct svn_sort__item_t *,
84                                                  const struct svn_sort__item_t *));
85
86svn_eid__hash_iter_t *
87svn_eid__hash_sorted_next(svn_eid__hash_iter_t *hi);
88
89/** A sort ordering callback function that returns an indication whether
90 * A sorts before or after or equal to B, by comparing their keys as EIDs.
91 */
92int
93svn_eid__hash_sort_compare_items_by_eid(const struct svn_sort__item_t *a,
94                                        const struct svn_sort__item_t *b);
95
96#define SVN_EID__HASH_ITER_SORTED(i, ht, comparison_func, pool) \
97  i = (void *)svn_eid__hash_sorted_first(pool, ht, comparison_func); \
98  i; \
99  i = (void *)svn_eid__hash_sorted_next((void *)i)
100
101#define SVN_EID__HASH_ITER_SORTED_BY_EID(i, ht, pool) \
102  SVN_EID__HASH_ITER_SORTED(i, ht, svn_eid__hash_sort_compare_items_by_eid, pool)
103
104
105/* ====================================================================== */
106
107/**
108 */
109typedef struct svn_element__branch_ref_t
110{
111  svn_revnum_t rev;
112  const char *branch_id;
113  int eid;
114} svn_element__branch_ref_t;
115
116/** Versioned payload of an element, excluding tree structure information.
117 *
118 * This specifies the properties and the text of a file or target of a
119 * symlink, directly, or by reference to an existing committed element, or
120 * by a delta against such a reference payload.
121 *
122 * ### An idea: If the sender and receiver agree, the payload for an element
123 *     may be specified as "null" to designate that the payload is not
124 *     available. For example, when a client performing a WC update has
125 *     no read authorization for a given path, the server may send null
126 *     payload and the client may record an 'absent' WC node. (This
127 *     would not make sense in a commit.)
128 */
129typedef struct svn_element__payload_t svn_element__payload_t;
130
131/*
132 * ========================================================================
133 * Element Payload Interface
134 * ========================================================================
135 *
136 * @defgroup svn_element_payload Element payload interface
137 * @{
138 */
139
140/** Versioned payload of a node, excluding tree structure information.
141 *
142 * Payload is described by setting fields in one of the following ways.
143 * Other fields SHOULD be null (or equivalent).
144 *
145 *   by reference:  (kind=unknown, ref)
146 *   dir:           (kind=dir, props)
147 *   file:          (kind=file, props, text)
148 *   symlink:       (kind=symlink, props, target)
149 *
150 * ### Idea for the future: Specify payload as an (optional) reference
151 *     plus (optional) overrides or deltas against the reference?
152 */
153struct svn_element__payload_t
154{
155  /* Is this a subbranch-root element, in other words a link to a nested
156   * branch? If so, all other fields are irrelevant. */
157  svn_boolean_t is_subbranch_root;
158
159  /* The node kind for this payload: dir, file, symlink, or unknown. */
160  svn_node_kind_t kind;
161
162  /* Reference an existing, committed payload. (Use with kind=unknown if
163   * there is no content in props/text/targe fields.)
164   * The 'null' value is (SVN_INVALID_REVNUM, NULL, *). */
165  svn_element__branch_ref_t branch_ref;
166
167  /* The pool in which the payload's content is allocated. Used when
168   * resolving (populating the props/text/target in) a payload that was
169   * originally defined by reference. */
170  apr_pool_t *pool;
171
172  /* Properties (for kind != unknown).
173   * Maps (const char *) name -> (svn_string_t) value.
174   * An empty hash means no properties. (SHOULD NOT be NULL.)
175   * ### Presently NULL means 'no change' in some contexts. */
176  apr_hash_t *props;
177
178  /* File text (for kind=file; otherwise SHOULD be NULL). */
179  svn_stringbuf_t *text;
180
181  /* Symlink target (for kind=symlink; otherwise SHOULD be NULL). */
182  const char *target;
183
184};
185
186/* Return true iff PAYLOAD satisfies all its invariants.
187 */
188svn_boolean_t
189svn_element__payload_invariants(const svn_element__payload_t *payload);
190
191/** Duplicate a node-payload @a old into @a result_pool.
192 */
193svn_element__payload_t *
194svn_element__payload_dup(const svn_element__payload_t *old,
195                         apr_pool_t *result_pool);
196
197/* Return true iff the payload of LEFT is identical to that of RIGHT.
198 * References are not supported. Node kind 'unknown' is not supported.
199 */
200svn_boolean_t
201svn_element__payload_equal(const svn_element__payload_t *left,
202                           const svn_element__payload_t *right,
203                           apr_pool_t *scratch_pool);
204
205/** Create a new node-payload object for a subbranch-root (link to a
206 * nested branch).
207 *
208 * Allocate the result in @a result_pool.
209 */
210svn_element__payload_t *
211svn_element__payload_create_subbranch(apr_pool_t *result_pool);
212
213/** Create a new node-payload object by reference to an existing payload.
214 *
215 * Set the node kind to 'unknown'.
216 *
217 * Allocate the result in @a result_pool.
218 */
219svn_element__payload_t *
220svn_element__payload_create_ref(svn_revnum_t rev,
221                                const char *branch_id,
222                                int eid,
223                                apr_pool_t *result_pool);
224
225/** Create a new node-payload object for a directory node.
226 *
227 * Allocate the result in @a result_pool.
228 */
229svn_element__payload_t *
230svn_element__payload_create_dir(apr_hash_t *props,
231                                apr_pool_t *result_pool);
232
233/** Create a new node-payload object for a file node.
234 *
235 * Allocate the result in @a result_pool.
236 */
237svn_element__payload_t *
238svn_element__payload_create_file(apr_hash_t *props,
239                                 svn_stringbuf_t *text,
240                                 apr_pool_t *result_pool);
241
242/** Create a new node-payload object for a symlink node.
243 *
244 * Allocate the result in @a result_pool.
245 */
246svn_element__payload_t *
247svn_element__payload_create_symlink(apr_hash_t *props,
248                                    const char *target,
249                                    apr_pool_t *result_pool);
250
251/** @} */
252
253
254/*
255 * ========================================================================
256 * Element-Revision Content
257 * ========================================================================
258 *
259 * @defgroup svn_el_rev_content Element-Revision Content
260 * @{
261 */
262
263/* The content (parent, name and payload) of an element-revision.
264 * In other words, an el-rev node in a (mixed-rev) directory-tree.
265 */
266typedef struct svn_element__content_t
267{
268  /* eid of the parent element, or -1 if this is the root element */
269  int parent_eid;
270  /* element name, or "" for root element; never null */
271  const char *name;
272  /* payload (kind, props, text, ...) */
273  svn_element__payload_t *payload;
274
275} svn_element__content_t;
276
277/* Return a new content object constructed with deep copies of PARENT_EID,
278 * NAME and PAYLOAD, allocated in RESULT_POOL.
279 */
280svn_element__content_t *
281svn_element__content_create(int parent_eid,
282                            const char *name,
283                            const svn_element__payload_t *payload,
284                            apr_pool_t *result_pool);
285
286/* Return a deep copy of OLD, allocated in RESULT_POOL.
287 */
288svn_element__content_t *
289svn_element__content_dup(const svn_element__content_t *old,
290                         apr_pool_t *result_pool);
291
292/* Return TRUE iff CONTENT_LEFT is the same as CONTENT_RIGHT. */
293svn_boolean_t
294svn_element__content_equal(const svn_element__content_t *content_left,
295                           const svn_element__content_t *content_right,
296                           apr_pool_t *scratch_pool);
297
298/** @} */
299
300
301/*
302 * ========================================================================
303 * Element Tree
304 * ========================================================================
305 *
306 * The elements in an Element Tree do not necessarily form a single,
307 * complete tree at all times.
308 *
309 * @defgroup svn_element_tree Element Tree
310 * @{
311 */
312
313/* A (sub)tree of elements.
314 *
315 * An element tree is described by the content of element ROOT_EID in E_MAP,
316 * and its children (as determined by their parent links) and their names
317 * and their content recursively. For the element ROOT_EID itself, only
318 * its content is relevant; its parent and name are to be ignored.
319 *
320 * E_MAP may also contain entries that are not part of the subtree. Thus,
321 * to select a sub-subtree, it is only necessary to change ROOT_EID.
322 *
323 * The EIDs used in here may be considered either as global EIDs (known to
324 * the repo), or as local stand-alone EIDs (in their own local name-space),
325 * according to the context.
326 */
327typedef struct svn_element__tree_t
328{
329  /* EID -> svn_element__content_t mapping. */
330  apr_hash_t *e_map;
331
332  /* Subtree root EID. (ROOT_EID must be an existing key in E_MAP.) */
333  int root_eid;
334
335} svn_element__tree_t;
336
337/* Create an element tree object.
338 *
339 * The result contains a *shallow* copy of E_MAP, or a new empty mapping
340 * if E_MAP is null.
341 */
342svn_element__tree_t *
343svn_element__tree_create(apr_hash_t *e_map,
344                         int root_eid,
345                         apr_pool_t *result_pool);
346
347svn_element__content_t *
348svn_element__tree_get(const svn_element__tree_t *tree,
349                      int eid);
350
351void
352svn_element__tree_set(svn_element__tree_t *tree,
353                      int eid,
354                      const svn_element__content_t *element);
355
356/* Purge entries from E_MAP that don't connect, via parent directory hierarchy,
357 * to ROOT_EID. In other words, remove elements that have been implicitly
358 * deleted.
359 *
360 * ROOT_EID must be present in E_MAP.
361 *
362 * ### Does not detect cycles: current implementation will not purge a cycle
363 *     that is disconnected from ROOT_EID. This could be a problem.
364 */
365void
366svn_element__tree_purge_orphans(apr_hash_t *e_map,
367                                int root_eid,
368                                apr_pool_t *scratch_pool);
369
370/* Return the subtree-relative path of element EID in TREE.
371 *
372 * If the element EID does not currently exist in TREE, return NULL.
373 *
374 * ### TODO: Clarify sequencing requirements.
375 */
376const char *
377svn_element__tree_get_path_by_eid(const svn_element__tree_t *tree,
378                                  int eid,
379                                  apr_pool_t *result_pool);
380
381/* Return the subtree rooted at EID within ELEMENT_TREE.
382 *
383 * The result is limited by the lifetime of ELEMENT_TREE. It includes a
384 * shallow copy of the mapping in ELEMENT_TREE: the hash table is
385 * duplicated but the keys and values (element content data) are not.
386 */
387svn_element__tree_t *
388svn_element__tree_get_subtree_at_eid(svn_element__tree_t *element_tree,
389                                     int eid,
390                                     apr_pool_t *result_pool);
391
392/** @} */
393
394
395#ifdef __cplusplus
396}
397#endif /* __cplusplus */
398
399#endif /* SVN_BRANCH_ELEMENT_H */
400