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 
24 /* This file is not for general consumption; it should only be used by
25    wc_db.c. */
26 #ifndef SVN_WC__I_AM_WC_DB
27 #error "You should not be using these data structures directly"
28 #endif /* SVN_WC__I_AM_WC_DB */
29 
30 #ifndef WC_DB_PRIVATE_H
31 #define WC_DB_PRIVATE_H
32 
33 #include "wc_db.h"
34 
35 
36 struct svn_wc__db_t {
37   /* We need the config whenever we run into a new WC directory, in order
38      to figure out where we should look for the corresponding datastore. */
39   svn_config_t *config;
40 
41   /* Should we fail with SVN_ERR_WC_UPGRADE_REQUIRED when it is
42      opened, and found to be not-current?  */
43   svn_boolean_t verify_format;
44 
45   /* Should we ensure the WORK_QUEUE is empty when a DB is locked
46    * for writing?  */
47   svn_boolean_t enforce_empty_wq;
48 
49   /* Should we open Sqlite databases EXCLUSIVE */
50   svn_boolean_t exclusive;
51 
52   /* Busy timeout in ms., 0 for the libsvn_subr default. */
53   apr_int32_t timeout;
54 
55   /* Map a given working copy directory to its relevant data.
56      const char *local_abspath -> svn_wc__db_wcroot_t *wcroot  */
57   apr_hash_t *dir_data;
58 
59   /* A few members to assist with caching of kind values for paths.  See
60      get_path_kind() for use. */
61   struct
62   {
63     svn_stringbuf_t *abspath;
64     svn_node_kind_t kind;
65   } parse_cache;
66 
67   /* As we grow the state of this DB, allocate that state here. */
68   apr_pool_t *state_pool;
69 };
70 
71 
72 /* Hold information about an owned lock */
73 typedef struct svn_wc__db_wclock_t
74 {
75   /* Relative path of the lock root */
76   const char *local_relpath;
77 
78   /* Number of levels locked (0 for infinity) */
79   int levels;
80 } svn_wc__db_wclock_t;
81 
82 
83 /** Hold information about a WCROOT.
84  *
85  * This structure is referenced by all per-directory handles underneath it.
86  */
87 typedef struct svn_wc__db_wcroot_t {
88   /* Location of this wcroot in the filesystem.  */
89   const char *abspath;
90 
91   /* The SQLite database containing the metadata for everything in
92      this wcroot.  */
93   svn_sqlite__db_t *sdb;
94 
95   /* The WCROOT.id for this directory (and all its children).  */
96   apr_int64_t wc_id;
97 
98   /* The format of this wcroot's metadata storage (see wc.h). If the
99      format has not (yet) been determined, this will be UNKNOWN_FORMAT.  */
100   int format;
101 
102   /* Array of svn_wc__db_wclock_t structures (not pointers!).
103      Typically just one or two locks maximum. */
104   apr_array_header_t *owned_locks;
105 
106   /* Map a working copy directory to a cached adm_access baton.
107      const char *local_abspath -> svn_wc_adm_access_t *adm_access */
108   apr_hash_t *access_cache;
109 
110 } svn_wc__db_wcroot_t;
111 
112 
113 /* */
114 svn_error_t *
115 svn_wc__db_close_many_wcroots(apr_hash_t *roots,
116                               apr_pool_t *state_pool,
117                               apr_pool_t *scratch_pool);
118 
119 
120 /* Construct a new svn_wc__db_wcroot_t. The WCROOT_ABSPATH and SDB parameters
121    must have lifetime of at least RESULT_POOL.  */
122 svn_error_t *
123 svn_wc__db_pdh_create_wcroot(svn_wc__db_wcroot_t **wcroot,
124                              const char *wcroot_abspath,
125                              svn_sqlite__db_t *sdb,
126                              apr_int64_t wc_id,
127                              int format,
128                              svn_boolean_t verify_format,
129                              apr_pool_t *result_pool,
130                              apr_pool_t *scratch_pool);
131 
132 
133 /* For a given LOCAL_ABSPATH, figure out what sqlite database (WCROOT) to
134    use and the RELPATH within that wcroot.
135 
136    *LOCAL_RELPATH will be allocated within RESULT_POOL. Temporary allocations
137    will be made in SCRATCH_POOL.
138 
139    *WCROOT will be allocated within DB->STATE_POOL.
140 
141    Certain internal structures will be allocated in DB->STATE_POOL.
142 */
143 svn_error_t *
144 svn_wc__db_wcroot_parse_local_abspath(svn_wc__db_wcroot_t **wcroot,
145                                       const char **local_relpath,
146                                       svn_wc__db_t *db,
147                                       const char *local_abspath,
148                                       apr_pool_t *result_pool,
149                                       apr_pool_t *scratch_pool);
150 
151 /* Return an error if the work queue in SDB is non-empty. */
152 svn_error_t *
153 svn_wc__db_verify_no_work(svn_sqlite__db_t *sdb);
154 
155 /* Assert that the given WCROOT is usable.
156    NOTE: the expression is multiply-evaluated!!  */
157 #define VERIFY_USABLE_WCROOT(wcroot)  SVN_ERR_ASSERT(               \
158     (wcroot) != NULL && (wcroot)->format == SVN_WC__VERSION)
159 
160 /* Check if the WCROOT is usable for light db operations such as path
161    calculations */
162 #define CHECK_MINIMAL_WCROOT(wcroot, abspath, scratch_pool)             \
163     do                                                                  \
164     {                                                                   \
165       if (wcroot == NULL)                                               \
166         return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,     \
167                     _("The node '%s' is not in a working copy."),       \
168                              svn_dirent_local_style(wri_abspath,        \
169                                                     scratch_pool));     \
170     }                                                                   \
171     while (0)
172 
173 /* Calculates the depth of the relpath below "" */
174 APR_INLINE static int
relpath_depth(const char * relpath)175 relpath_depth(const char *relpath)
176 {
177   int n = 1;
178   if (*relpath == '\0')
179     return 0;
180 
181   do
182   {
183     if (*relpath == '/')
184       n++;
185   }
186   while (*(++relpath));
187 
188   return n;
189 }
190 
191 
192 /* */
193 svn_error_t *
194 svn_wc__db_util_fetch_wc_id(apr_int64_t *wc_id,
195                             svn_sqlite__db_t *sdb,
196                             apr_pool_t *scratch_pool);
197 
198 /* Open a connection in *SDB to the WC database found in the WC metadata
199  * directory inside DIR_ABSPATH, having the filename SDB_FNAME.
200  *
201  * SMODE, EXCLUSIVE and TIMEOUT are passed to svn_sqlite__open().
202  *
203  * Register MY_STATEMENTS, or if that is null, the default set of WC DB
204  * statements, as the set of statements to be prepared now and executed
205  * later.  MY_STATEMENTS (the strings and the array itself) is not duplicated
206  * internally, and should have a lifetime at least as long as RESULT_POOL.
207  * See svn_sqlite__open() for details. */
208 svn_error_t *
209 svn_wc__db_util_open_db(svn_sqlite__db_t **sdb,
210                         const char *dir_abspath,
211                         const char *sdb_fname,
212                         svn_sqlite__mode_t smode,
213                         svn_boolean_t exclusive,
214                         apr_int32_t timeout,
215                         const char *const *my_statements,
216                         apr_pool_t *result_pool,
217                         apr_pool_t *scratch_pool);
218 
219 /* Like svn_wc__db_wq_add() but taking WCROOT */
220 svn_error_t *
221 svn_wc__db_wq_add_internal(svn_wc__db_wcroot_t *wcroot,
222                            const svn_skel_t *work_item,
223                            apr_pool_t *scratch_pool);
224 
225 
226 /* Like svn_wc__db_read_info(), but taking WCROOT+LOCAL_RELPATH instead of
227    DB+LOCAL_ABSPATH, and outputting repos ids instead of URL+UUID. */
228 svn_error_t *
229 svn_wc__db_read_info_internal(svn_wc__db_status_t *status,
230                               svn_node_kind_t *kind,
231                               svn_revnum_t *revision,
232                               const char **repos_relpath,
233                               apr_int64_t *repos_id,
234                               svn_revnum_t *changed_rev,
235                               apr_time_t *changed_date,
236                               const char **changed_author,
237                               svn_depth_t *depth,
238                               const svn_checksum_t **checksum,
239                               const char **target,
240                               const char **original_repos_relpath,
241                               apr_int64_t *original_repos_id,
242                               svn_revnum_t *original_revision,
243                               svn_wc__db_lock_t **lock,
244                               svn_filesize_t *recorded_size,
245                               apr_time_t *recorded_mod_time,
246                               const char **changelist,
247                               svn_boolean_t *conflicted,
248                               svn_boolean_t *op_root,
249                               svn_boolean_t *had_props,
250                               svn_boolean_t *props_mod,
251                               svn_boolean_t *have_base,
252                               svn_boolean_t *have_more_work,
253                               svn_boolean_t *have_work,
254                               svn_wc__db_wcroot_t *wcroot,
255                               const char *local_relpath,
256                               apr_pool_t *result_pool,
257                               apr_pool_t *scratch_pool);
258 
259 /* Like svn_wc__db_base_get_info(), but taking WCROOT+LOCAL_RELPATH instead of
260    DB+LOCAL_ABSPATH and outputting REPOS_ID instead of URL+UUID. */
261 svn_error_t *
262 svn_wc__db_base_get_info_internal(svn_wc__db_status_t *status,
263                                   svn_node_kind_t *kind,
264                                   svn_revnum_t *revision,
265                                   const char **repos_relpath,
266                                   apr_int64_t *repos_id,
267                                   svn_revnum_t *changed_rev,
268                                   apr_time_t *changed_date,
269                                   const char **changed_author,
270                                   svn_depth_t *depth,
271                                   const svn_checksum_t **checksum,
272                                   const char **target,
273                                   svn_wc__db_lock_t **lock,
274                                   svn_boolean_t *had_props,
275                                   apr_hash_t **props,
276                                   svn_boolean_t *update_root,
277                                   svn_wc__db_wcroot_t *wcroot,
278                                   const char *local_relpath,
279                                   apr_pool_t *result_pool,
280                                   apr_pool_t *scratch_pool);
281 
282 /* Similar to svn_wc__db_base_get_info(), but taking WCROOT+LOCAL_RELPATH
283  * instead of DB+LOCAL_ABSPATH, an explicit op-depth of the node to get
284  * information about, and outputting REPOS_ID instead of URL+UUID, and
285  * without the LOCK or UPDATE_ROOT outputs.
286  *
287  * OR
288  *
289  * Similar to svn_wc__db_base_get_info_internal(), but taking an explicit
290  * op-depth OP_DEPTH of the node to get information about, and without the
291  * LOCK or UPDATE_ROOT outputs.
292  *
293  * ### [JAF] TODO: Harmonize svn_wc__db_base_get_info[_internal] with
294  * svn_wc__db_depth_get_info -- common API, common implementation.
295  */
296 svn_error_t *
297 svn_wc__db_depth_get_info(svn_wc__db_status_t *status,
298                           svn_node_kind_t *kind,
299                           svn_revnum_t *revision,
300                           const char **repos_relpath,
301                           apr_int64_t *repos_id,
302                           svn_revnum_t *changed_rev,
303                           apr_time_t *changed_date,
304                           const char **changed_author,
305                           svn_depth_t *depth,
306                           const svn_checksum_t **checksum,
307                           const char **target,
308                           svn_boolean_t *had_props,
309                           apr_hash_t **props,
310                           svn_wc__db_wcroot_t *wcroot,
311                           const char *local_relpath,
312                           int op_depth,
313                           apr_pool_t *result_pool,
314                           apr_pool_t *scratch_pool);
315 
316 svn_error_t *
317 svn_wc__db_scan_addition_internal(
318               svn_wc__db_status_t *status,
319               const char **op_root_relpath_p,
320               const char **repos_relpath,
321               apr_int64_t *repos_id,
322               const char **original_repos_relpath,
323               apr_int64_t *original_repos_id,
324               svn_revnum_t *original_revision,
325               svn_wc__db_wcroot_t *wcroot,
326               const char *local_relpath,
327               apr_pool_t *result_pool,
328               apr_pool_t *scratch_pool);
329 
330 svn_error_t *
331 svn_wc__db_scan_deletion_internal(
332                   const char **base_del_relpath,
333                   const char **moved_to_relpath,
334                   const char **work_del_relpath,
335                   const char **moved_to_op_root_relpath,
336                   svn_wc__db_wcroot_t *wcroot,
337                   const char *local_relpath,
338                   apr_pool_t *result_pool,
339                   apr_pool_t *scratch_pool);
340 
341 
342 /* Look up REPOS_ID in WCROOT->SDB and set *REPOS_ROOT_URL and/or *REPOS_UUID
343    to its root URL and UUID respectively.  If REPOS_ID is INVALID_REPOS_ID,
344    use NULL for both URL and UUID.  Either or both output parameters may be
345    NULL if not wanted.  */
346 svn_error_t *
347 svn_wc__db_fetch_repos_info(const char **repos_root_url,
348                             const char **repos_uuid,
349                             svn_wc__db_wcroot_t *wcroot,
350                             apr_int64_t repos_id,
351                             apr_pool_t *result_pool);
352 
353 /* Like svn_wc__db_read_conflict(), but with WCROOT+LOCAL_RELPATH instead of
354    DB+LOCAL_ABSPATH, and outputting relpaths instead of abspaths. */
355 svn_error_t *
356 svn_wc__db_read_conflict_internal(svn_skel_t **conflict,
357                                   svn_node_kind_t *kind,
358                                   apr_hash_t **props,
359                                   svn_wc__db_wcroot_t *wcroot,
360                                   const char *local_relpath,
361                                   apr_pool_t *result_pool,
362                                   apr_pool_t *scratch_pool);
363 
364 /* Like svn_wc__db_op_mark_conflict(), but with WCROOT+LOCAL_RELPATH instead of
365    DB+LOCAL_ABSPATH. */
366 svn_error_t *
367 svn_wc__db_mark_conflict_internal(svn_wc__db_wcroot_t *wcroot,
368                                   const char *local_relpath,
369                                   const svn_skel_t *conflict_skel,
370                                   apr_pool_t *scratch_pool);
371 
372 
373 /* Transaction handling */
374 
375 /* Evaluate the expression EXPR within a transaction.
376  *
377  * Begin a transaction in WCROOT's DB; evaluate the expression EXPR, which would
378  * typically be a function call that does some work in DB; finally commit
379  * the transaction if EXPR evaluated to SVN_NO_ERROR, otherwise roll back
380  * the transaction.
381  */
382 #define SVN_WC__DB_WITH_TXN(expr, wcroot) \
383   SVN_SQLITE__WITH_LOCK(expr, (wcroot)->sdb)
384 
385 
386 /* Evaluate the expressions EXPR1..EXPR4 within a transaction, returning the
387  * first error if an error occurs.
388  *
389  * Begin a transaction in WCROOT's DB; evaluate the expressions, which would
390  * typically be  function calls that do some work in DB; finally commit
391  * the transaction if EXPR evaluated to SVN_NO_ERROR, otherwise roll back
392  * the transaction.
393  */
394 #define SVN_WC__DB_WITH_TXN4(expr1, expr2, expr3, expr4, wcroot) \
395   SVN_SQLITE__WITH_LOCK4(expr1, expr2, expr3, expr4, (wcroot)->sdb)
396 
397 /* Update the single op-depth layer in the move destination subtree
398    rooted at DST_RELPATH to make it match the move source subtree
399    rooted at SRC_RELPATH. */
400 svn_error_t *
401 svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot,
402                                   const char *src_op_relpath,
403                                   int src_op_depth,
404                                   const char *dst_op_relpath,
405                                   svn_skel_t *conflict,
406                                   svn_skel_t *work_items,
407                                   apr_pool_t *scratch_pool);
408 
409 /* Like svn_wc__db_op_make_copy but with wcroot, local_relpath */
410 svn_error_t *
411 svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
412                                  const char *local_relpath,
413                                  svn_boolean_t move_move_info,
414                                  const svn_skel_t *conflicts,
415                                  const svn_skel_t *work_items,
416                                  apr_pool_t *scratch_pool);
417 
418 
419 /* Extract the moved-to information for LOCAL_RELPATH as it existed
420    at OP-DEPTH.  The output paths are optional and set to NULL
421    if there is no move, otherwise:
422 
423    *MOVE_SRC_RELPATH: the path that was moved (LOCAL_RELPATH or one
424                       of its ancestors)
425 
426    *MOVE_DST_RELPATH: The path *MOVE_SRC_RELPATH was moved to.
427 
428    *DELETE_RELPATH: The path at which LOCAL_RELPATH was removed (
429                     *MOVE_SRC_RELPATH or one of its ancestors)
430 
431    Given a path A/B/C with A/B moved to X and A deleted then for A/B/C:
432 
433      MOVE_SRC_RELPATH is A/B
434      MOVE_DST_RELPATH is X
435      DELETE_RELPATH is A
436 
437      X/C can be calculated if necessesary, like with the other
438      scan functions.
439 
440    This function returns SVN_ERR_WC_PATH_NOT_FOUND if LOCAL_RELPATH didn't
441    exist at OP_DEPTH, or when it is not shadowed.
442 
443    ### Think about combining with scan_deletion?  Also with
444    ### scan_addition to get moved-to for replaces?  Do we need to
445    ### return the op-root of the move source, i.e. A/B in the example
446    ### above?  */
447 svn_error_t *
448 svn_wc__db_scan_moved_to_internal(const char **move_src_relpath,
449                                   const char **move_dst_relpath,
450                                   const char **delete_relpath,
451                                   svn_wc__db_wcroot_t *wcroot,
452                                   const char *local_relpath,
453                                   int op_depth,
454                                   apr_pool_t *result_pool,
455                                   apr_pool_t *scratch_pool);
456 
457 /* Like svn_wc__db_op_set_props, but updates ACTUAL_NODE directly without
458    comparing with the pristine properties, etc.
459 */
460 svn_error_t *
461 svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
462                                  const char *local_relpath,
463                                  apr_hash_t *props,
464                                  svn_boolean_t clear_recorded_info,
465                                  apr_pool_t *scratch_pool);
466 
467 svn_error_t *
468 svn_wc__db_read_props_internal(apr_hash_t **props,
469                                svn_wc__db_wcroot_t *wcroot,
470                                const char *local_relpath,
471                                apr_pool_t *result_pool,
472                                apr_pool_t *scratch_pool);
473 
474 /* Like svn_wc__db_wclock_owns_lock() but taking WCROOT+LOCAL_RELPATH instead
475    of DB+LOCAL_ABSPATH.  */
476 svn_error_t *
477 svn_wc__db_wclock_owns_lock_internal(svn_boolean_t *own_lock,
478                                      svn_wc__db_wcroot_t *wcroot,
479                                      const char *local_relpath,
480                                      svn_boolean_t exact,
481                                      apr_pool_t *scratch_pool);
482 
483 /* Do a post-drive revision bump for the moved-away destination for
484    any move sources under LOCAL_RELPATH.  This is called from within
485    the revision bump transaction after the tree at LOCAL_RELPATH has
486    been bumped. */
487 svn_error_t *
488 svn_wc__db_bump_moved_away(svn_wc__db_wcroot_t *wcroot,
489                            const char *local_relpath,
490                            svn_depth_t depth,
491                            svn_wc__db_t *db,
492                            apr_pool_t *scratch_pool);
493 
494 /* Unbreak the move from LOCAL_RELPATH on op-depth in WCROOT, by making
495    the destination DST_RELPATH a normal copy. SRC_OP_DEPTH is the op-depth
496    where the move_to information is stored */
497 svn_error_t *
498 svn_wc__db_op_break_move_internal(svn_wc__db_wcroot_t *wcroot,
499                                   const char *src_relpath,
500                                   int delete_op_depth,
501                                   const char *dst_relpath,
502                                   const svn_skel_t *work_items,
503                                   apr_pool_t *scratch_pool);
504 
505 svn_error_t *
506 svn_wc__db_op_mark_resolved_internal(svn_wc__db_wcroot_t *wcroot,
507                                      const char *local_relpath,
508                                      svn_wc__db_t *db,
509                                      svn_boolean_t resolved_text,
510                                      svn_boolean_t resolved_props,
511                                      svn_boolean_t resolved_tree,
512                                      const svn_skel_t *work_items,
513                                      apr_pool_t *scratch_pool);
514 
515 /* op_depth is the depth at which the node is added. */
516 svn_error_t *
517 svn_wc__db_op_raise_moved_away_internal(
518                         svn_wc__db_wcroot_t *wcroot,
519                         const char *local_relpath,
520                         int op_depth,
521                         svn_wc__db_t *db,
522                         svn_wc_operation_t operation,
523                         svn_wc_conflict_action_t action,
524                         const svn_wc_conflict_version_t *old_version,
525                         const svn_wc_conflict_version_t *new_version,
526                         apr_pool_t *scratch_pool);
527 
528 svn_error_t *
529 svn_wc__db_update_move_list_notify(svn_wc__db_wcroot_t *wcroot,
530                                    svn_revnum_t old_revision,
531                                    svn_revnum_t new_revision,
532                                    svn_wc_notify_func2_t notify_func,
533                                    void *notify_baton,
534                                    apr_pool_t *scratch_pool);
535 
536 svn_error_t *
537 svn_wc__db_verify_db_full_internal(svn_wc__db_wcroot_t *wcroot,
538                                    svn_wc__db_verify_cb_t callback,
539                                    void *baton,
540                                    apr_pool_t *scratch_pool);
541 
542 #endif /* WC_DB_PRIVATE_H */
543