1 /* dag.h : DAG-like interface filesystem
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 #ifndef SVN_LIBSVN_FS_X_DAG_H
24 #define SVN_LIBSVN_FS_X_DAG_H
25 
26 #include "svn_fs.h"
27 #include "svn_delta.h"
28 #include "private/svn_cache.h"
29 
30 #include "fs.h"
31 #include "id.h"
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif /* __cplusplus */
36 
37 
38 /* The interface in this file provides all the essential filesystem
39    operations, but exposes the filesystem's DAG structure.  This makes
40    it simpler to implement than the public interface, since a client
41    of this interface has to understand and cope with shared structure
42    directly as it appears in the database.  However, it's still a
43    self-consistent set of invariants to maintain, making it
44    (hopefully) a useful interface boundary.
45 
46    In other words:
47 
48    - The dag_node_t interface exposes the internal DAG structure of
49      the filesystem, while the svn_fs.h interface does any cloning
50      necessary to make the filesystem look like a tree.
51 
52    - The dag_node_t interface exposes the existence of copy nodes,
53      whereas the svn_fs.h handles them transparently.
54 
55    - dag_node_t's must be explicitly cloned, whereas the svn_fs.h
56      operations make clones implicitly.
57 
58    - Callers of the dag_node_t interface use Berkeley DB transactions
59      to ensure consistency between operations, while callers of the
60      svn_fs.h interface use Subversion transactions.  */
61 
62 
63 /* Generic DAG node stuff.  */
64 
65 typedef struct dag_node_t dag_node_t;
66 
67 /* Fill *NODE with a dag_node_t representing node revision ID in FS,
68    allocating in RESULT_POOL.  Use SCRATCH_POOL for temporaries. */
69 svn_error_t *
70 svn_fs_x__dag_get_node(dag_node_t **node,
71                        svn_fs_t *fs,
72                        const svn_fs_x__id_t *id,
73                        apr_pool_t *result_pool,
74                        apr_pool_t *scratch_pool);
75 
76 
77 /* Return a new dag_node_t object referring to the same node as NODE,
78    allocated in RESULT_POOL.  If you're trying to build a structure in a
79    pool that wants to refer to dag nodes that may have been allocated
80    elsewhere, you can call this function and avoid inter-pool pointers. */
81 dag_node_t *
82 svn_fs_x__dag_dup(const dag_node_t *node,
83                   apr_pool_t *result_pool);
84 
85 /* Return the filesystem containing NODE.  */
86 svn_fs_t *
87 svn_fs_x__dag_get_fs(dag_node_t *node);
88 
89 /* Changes the filesystem containing NODE to FS.  (Used when pulling
90    nodes out of a shared cache, say.) */
91 void
92 svn_fs_x__dag_set_fs(dag_node_t *node,
93                      svn_fs_t *fs);
94 
95 
96 /* Return NODE's revision number.  If NODE has never been committed as
97    part of a revision, set *REV to SVN_INVALID_REVNUM.  */
98 svn_revnum_t
99 svn_fs_x__dag_get_revision(const dag_node_t *node);
100 
101 
102 /* Return the node revision ID of NODE.  The value returned is shared
103    with NODE, and will be deallocated when NODE is.  */
104 const svn_fs_x__id_t *
105 svn_fs_x__dag_get_id(const dag_node_t *node);
106 
107 /* Return the node ID of NODE.  The value returned is shared with NODE,
108    and will be deallocated when NODE is.  */
109 const svn_fs_x__id_t *
110 svn_fs_x__dag_get_node_id(dag_node_t *node);
111 
112 /* Return the copy ID of NODE.  The value returned is shared with NODE,
113    and will be deallocated when NODE is.  */
114 const svn_fs_x__id_t *
115 svn_fs_x__dag_get_copy_id(dag_node_t *node);
116 
117 /* Return TRUE, iff nodes LHS and RHS have the same node ID. */
118 svn_boolean_t
119 svn_fs_x__dag_related_node(dag_node_t *lhs,
120                            dag_node_t *rhs);
121 
122 /* Return TRUE, iff nodes LHS and RHS have the same node and copy IDs.
123  */
124 svn_boolean_t
125 svn_fs_x__dag_same_line_of_history(dag_node_t *lhs,
126                                    dag_node_t *rhs);
127 
128 /* Return the created path of NODE.  The value returned is shared
129    with NODE, and will be deallocated when NODE is.  */
130 const char *
131 svn_fs_x__dag_get_created_path(dag_node_t *node);
132 
133 
134 /* Return the node revision ID of NODE's immediate predecessor.
135  */
136 const svn_fs_x__id_t *
137 svn_fs_x__dag_get_predecessor_id(dag_node_t *node);
138 
139 /* Return the number of predecessors NODE has (recursively).
140  */
141 int
142 svn_fs_x__dag_get_predecessor_count(dag_node_t *node);
143 
144 /* Return the number of node under NODE (inclusive) with svn:mergeinfo
145    properties.
146  */
147 apr_int64_t
148 svn_fs_x__dag_get_mergeinfo_count(dag_node_t *node);
149 
150 /* Return TRUE, iff NODE is a directory with at least one descendant (not
151    including itself) with svn:mergeinfo.
152  */
153 svn_boolean_t
154 svn_fs_x__dag_has_descendants_with_mergeinfo(dag_node_t *node);
155 
156 /* Return TRUE, iff NODE itself has svn:mergeinfo set on it.  */
157 svn_boolean_t
158 svn_fs_x__dag_has_mergeinfo(dag_node_t *node);
159 
160 /* Return non-zero IFF NODE is currently mutable. */
161 svn_boolean_t
162 svn_fs_x__dag_check_mutable(const dag_node_t *node);
163 
164 /* Return the node kind of NODE. */
165 svn_node_kind_t
166 svn_fs_x__dag_node_kind(dag_node_t *node);
167 
168 /* Set *PROPLIST_P to a PROPLIST hash representing the entire property
169    list of NODE, allocating from POOL.  The hash has const char *
170    names (the property names) and svn_string_t * values (the property
171    values).
172 
173    If properties do not exist on NODE, *PROPLIST_P will be set to
174    NULL.
175 
176    Allocate the result in RESULT_POOL and use SCRATCH_POOL for temporaries.
177  */
178 svn_error_t *
179 svn_fs_x__dag_get_proplist(apr_hash_t **proplist_p,
180                            dag_node_t *node,
181                            apr_pool_t *result_pool,
182                            apr_pool_t *scratch_pool);
183 
184 /* Set the property list of NODE to PROPLIST, allocating from POOL.
185    The node being changed must be mutable.
186 
187    Use SCRATCH_POOL for temporary allocations.
188  */
189 svn_error_t *
190 svn_fs_x__dag_set_proplist(dag_node_t *node,
191                            apr_hash_t *proplist,
192                            apr_pool_t *scratch_pool);
193 
194 /* Increment the mergeinfo_count field on NODE by INCREMENT.  The node
195    being changed must be mutable.
196 
197    Use SCRATCH_POOL for temporary allocations.
198  */
199 svn_error_t *
200 svn_fs_x__dag_increment_mergeinfo_count(dag_node_t *node,
201                                         apr_int64_t increment,
202                                         apr_pool_t *scratch_pool);
203 
204 /* Set the has-mergeinfo flag on NODE to HAS_MERGEINFO.  The node
205    being changed must be mutable.
206 
207    Use SCRATCH_POOL for temporary allocations.
208  */
209 svn_error_t *
210 svn_fs_x__dag_set_has_mergeinfo(dag_node_t *node,
211                                 svn_boolean_t has_mergeinfo,
212                                 apr_pool_t *scratch_pool);
213 
214 
215 
216 /* Revision and transaction roots.  */
217 
218 
219 /* Open the root of change set CHANGE_SET of filesystem FS, allocating from
220    RESULT_POOL.  Set *NODE_P to the new node.  Use SCRATCH_POOL for
221    temporary allocations.*/
222 svn_error_t *
223 svn_fs_x__dag_root(dag_node_t **node_p,
224                    svn_fs_t *fs,
225                    svn_fs_x__change_set_t change_set,
226                    apr_pool_t *result_pool,
227                    apr_pool_t *scratch_pool);
228 
229 
230 /* Directories.  */
231 
232 
233 /* Open the node named NAME in the directory PARENT.  Set *CHILD_P to
234    the new node, allocated in RESULT_POOL.  NAME must be a single path
235    component; it cannot be a slash-separated directory path.  If NAME does
236    not exist within PARENT, set *CHILD_P to NULL.
237  */
238 svn_error_t *
239 svn_fs_x__dag_open(dag_node_t **child_p,
240                    dag_node_t *parent,
241                    const char *name,
242                    apr_pool_t *result_pool,
243                    apr_pool_t *scratch_pool);
244 
245 
246 /* Set *ID_P to the noderev-id for entry NAME in PARENT.  If no such
247    entry exists, set *ID_P to "unused" but do not error. */
248 svn_error_t *
249 svn_fs_x__dir_entry_id(svn_fs_x__id_t *id_p,
250                        dag_node_t *parent,
251                        const char *name,
252                        apr_pool_t *scratch_pool);
253 
254 /* Set *ENTRIES_P to an array of NODE's entries, sorted by entry names,
255    and the values are svn_fs_x__dirent_t. The returned table (and elements)
256    is allocated in RESULT_POOL, temporaries in SCRATCH_POOL. */
257 svn_error_t *
258 svn_fs_x__dag_dir_entries(apr_array_header_t **entries_p,
259                           dag_node_t *node,
260                           apr_pool_t *result_pool,
261                           apr_pool_t *scratch_pool);
262 
263 /* Set ENTRY_NAME in NODE to point to ID (with kind KIND), allocating
264    from POOL.  NODE must be a mutable directory.  ID can refer to a
265    mutable or immutable node.  If ENTRY_NAME does not exist, it will
266    be created.  TXN_ID is the Subversion transaction under which this
267    occurs.
268 
269    Use SCRATCH_POOL for temporary allocations.
270  */
271 svn_error_t *
272 svn_fs_x__dag_set_entry(dag_node_t *node,
273                         const char *entry_name,
274                         const svn_fs_x__id_t *id,
275                         svn_node_kind_t kind,
276                         svn_fs_x__txn_id_t txn_id,
277                         apr_pool_t *scratch_pool);
278 
279 
280 /* Make a new mutable clone of the node named NAME in PARENT, and
281    adjust PARENT's directory entry to point to it, unless NAME in
282    PARENT already refers to a mutable node.  In either case, set
283    *CHILD_P to a reference to the new node, allocated in POOL.  PARENT
284    must be mutable.  NAME must be a single path component; it cannot
285    be a slash-separated directory path.  PARENT_PATH must be the
286    canonicalized absolute path of the parent directory.
287 
288    COPY_ID, if non-NULL, is a key into the `copies' table, and
289    indicates that this new node is being created as the result of a
290    copy operation, and specifically which operation that was.
291 
292    PATH is the canonicalized absolute path at which this node is being
293    created.
294 
295    TXN_ID is the Subversion transaction under which this occurs.
296 
297    Allocate *CHILD_P in RESULT_POOL and use SCRATCH_POOL for temporaries.
298  */
299 svn_error_t *
300 svn_fs_x__dag_clone_child(dag_node_t **child_p,
301                           dag_node_t *parent,
302                           const char *parent_path,
303                           const char *name,
304                           const svn_fs_x__id_t *copy_id,
305                           svn_fs_x__txn_id_t txn_id,
306                           svn_boolean_t is_parent_copyroot,
307                           apr_pool_t *result_pool,
308                           apr_pool_t *scratch_pool);
309 
310 
311 /* Delete the directory entry named NAME from PARENT, allocating from
312    POOL.  PARENT must be mutable.  NAME must be a single path
313    component; it cannot be a slash-separated directory path.  If the
314    node being deleted is a mutable directory, remove all mutable nodes
315    reachable from it.  TXN_ID is the Subversion transaction under
316    which this occurs.
317 
318    If return SVN_ERR_FS_NO_SUCH_ENTRY, then there is no entry NAME in
319    PARENT.
320 
321    Use SCRATCH_POOL for temporary allocations.
322  */
323 svn_error_t *
324 svn_fs_x__dag_delete(dag_node_t *parent,
325                      const char *name,
326                      svn_fs_x__txn_id_t txn_id,
327                      apr_pool_t *scratch_pool);
328 
329 
330 /* Create a new mutable directory named NAME in PARENT.  Set *CHILD_P
331    to a reference to the new node, allocated in RESULT_POOL.  The new
332    directory has no contents, and no properties.  PARENT must be
333    mutable.  NAME must be a single path component; it cannot be a
334    slash-separated directory path.  PARENT_PATH must be the
335    canonicalized absolute path of the parent directory.  PARENT must
336    not currently have an entry named NAME.  TXN_ID is the Subversion
337    transaction under which this occurs.
338 
339    Use SCRATCH_POOL for temporary allocations.
340  */
341 svn_error_t *
342 svn_fs_x__dag_make_dir(dag_node_t **child_p,
343                        dag_node_t *parent,
344                        const char *parent_path,
345                        const char *name,
346                        svn_fs_x__txn_id_t txn_id,
347                        apr_pool_t *result_pool,
348                        apr_pool_t *scratch_pool);
349 
350 
351 
352 /* Files.  */
353 
354 
355 /* Set *CONTENTS to a readable generic stream which yields the
356    contents of FILE.  Allocate the stream in RESULT_POOL.
357 
358    If FILE is not a file, return SVN_ERR_FS_NOT_FILE.
359  */
360 svn_error_t *
361 svn_fs_x__dag_get_contents(svn_stream_t **contents,
362                            dag_node_t *file,
363                            apr_pool_t *result_pool);
364 
365 /* Attempt to fetch the contents of NODE and pass it along with the BATON
366    to the PROCESSOR.   Set *SUCCESS only of the data could be provided
367    and the processor had been called.
368 
369    Use SCRATCH_POOL for temporary allocations.
370  */
371 svn_error_t *
372 svn_fs_x__dag_try_process_file_contents(svn_boolean_t *success,
373                                         dag_node_t *node,
374                                         svn_fs_process_contents_func_t processor,
375                                         void* baton,
376                                         apr_pool_t *scratch_pool);
377 
378 
379 /* Set *STREAM_P to a delta stream that will turn the contents of SOURCE into
380    the contents of TARGET, allocated in RESULT_POOL.  If SOURCE is null, the
381    empty string will be used is its stead.
382 
383    Use SCRATCH_POOL for temporary allocations.
384  */
385 svn_error_t *
386 svn_fs_x__dag_get_file_delta_stream(svn_txdelta_stream_t **stream_p,
387                                     dag_node_t *source,
388                                     dag_node_t *target,
389                                     apr_pool_t *result_pool,
390                                     apr_pool_t *scratch_pool);
391 
392 /* Return a generic writable stream in *CONTENTS with which to set the
393    contents of FILE.  Allocate the stream in RESULT_POOL.
394 
395    Any previous edits on the file will be deleted, and a new edit
396    stream will be constructed.
397  */
398 svn_error_t *
399 svn_fs_x__dag_get_edit_stream(svn_stream_t **contents,
400                               dag_node_t *file,
401                               apr_pool_t *result_pool);
402 
403 
404 /* Signify the completion of edits to FILE made using the stream
405    returned by svn_fs_x__dag_get_edit_stream.
406 
407    If CHECKSUM is non-null, it must match the checksum for FILE's
408    contents (note: this is not recalculated, the recorded checksum is
409    used), else the error SVN_ERR_CHECKSUM_MISMATCH is returned.
410 
411    This operation is a no-op if no edits are present.
412 
413    Use SCRATCH_POOL for temporary allocations.
414  */
415 svn_error_t *
416 svn_fs_x__dag_finalize_edits(dag_node_t *file,
417                              const svn_checksum_t *checksum,
418                              apr_pool_t *scratch_pool);
419 
420 
421 /* Set *LENGTH to the length of the contents of FILE.
422  */
423 svn_error_t *
424 svn_fs_x__dag_file_length(svn_filesize_t *length,
425                           dag_node_t *file);
426 
427 /* Put the recorded checksum of type KIND for FILE into CHECKSUM, allocating
428    from RESULT_POOL.
429 
430    If no stored checksum is available, do not calculate the checksum,
431    just put NULL into CHECKSUM.
432  */
433 svn_error_t *
434 svn_fs_x__dag_file_checksum(svn_checksum_t **checksum,
435                             dag_node_t *file,
436                             svn_checksum_kind_t kind,
437                             apr_pool_t *result_pool);
438 
439 /* Create a new mutable file named NAME in PARENT.  Set *CHILD_P to a
440    reference to the new node, allocated in RESULT_POOL.  The new file's
441    contents are the empty string, and it has no properties.  PARENT
442    must be mutable.  NAME must be a single path component; it cannot
443    be a slash-separated directory path.  PARENT_PATH must be the
444    canonicalized absolute path of the parent directory.  TXN_ID is the
445    Subversion transaction under which this occurs.
446 
447    Use SCRATCH_POOL for temporary allocations.
448  */
449 svn_error_t *
450 svn_fs_x__dag_make_file(dag_node_t **child_p,
451                         dag_node_t *parent,
452                         const char *parent_path,
453                         const char *name,
454                         svn_fs_x__txn_id_t txn_id,
455                         apr_pool_t *result_pool,
456                         apr_pool_t *scratch_pool);
457 
458 
459 
460 /* Copies */
461 
462 /* Make ENTRY in TO_NODE be a copy of FROM_NODE.  TO_NODE must be mutable.
463    TXN_ID is the Subversion transaction under which this occurs.
464 
465    If PRESERVE_HISTORY is true, the new node will record that it was
466    copied from FROM_PATH in FROM_REV; therefore, FROM_NODE should be
467    the node found at FROM_PATH in FROM_REV, although this is not
468    checked.  FROM_PATH should be canonicalized before being passed
469    here.
470 
471    If PRESERVE_HISTORY is false, FROM_PATH and FROM_REV are ignored.
472 
473    Use SCRATCH_POOL for temporary allocations.
474  */
475 svn_error_t *
476 svn_fs_x__dag_copy(dag_node_t *to_node,
477                    const char *entry,
478                    dag_node_t *from_node,
479                    svn_boolean_t preserve_history,
480                    svn_revnum_t from_rev,
481                    const char *from_path,
482                    svn_fs_x__txn_id_t txn_id,
483                    apr_pool_t *scratch_pool);
484 
485 
486 /* Comparison */
487 
488 /* Find out what is the same between two nodes.  If STRICT is FALSE,
489    this function may report false positives, i.e. report changes even
490    if the resulting contents / props are equal.
491 
492    If PROPS_CHANGED is non-null, set *PROPS_CHANGED to 1 if the two
493    nodes have different property lists, or to 0 if same.
494 
495    If CONTENTS_CHANGED is non-null, set *CONTENTS_CHANGED to 1 if the
496    two nodes have different contents, or to 0 if same.  NODE1 and NODE2
497    must refer to files from the same filesystem.
498 
499    Use SCRATCH_POOL for temporary allocations.
500  */
501 svn_error_t *
502 svn_fs_x__dag_things_different(svn_boolean_t *props_changed,
503                                svn_boolean_t *contents_changed,
504                                dag_node_t *node1,
505                                dag_node_t *node2,
506                                svn_boolean_t strict,
507                                apr_pool_t *scratch_pool);
508 
509 
510 /* Set *REV and *PATH to the copyroot revision and path of node NODE, or
511    to SVN_INVALID_REVNUM and NULL if no copyroot exists.
512  */
513 void
514 svn_fs_x__dag_get_copyroot(svn_revnum_t *rev,
515                            const char **path,
516                            dag_node_t *node);
517 
518 /* Return the copyfrom revision associated with NODE.
519  */
520 svn_revnum_t
521 svn_fs_x__dag_get_copyfrom_rev(dag_node_t *node);
522 
523 /* Return the copyfrom path associated with NODE.
524  */
525 const char *
526 svn_fs_x__dag_get_copyfrom_path(dag_node_t *node);
527 
528 /* Update *TARGET so that SOURCE is it's predecessor.
529 
530    Use SCRATCH_POOL for temporary allocations.
531  */
532 svn_error_t *
533 svn_fs_x__dag_update_ancestry(dag_node_t *target,
534                               dag_node_t *source,
535                               apr_pool_t *scratch_pool);
536 #ifdef __cplusplus
537 }
538 #endif /* __cplusplus */
539 
540 #endif /* SVN_LIBSVN_FS_X_DAG_H */
541