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