1 /*
2 * node.c: routines for getting information about nodes in the working copy.
3 *
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 */
23
24 /* A note about these functions:
25
26 We aren't really sure yet which bits of data libsvn_client needs about
27 nodes. In wc-1, we just grab the entry, and then use whatever we want
28 from it. Such a pattern is Bad.
29
30 This file is intended to hold functions which retrieve specific bits of
31 information about a node, and will hopefully give us a better idea about
32 what data libsvn_client needs, and how to best provide that data in 1.7
33 final. As such, these functions should only be called from outside
34 libsvn_wc; any internal callers are encouraged to use the appropriate
35 information fetching function, such as svn_wc__db_read_info().
36 */
37
38 #include <apr_pools.h>
39 #include <apr_time.h>
40
41 #include "svn_pools.h"
42 #include "svn_dirent_uri.h"
43 #include "svn_path.h"
44 #include "svn_hash.h"
45 #include "svn_types.h"
46
47 #include "wc.h"
48 #include "props.h"
49 #include "entries.h"
50 #include "wc_db.h"
51
52 #include "svn_private_config.h"
53 #include "private/svn_wc_private.h"
54
55
56 /* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining
57 * each name in REL_CHILDREN onto DIR_ABSPATH. If SHOW_HIDDEN is false then
58 * omit any paths that are reported as 'hidden' by svn_wc__db_node_hidden().
59 *
60 * Allocate the output array and its elements in RESULT_POOL. */
61 static svn_error_t *
filter_and_make_absolute(const apr_array_header_t ** children_abspaths,svn_wc_context_t * wc_ctx,const char * dir_abspath,const apr_array_header_t * rel_children,svn_boolean_t show_hidden,apr_pool_t * result_pool,apr_pool_t * scratch_pool)62 filter_and_make_absolute(const apr_array_header_t **children_abspaths,
63 svn_wc_context_t *wc_ctx,
64 const char *dir_abspath,
65 const apr_array_header_t *rel_children,
66 svn_boolean_t show_hidden,
67 apr_pool_t *result_pool,
68 apr_pool_t *scratch_pool)
69 {
70 apr_array_header_t *children;
71 int i;
72
73 children = apr_array_make(result_pool, rel_children->nelts,
74 sizeof(const char *));
75 for (i = 0; i < rel_children->nelts; i++)
76 {
77 const char *child_abspath = svn_dirent_join(dir_abspath,
78 APR_ARRAY_IDX(rel_children,
79 i,
80 const char *),
81 result_pool);
82
83 /* Don't add hidden nodes to *CHILDREN if we don't want them. */
84 if (!show_hidden)
85 {
86 svn_boolean_t child_is_hidden;
87
88 SVN_ERR(svn_wc__db_node_hidden(&child_is_hidden, wc_ctx->db,
89 child_abspath, scratch_pool));
90 if (child_is_hidden)
91 continue;
92 }
93
94 APR_ARRAY_PUSH(children, const char *) = child_abspath;
95 }
96
97 *children_abspaths = children;
98
99 return SVN_NO_ERROR;
100 }
101
102
103 svn_error_t *
svn_wc__node_get_children_of_working_node(const apr_array_header_t ** children,svn_wc_context_t * wc_ctx,const char * dir_abspath,svn_boolean_t show_hidden,apr_pool_t * result_pool,apr_pool_t * scratch_pool)104 svn_wc__node_get_children_of_working_node(const apr_array_header_t **children,
105 svn_wc_context_t *wc_ctx,
106 const char *dir_abspath,
107 svn_boolean_t show_hidden,
108 apr_pool_t *result_pool,
109 apr_pool_t *scratch_pool)
110 {
111 const apr_array_header_t *rel_children;
112
113 SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
114 wc_ctx->db, dir_abspath,
115 scratch_pool, scratch_pool));
116 SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
117 rel_children, show_hidden,
118 result_pool, scratch_pool));
119 return SVN_NO_ERROR;
120 }
121
122 svn_error_t *
svn_wc__node_get_children(const apr_array_header_t ** children,svn_wc_context_t * wc_ctx,const char * dir_abspath,svn_boolean_t show_hidden,apr_pool_t * result_pool,apr_pool_t * scratch_pool)123 svn_wc__node_get_children(const apr_array_header_t **children,
124 svn_wc_context_t *wc_ctx,
125 const char *dir_abspath,
126 svn_boolean_t show_hidden,
127 apr_pool_t *result_pool,
128 apr_pool_t *scratch_pool)
129 {
130 const apr_array_header_t *rel_children;
131
132 SVN_ERR(svn_wc__db_read_children(&rel_children, wc_ctx->db, dir_abspath,
133 scratch_pool, scratch_pool));
134 SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
135 rel_children, show_hidden,
136 result_pool, scratch_pool));
137 return SVN_NO_ERROR;
138 }
139
140
141 svn_error_t *
svn_wc__internal_get_repos_info(svn_revnum_t * revision,const char ** repos_relpath,const char ** repos_root_url,const char ** repos_uuid,svn_wc__db_t * db,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)142 svn_wc__internal_get_repos_info(svn_revnum_t *revision,
143 const char **repos_relpath,
144 const char **repos_root_url,
145 const char **repos_uuid,
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 svn_wc__db_status_t status;
152 svn_boolean_t have_work;
153
154 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
155 repos_root_url, repos_uuid,
156 NULL, NULL, NULL, NULL, NULL, NULL,
157 NULL, NULL, NULL, NULL, NULL, NULL,
158 NULL, NULL, NULL, NULL, NULL, NULL,
159 NULL, NULL, &have_work,
160 db, local_abspath,
161 result_pool, scratch_pool));
162
163 if ((repos_relpath ? *repos_relpath != NULL : TRUE)
164 && (repos_root_url ? *repos_root_url != NULL: TRUE)
165 && (repos_uuid ? *repos_uuid != NULL : TRUE))
166 return SVN_NO_ERROR; /* We got the requested information */
167
168 if (!have_work) /* not-present, (server-)excluded? */
169 {
170 return SVN_NO_ERROR; /* Can't fetch more */
171 }
172
173 if (status == svn_wc__db_status_deleted)
174 {
175 const char *base_del_abspath, *wrk_del_abspath;
176
177 SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL,
178 &wrk_del_abspath, NULL,
179 db, local_abspath,
180 scratch_pool, scratch_pool));
181
182 if (base_del_abspath)
183 {
184 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, repos_relpath,
185 repos_root_url, repos_uuid, NULL,
186 NULL, NULL, NULL, NULL, NULL, NULL,
187 NULL, NULL, NULL,
188 db, base_del_abspath,
189 result_pool, scratch_pool));
190
191 /* If we have a repos_relpath, it is of the op-root */
192 if (repos_relpath)
193 *repos_relpath = svn_relpath_join(*repos_relpath,
194 svn_dirent_skip_ancestor(base_del_abspath,
195 local_abspath),
196 result_pool);
197 /* We keep revision as SVN_INVALID_REVNUM */
198 }
199 else if (wrk_del_abspath)
200 {
201 const char *op_root_abspath = NULL;
202
203 SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
204 ? &op_root_abspath : NULL,
205 repos_relpath, repos_root_url,
206 repos_uuid, NULL, NULL, NULL, NULL,
207 db, svn_dirent_dirname(
208 wrk_del_abspath,
209 scratch_pool),
210 result_pool, scratch_pool));
211
212 /* If we have a repos_relpath, it is of the op-root */
213 if (repos_relpath)
214 *repos_relpath = svn_relpath_join(
215 *repos_relpath,
216 svn_dirent_skip_ancestor(op_root_abspath,
217 local_abspath),
218 result_pool);
219 }
220 }
221 else /* added, or WORKING incomplete */
222 {
223 const char *op_root_abspath = NULL;
224
225 /* We have an addition. scan_addition() will find the intended
226 repository location by scanning up the tree. */
227 SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
228 ? &op_root_abspath : NULL,
229 repos_relpath, repos_root_url,
230 repos_uuid, NULL, NULL, NULL, NULL,
231 db, local_abspath,
232 result_pool, scratch_pool));
233 }
234
235 SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL);
236 SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL);
237 return SVN_NO_ERROR;
238 }
239
240 svn_error_t *
svn_wc__node_get_repos_info(svn_revnum_t * revision,const char ** repos_relpath,const char ** repos_root_url,const char ** repos_uuid,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)241 svn_wc__node_get_repos_info(svn_revnum_t *revision,
242 const char **repos_relpath,
243 const char **repos_root_url,
244 const char **repos_uuid,
245 svn_wc_context_t *wc_ctx,
246 const char *local_abspath,
247 apr_pool_t *result_pool,
248 apr_pool_t *scratch_pool)
249 {
250 return svn_error_trace(
251 svn_wc__internal_get_repos_info(revision,
252 repos_relpath,
253 repos_root_url,
254 repos_uuid,
255 wc_ctx->db, local_abspath,
256 result_pool, scratch_pool));
257 }
258
259 /* Convert DB_KIND into the appropriate NODE_KIND value.
260 * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB
261 * even if DB_STATUS indicates that the node is hidden.
262 * Else, return svn_node_none for such nodes.
263 *
264 * ### This is a bit ugly. We should consider promoting svn_kind_t
265 * ### to the de-facto node kind type instead of converting between them
266 * ### in non-backwards compat code.
267 * ### See also comments at the definition of svn_kind_t.
268 *
269 * ### In reality, the previous comment is out of date, as there is
270 * ### now only one enumeration for node kinds, and that is
271 * ### svn_node_kind_t (svn_kind_t was merged with that). But it's
272 * ### still ugly.
273 */
274 static svn_error_t *
convert_db_kind_to_node_kind(svn_node_kind_t * node_kind,svn_node_kind_t db_kind,svn_wc__db_status_t db_status,svn_boolean_t show_hidden)275 convert_db_kind_to_node_kind(svn_node_kind_t *node_kind,
276 svn_node_kind_t db_kind,
277 svn_wc__db_status_t db_status,
278 svn_boolean_t show_hidden)
279 {
280 *node_kind = db_kind;
281
282 /* Make sure hidden nodes return svn_node_none. */
283 if (! show_hidden)
284 switch (db_status)
285 {
286 case svn_wc__db_status_not_present:
287 case svn_wc__db_status_server_excluded:
288 case svn_wc__db_status_excluded:
289 *node_kind = svn_node_none;
290
291 default:
292 break;
293 }
294
295 return SVN_NO_ERROR;
296 }
297
298 svn_error_t *
svn_wc_read_kind2(svn_node_kind_t * kind,svn_wc_context_t * wc_ctx,const char * local_abspath,svn_boolean_t show_deleted,svn_boolean_t show_hidden,apr_pool_t * scratch_pool)299 svn_wc_read_kind2(svn_node_kind_t *kind,
300 svn_wc_context_t *wc_ctx,
301 const char *local_abspath,
302 svn_boolean_t show_deleted,
303 svn_boolean_t show_hidden,
304 apr_pool_t *scratch_pool)
305 {
306 svn_node_kind_t db_kind;
307
308 SVN_ERR(svn_wc__db_read_kind(&db_kind,
309 wc_ctx->db, local_abspath,
310 TRUE,
311 show_deleted,
312 show_hidden,
313 scratch_pool));
314
315 if (db_kind == svn_node_dir)
316 *kind = svn_node_dir;
317 else if (db_kind == svn_node_file || db_kind == svn_node_symlink)
318 *kind = svn_node_file;
319 else
320 *kind = svn_node_none;
321
322 return SVN_NO_ERROR;
323 }
324
325 svn_error_t *
svn_wc__node_get_depth(svn_depth_t * depth,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * scratch_pool)326 svn_wc__node_get_depth(svn_depth_t *depth,
327 svn_wc_context_t *wc_ctx,
328 const char *local_abspath,
329 apr_pool_t *scratch_pool)
330 {
331 return svn_error_trace(
332 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
333 NULL, NULL, depth, NULL, NULL, NULL, NULL,
334 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
335 NULL, NULL, NULL, NULL, NULL, NULL,
336 wc_ctx->db, local_abspath, scratch_pool,
337 scratch_pool));
338 }
339
340 svn_error_t *
svn_wc__node_get_changed_info(svn_revnum_t * changed_rev,apr_time_t * changed_date,const char ** changed_author,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)341 svn_wc__node_get_changed_info(svn_revnum_t *changed_rev,
342 apr_time_t *changed_date,
343 const char **changed_author,
344 svn_wc_context_t *wc_ctx,
345 const char *local_abspath,
346 apr_pool_t *result_pool,
347 apr_pool_t *scratch_pool)
348 {
349 return svn_error_trace(
350 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev,
351 changed_date, changed_author, NULL, NULL, NULL,
352 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
353 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
354 wc_ctx->db, local_abspath, result_pool,
355 scratch_pool));
356 }
357
358 svn_error_t *
svn_wc__node_get_url(const char ** url,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)359 svn_wc__node_get_url(const char **url,
360 svn_wc_context_t *wc_ctx,
361 const char *local_abspath,
362 apr_pool_t *result_pool,
363 apr_pool_t *scratch_pool)
364 {
365 return svn_error_trace(svn_wc__db_read_url(url, wc_ctx->db, local_abspath,
366 result_pool, scratch_pool));
367 }
368
369 /* A recursive node-walker, helper for svn_wc__internal_walk_children().
370 *
371 * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of
372 * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a
373 * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else
374 * ignore them. Restrict the depth of the walk to DEPTH.
375 *
376 * ### Is it possible for a subdirectory to be hidden and known to be a
377 * directory? If so, and if show_hidden is true, this will try to
378 * recurse into it. */
379 static svn_error_t *
walker_helper(svn_wc__db_t * db,const char * dir_abspath,svn_boolean_t show_hidden,const apr_hash_t * changelist_filter,svn_wc__node_found_func_t walk_callback,void * walk_baton,svn_depth_t depth,svn_cancel_func_t cancel_func,void * cancel_baton,apr_pool_t * scratch_pool)380 walker_helper(svn_wc__db_t *db,
381 const char *dir_abspath,
382 svn_boolean_t show_hidden,
383 const apr_hash_t *changelist_filter,
384 svn_wc__node_found_func_t walk_callback,
385 void *walk_baton,
386 svn_depth_t depth,
387 svn_cancel_func_t cancel_func,
388 void *cancel_baton,
389 apr_pool_t *scratch_pool)
390 {
391 apr_hash_t *rel_children_info;
392 apr_hash_index_t *hi;
393 apr_pool_t *iterpool;
394
395 if (depth == svn_depth_empty)
396 return SVN_NO_ERROR;
397
398 SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db,
399 dir_abspath, scratch_pool,
400 scratch_pool));
401
402
403 iterpool = svn_pool_create(scratch_pool);
404 for (hi = apr_hash_first(scratch_pool, rel_children_info);
405 hi;
406 hi = apr_hash_next(hi))
407 {
408 const char *child_name = svn__apr_hash_index_key(hi);
409 struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi);
410 svn_node_kind_t child_kind = wi->kind;
411 svn_wc__db_status_t child_status = wi->status;
412 const char *child_abspath;
413
414 svn_pool_clear(iterpool);
415
416 /* See if someone wants to cancel this operation. */
417 if (cancel_func)
418 SVN_ERR(cancel_func(cancel_baton));
419
420 child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
421
422 if (!show_hidden)
423 switch (child_status)
424 {
425 case svn_wc__db_status_not_present:
426 case svn_wc__db_status_server_excluded:
427 case svn_wc__db_status_excluded:
428 continue;
429 default:
430 break;
431 }
432
433 /* Return the child, if appropriate. */
434 if ( (child_kind == svn_node_file
435 || depth >= svn_depth_immediates)
436 && svn_wc__internal_changelist_match(db, child_abspath,
437 changelist_filter,
438 scratch_pool) )
439 {
440 svn_node_kind_t kind;
441
442 SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind,
443 child_status, show_hidden));
444 /* ### We might want to pass child_status as well because at least
445 * ### one callee is asking for it.
446 * ### But is it OK to use an svn_wc__db type in this API?
447 * ### Not yet, we need to get the node walker
448 * ### libsvn_wc-internal first. -hkw */
449 SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool));
450 }
451
452 /* Recurse into this directory, if appropriate. */
453 if (child_kind == svn_node_dir
454 && depth >= svn_depth_immediates)
455 {
456 svn_depth_t depth_below_here = depth;
457
458 if (depth == svn_depth_immediates)
459 depth_below_here = svn_depth_empty;
460
461 SVN_ERR(walker_helper(db, child_abspath, show_hidden,
462 changelist_filter,
463 walk_callback, walk_baton,
464 depth_below_here,
465 cancel_func, cancel_baton,
466 iterpool));
467 }
468 }
469
470 svn_pool_destroy(iterpool);
471
472 return SVN_NO_ERROR;
473 }
474
475
476 svn_error_t *
svn_wc__internal_walk_children(svn_wc__db_t * db,const char * local_abspath,svn_boolean_t show_hidden,const apr_array_header_t * changelist_filter,svn_wc__node_found_func_t walk_callback,void * walk_baton,svn_depth_t walk_depth,svn_cancel_func_t cancel_func,void * cancel_baton,apr_pool_t * scratch_pool)477 svn_wc__internal_walk_children(svn_wc__db_t *db,
478 const char *local_abspath,
479 svn_boolean_t show_hidden,
480 const apr_array_header_t *changelist_filter,
481 svn_wc__node_found_func_t walk_callback,
482 void *walk_baton,
483 svn_depth_t walk_depth,
484 svn_cancel_func_t cancel_func,
485 void *cancel_baton,
486 apr_pool_t *scratch_pool)
487 {
488 svn_node_kind_t db_kind;
489 svn_node_kind_t kind;
490 svn_wc__db_status_t status;
491 apr_hash_t *changelist_hash = NULL;
492
493 SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
494 && walk_depth <= svn_depth_infinity);
495
496 if (changelist_filter && changelist_filter->nelts)
497 SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
498 scratch_pool));
499
500 /* Check if the node exists before the first callback */
501 SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
502 NULL, NULL, NULL, NULL, NULL, NULL,
503 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
504 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
505 db, local_abspath, scratch_pool, scratch_pool));
506
507 SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
508
509 if (svn_wc__internal_changelist_match(db, local_abspath,
510 changelist_hash, scratch_pool))
511 SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
512
513 if (db_kind == svn_node_file
514 || status == svn_wc__db_status_not_present
515 || status == svn_wc__db_status_excluded
516 || status == svn_wc__db_status_server_excluded)
517 return SVN_NO_ERROR;
518
519 if (db_kind == svn_node_dir)
520 {
521 return svn_error_trace(
522 walker_helper(db, local_abspath, show_hidden, changelist_hash,
523 walk_callback, walk_baton,
524 walk_depth, cancel_func, cancel_baton, scratch_pool));
525 }
526
527 return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
528 _("'%s' has an unrecognized node kind"),
529 svn_dirent_local_style(local_abspath,
530 scratch_pool));
531 }
532
533 svn_error_t *
svn_wc__node_is_status_deleted(svn_boolean_t * is_deleted,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * scratch_pool)534 svn_wc__node_is_status_deleted(svn_boolean_t *is_deleted,
535 svn_wc_context_t *wc_ctx,
536 const char *local_abspath,
537 apr_pool_t *scratch_pool)
538 {
539 svn_wc__db_status_t status;
540
541 SVN_ERR(svn_wc__db_read_info(&status,
542 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
543 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
544 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
545 NULL, NULL, NULL, NULL, NULL,
546 wc_ctx->db, local_abspath,
547 scratch_pool, scratch_pool));
548
549 *is_deleted = (status == svn_wc__db_status_deleted);
550
551 return SVN_NO_ERROR;
552 }
553
554 svn_error_t *
svn_wc__node_get_deleted_ancestor(const char ** deleted_ancestor_abspath,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)555 svn_wc__node_get_deleted_ancestor(const char **deleted_ancestor_abspath,
556 svn_wc_context_t *wc_ctx,
557 const char *local_abspath,
558 apr_pool_t *result_pool,
559 apr_pool_t *scratch_pool)
560 {
561 svn_wc__db_status_t status;
562
563 *deleted_ancestor_abspath = NULL;
564
565 SVN_ERR(svn_wc__db_read_info(&status,
566 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
567 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
568 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
569 NULL, NULL, NULL, NULL, NULL,
570 wc_ctx->db, local_abspath,
571 scratch_pool, scratch_pool));
572
573 if (status == svn_wc__db_status_deleted)
574 SVN_ERR(svn_wc__db_scan_deletion(deleted_ancestor_abspath, NULL, NULL,
575 NULL, wc_ctx->db, local_abspath,
576 result_pool, scratch_pool));
577
578 return SVN_NO_ERROR;
579 }
580
581 svn_error_t *
svn_wc__node_is_not_present(svn_boolean_t * is_not_present,svn_boolean_t * is_excluded,svn_boolean_t * is_server_excluded,svn_wc_context_t * wc_ctx,const char * local_abspath,svn_boolean_t base_only,apr_pool_t * scratch_pool)582 svn_wc__node_is_not_present(svn_boolean_t *is_not_present,
583 svn_boolean_t *is_excluded,
584 svn_boolean_t *is_server_excluded,
585 svn_wc_context_t *wc_ctx,
586 const char *local_abspath,
587 svn_boolean_t base_only,
588 apr_pool_t *scratch_pool)
589 {
590 svn_wc__db_status_t status;
591
592 if (base_only)
593 {
594 SVN_ERR(svn_wc__db_base_get_info(&status,
595 NULL, NULL, NULL, NULL, NULL, NULL,
596 NULL, NULL, NULL, NULL, NULL, NULL,
597 NULL, NULL, NULL,
598 wc_ctx->db, local_abspath,
599 scratch_pool, scratch_pool));
600 }
601 else
602 {
603 SVN_ERR(svn_wc__db_read_info(&status,
604 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
605 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
606 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
607 NULL, NULL, NULL, NULL, NULL,
608 wc_ctx->db, local_abspath,
609 scratch_pool, scratch_pool));
610 }
611
612 if (is_not_present)
613 *is_not_present = (status == svn_wc__db_status_not_present);
614
615 if (is_excluded)
616 *is_excluded = (status == svn_wc__db_status_excluded);
617
618 if (is_server_excluded)
619 *is_server_excluded = (status == svn_wc__db_status_server_excluded);
620
621 return SVN_NO_ERROR;
622 }
623
624 svn_error_t *
svn_wc__node_is_added(svn_boolean_t * is_added,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * scratch_pool)625 svn_wc__node_is_added(svn_boolean_t *is_added,
626 svn_wc_context_t *wc_ctx,
627 const char *local_abspath,
628 apr_pool_t *scratch_pool)
629 {
630 svn_wc__db_status_t status;
631
632 SVN_ERR(svn_wc__db_read_info(&status,
633 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
634 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
635 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
636 NULL, NULL, NULL, NULL, NULL,
637 wc_ctx->db, local_abspath,
638 scratch_pool, scratch_pool));
639 *is_added = (status == svn_wc__db_status_added);
640
641 return SVN_NO_ERROR;
642 }
643
644 svn_error_t *
svn_wc__node_has_working(svn_boolean_t * has_working,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * scratch_pool)645 svn_wc__node_has_working(svn_boolean_t *has_working,
646 svn_wc_context_t *wc_ctx,
647 const char *local_abspath,
648 apr_pool_t *scratch_pool)
649 {
650 svn_wc__db_status_t status;
651
652 SVN_ERR(svn_wc__db_read_info(&status,
653 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
654 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
655 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
656 NULL, NULL, NULL, NULL, has_working,
657 wc_ctx->db, local_abspath,
658 scratch_pool, scratch_pool));
659
660 return SVN_NO_ERROR;
661 }
662
663
664 svn_error_t *
svn_wc__node_get_base(svn_node_kind_t * kind,svn_revnum_t * revision,const char ** repos_relpath,const char ** repos_root_url,const char ** repos_uuid,const char ** lock_token,svn_wc_context_t * wc_ctx,const char * local_abspath,svn_boolean_t ignore_enoent,svn_boolean_t show_hidden,apr_pool_t * result_pool,apr_pool_t * scratch_pool)665 svn_wc__node_get_base(svn_node_kind_t *kind,
666 svn_revnum_t *revision,
667 const char **repos_relpath,
668 const char **repos_root_url,
669 const char **repos_uuid,
670 const char **lock_token,
671 svn_wc_context_t *wc_ctx,
672 const char *local_abspath,
673 svn_boolean_t ignore_enoent,
674 svn_boolean_t show_hidden,
675 apr_pool_t *result_pool,
676 apr_pool_t *scratch_pool)
677 {
678 svn_error_t *err;
679 svn_wc__db_status_t status;
680 svn_wc__db_lock_t *lock;
681 svn_node_kind_t db_kind;
682
683 err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath,
684 repos_root_url, repos_uuid, NULL,
685 NULL, NULL, NULL, NULL, NULL,
686 lock_token ? &lock : NULL,
687 NULL, NULL, NULL,
688 wc_ctx->db, local_abspath,
689 result_pool, scratch_pool);
690
691 if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
692 return svn_error_trace(err);
693 else if (err
694 || (!err && !show_hidden
695 && (status != svn_wc__db_status_normal
696 && status != svn_wc__db_status_incomplete)))
697 {
698 if (!ignore_enoent)
699 {
700 if (err)
701 return svn_error_trace(err);
702 else
703 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
704 _("The node '%s' was not found."),
705 svn_dirent_local_style(local_abspath,
706 scratch_pool));
707 }
708 svn_error_clear(err);
709
710 if (kind)
711 *kind = svn_node_unknown;
712 if (revision)
713 *revision = SVN_INVALID_REVNUM;
714 if (repos_relpath)
715 *repos_relpath = NULL;
716 if (repos_root_url)
717 *repos_root_url = NULL;
718 if (repos_uuid)
719 *repos_uuid = NULL;
720 if (lock_token)
721 *lock_token = NULL;
722 return SVN_NO_ERROR;
723 }
724
725 if (kind)
726 *kind = db_kind;
727 if (lock_token)
728 *lock_token = lock ? lock->token : NULL;
729
730 SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision));
731 SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
732 SVN_ERR_ASSERT(!repos_root_url || *repos_root_url);
733 SVN_ERR_ASSERT(!repos_uuid || *repos_uuid);
734 return SVN_NO_ERROR;
735 }
736
737 svn_error_t *
svn_wc__node_get_pre_ng_status_data(svn_revnum_t * revision,svn_revnum_t * changed_rev,apr_time_t * changed_date,const char ** changed_author,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)738 svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision,
739 svn_revnum_t *changed_rev,
740 apr_time_t *changed_date,
741 const char **changed_author,
742 svn_wc_context_t *wc_ctx,
743 const char *local_abspath,
744 apr_pool_t *result_pool,
745 apr_pool_t *scratch_pool)
746 {
747 svn_wc__db_status_t status;
748 svn_boolean_t have_base, have_more_work, have_work;
749
750 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL,
751 changed_rev, changed_date, changed_author,
752 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
753 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
754 &have_base, &have_more_work, &have_work,
755 wc_ctx->db, local_abspath,
756 result_pool, scratch_pool));
757
758 if (!have_work
759 || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev))
760 && (!revision || SVN_IS_VALID_REVNUM(*revision)))
761 || ((status != svn_wc__db_status_added)
762 && (status != svn_wc__db_status_deleted)))
763 {
764 return SVN_NO_ERROR; /* We got everything we need */
765 }
766
767 if (have_base && !have_more_work)
768 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
769 changed_rev, changed_date, changed_author,
770 NULL, NULL, NULL,
771 NULL, NULL, NULL, NULL,
772 wc_ctx->db, local_abspath,
773 result_pool, scratch_pool));
774 else if (status == svn_wc__db_status_deleted)
775 /* Check the information below a WORKING delete */
776 SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev,
777 changed_date, changed_author, NULL,
778 NULL, NULL, NULL, NULL,
779 wc_ctx->db, local_abspath,
780 result_pool, scratch_pool));
781
782 return SVN_NO_ERROR;
783 }
784
785 svn_error_t *
svn_wc__internal_node_get_schedule(svn_wc_schedule_t * schedule,svn_boolean_t * copied,svn_wc__db_t * db,const char * local_abspath,apr_pool_t * scratch_pool)786 svn_wc__internal_node_get_schedule(svn_wc_schedule_t *schedule,
787 svn_boolean_t *copied,
788 svn_wc__db_t *db,
789 const char *local_abspath,
790 apr_pool_t *scratch_pool)
791 {
792 svn_wc__db_status_t status;
793 svn_boolean_t op_root;
794 svn_boolean_t have_base;
795 svn_boolean_t have_work;
796 svn_boolean_t have_more_work;
797 const char *copyfrom_relpath;
798
799 if (schedule)
800 *schedule = svn_wc_schedule_normal;
801 if (copied)
802 *copied = FALSE;
803
804 SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
805 NULL, NULL, NULL, NULL, NULL, ©from_relpath,
806 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
807 &op_root, NULL, NULL,
808 &have_base, &have_more_work, &have_work,
809 db, local_abspath, scratch_pool, scratch_pool));
810
811 switch (status)
812 {
813 case svn_wc__db_status_not_present:
814 case svn_wc__db_status_server_excluded:
815 case svn_wc__db_status_excluded:
816 /* We used status normal in the entries world. */
817 if (schedule)
818 *schedule = svn_wc_schedule_normal;
819 break;
820 case svn_wc__db_status_normal:
821 case svn_wc__db_status_incomplete:
822 break;
823
824 case svn_wc__db_status_deleted:
825 {
826 if (schedule)
827 *schedule = svn_wc_schedule_delete;
828
829 if (!copied)
830 break;
831
832 if (have_more_work || !have_base)
833 *copied = TRUE;
834 else
835 {
836 const char *work_del_abspath;
837
838 /* Find out details of our deletion. */
839 SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
840 &work_del_abspath, NULL,
841 db, local_abspath,
842 scratch_pool, scratch_pool));
843
844 if (work_del_abspath)
845 *copied = TRUE; /* Working deletion */
846 }
847 break;
848 }
849 case svn_wc__db_status_added:
850 {
851 if (!op_root)
852 {
853 if (copied)
854 *copied = TRUE;
855
856 if (schedule)
857 *schedule = svn_wc_schedule_normal;
858
859 break;
860 }
861
862 if (copied)
863 *copied = (copyfrom_relpath != NULL);
864
865 if (schedule)
866 *schedule = svn_wc_schedule_add;
867 else
868 break;
869
870 /* Check for replaced */
871 if (have_base || have_more_work)
872 {
873 svn_wc__db_status_t below_working;
874 SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
875 &below_working,
876 db, local_abspath,
877 scratch_pool));
878
879 /* If the node is not present or deleted (read: not present
880 in working), then the node is not a replacement */
881 if (below_working != svn_wc__db_status_not_present
882 && below_working != svn_wc__db_status_deleted)
883 {
884 *schedule = svn_wc_schedule_replace;
885 break;
886 }
887 }
888 break;
889 }
890 default:
891 SVN_ERR_MALFUNCTION();
892 }
893
894 return SVN_NO_ERROR;
895 }
896
897 svn_error_t *
svn_wc__node_get_schedule(svn_wc_schedule_t * schedule,svn_boolean_t * copied,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * scratch_pool)898 svn_wc__node_get_schedule(svn_wc_schedule_t *schedule,
899 svn_boolean_t *copied,
900 svn_wc_context_t *wc_ctx,
901 const char *local_abspath,
902 apr_pool_t *scratch_pool)
903 {
904 return svn_error_trace(
905 svn_wc__internal_node_get_schedule(schedule,
906 copied,
907 wc_ctx->db,
908 local_abspath,
909 scratch_pool));
910 }
911
912 svn_error_t *
svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * scratch_pool)913 svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx,
914 const char *local_abspath,
915 apr_pool_t *scratch_pool)
916 {
917 return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive(
918 wc_ctx->db, local_abspath, scratch_pool));
919 }
920
921
922 svn_error_t *
svn_wc__node_get_lock_tokens_recursive(apr_hash_t ** lock_tokens,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)923 svn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens,
924 svn_wc_context_t *wc_ctx,
925 const char *local_abspath,
926 apr_pool_t *result_pool,
927 apr_pool_t *scratch_pool)
928 {
929 return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive(
930 lock_tokens, wc_ctx->db, local_abspath,
931 result_pool, scratch_pool));
932 }
933
934 svn_error_t *
svn_wc__get_excluded_subtrees(apr_hash_t ** server_excluded_subtrees,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)935 svn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees,
936 svn_wc_context_t *wc_ctx,
937 const char *local_abspath,
938 apr_pool_t *result_pool,
939 apr_pool_t *scratch_pool)
940 {
941 return svn_error_trace(
942 svn_wc__db_get_excluded_subtrees(server_excluded_subtrees,
943 wc_ctx->db,
944 local_abspath,
945 result_pool,
946 scratch_pool));
947 }
948
949 svn_error_t *
svn_wc__internal_get_origin(svn_boolean_t * is_copy,svn_revnum_t * revision,const char ** repos_relpath,const char ** repos_root_url,const char ** repos_uuid,const char ** copy_root_abspath,svn_wc__db_t * db,const char * local_abspath,svn_boolean_t scan_deleted,apr_pool_t * result_pool,apr_pool_t * scratch_pool)950 svn_wc__internal_get_origin(svn_boolean_t *is_copy,
951 svn_revnum_t *revision,
952 const char **repos_relpath,
953 const char **repos_root_url,
954 const char **repos_uuid,
955 const char **copy_root_abspath,
956 svn_wc__db_t *db,
957 const char *local_abspath,
958 svn_boolean_t scan_deleted,
959 apr_pool_t *result_pool,
960 apr_pool_t *scratch_pool)
961 {
962 const char *original_repos_relpath;
963 const char *original_repos_root_url;
964 const char *original_repos_uuid;
965 svn_revnum_t original_revision;
966 svn_wc__db_status_t status;
967
968 const char *tmp_repos_relpath;
969
970 if (!repos_relpath)
971 repos_relpath = &tmp_repos_relpath;
972
973 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
974 repos_root_url, repos_uuid, NULL, NULL, NULL,
975 NULL, NULL, NULL,
976 &original_repos_relpath,
977 &original_repos_root_url,
978 &original_repos_uuid, &original_revision,
979 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
980 NULL, NULL, is_copy,
981 db, local_abspath, result_pool, scratch_pool));
982
983 if (*repos_relpath)
984 {
985 return SVN_NO_ERROR; /* Returned BASE information */
986 }
987
988 if (status == svn_wc__db_status_deleted && !scan_deleted)
989 {
990 if (is_copy)
991 *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */
992
993 return SVN_NO_ERROR; /* No info */
994 }
995
996 if (original_repos_relpath)
997 {
998 *repos_relpath = original_repos_relpath;
999 if (revision)
1000 *revision = original_revision;
1001 if (repos_root_url)
1002 *repos_root_url = original_repos_root_url;
1003 if (repos_uuid)
1004 *repos_uuid = original_repos_uuid;
1005
1006 if (copy_root_abspath == NULL)
1007 return SVN_NO_ERROR;
1008 }
1009
1010 {
1011 svn_boolean_t scan_working = FALSE;
1012
1013 if (status == svn_wc__db_status_added)
1014 scan_working = TRUE;
1015 else if (status == svn_wc__db_status_deleted)
1016 {
1017 svn_boolean_t have_base;
1018 /* Is this a BASE or a WORKING delete? */
1019 SVN_ERR(svn_wc__db_info_below_working(&have_base, &scan_working,
1020 &status, db, local_abspath,
1021 scratch_pool));
1022 }
1023
1024 if (scan_working)
1025 {
1026 const char *op_root_abspath;
1027
1028 SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL,
1029 NULL, NULL, &original_repos_relpath,
1030 repos_root_url,
1031 repos_uuid, revision,
1032 db, local_abspath,
1033 result_pool, scratch_pool));
1034
1035 if (status == svn_wc__db_status_added)
1036 {
1037 if (is_copy)
1038 *is_copy = FALSE;
1039 return SVN_NO_ERROR; /* Local addition */
1040 }
1041
1042 /* We don't know how the following error condition can be fulfilled
1043 * but we have seen that happening in the wild. Better to create
1044 * an error than a SEGFAULT. */
1045 if (status == svn_wc__db_status_incomplete && !original_repos_relpath)
1046 return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
1047 _("Incomplete copy information on path '%s'."),
1048 svn_dirent_local_style(local_abspath,
1049 scratch_pool));
1050
1051 *repos_relpath = svn_relpath_join(
1052 original_repos_relpath,
1053 svn_dirent_skip_ancestor(op_root_abspath,
1054 local_abspath),
1055 result_pool);
1056 if (copy_root_abspath)
1057 *copy_root_abspath = op_root_abspath;
1058 }
1059 else /* Deleted, excluded, not-present, server-excluded, ... */
1060 {
1061 if (is_copy)
1062 *is_copy = FALSE;
1063
1064 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath,
1065 repos_root_url, repos_uuid, NULL,
1066 NULL, NULL, NULL, NULL, NULL, NULL,
1067 NULL, NULL, NULL,
1068 db, local_abspath,
1069 result_pool, scratch_pool));
1070 }
1071
1072 return SVN_NO_ERROR;
1073 }
1074 }
1075
1076 svn_error_t *
svn_wc__node_get_origin(svn_boolean_t * is_copy,svn_revnum_t * revision,const char ** repos_relpath,const char ** repos_root_url,const char ** repos_uuid,const char ** copy_root_abspath,svn_wc_context_t * wc_ctx,const char * local_abspath,svn_boolean_t scan_deleted,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1077 svn_wc__node_get_origin(svn_boolean_t *is_copy,
1078 svn_revnum_t *revision,
1079 const char **repos_relpath,
1080 const char **repos_root_url,
1081 const char **repos_uuid,
1082 const char **copy_root_abspath,
1083 svn_wc_context_t *wc_ctx,
1084 const char *local_abspath,
1085 svn_boolean_t scan_deleted,
1086 apr_pool_t *result_pool,
1087 apr_pool_t *scratch_pool)
1088 {
1089 return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision,
1090 repos_relpath, repos_root_url, repos_uuid,
1091 copy_root_abspath,
1092 wc_ctx->db, local_abspath, scan_deleted,
1093 result_pool, scratch_pool));
1094 }
1095
1096 svn_error_t *
svn_wc__node_get_commit_status(svn_boolean_t * added,svn_boolean_t * deleted,svn_boolean_t * is_replace_root,svn_boolean_t * is_op_root,svn_revnum_t * revision,svn_revnum_t * original_revision,const char ** original_repos_relpath,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1097 svn_wc__node_get_commit_status(svn_boolean_t *added,
1098 svn_boolean_t *deleted,
1099 svn_boolean_t *is_replace_root,
1100 svn_boolean_t *is_op_root,
1101 svn_revnum_t *revision,
1102 svn_revnum_t *original_revision,
1103 const char **original_repos_relpath,
1104 svn_wc_context_t *wc_ctx,
1105 const char *local_abspath,
1106 apr_pool_t *result_pool,
1107 apr_pool_t *scratch_pool)
1108 {
1109 svn_wc__db_status_t status;
1110 svn_boolean_t have_base;
1111 svn_boolean_t have_more_work;
1112 svn_boolean_t op_root;
1113
1114 /* ### All of this should be handled inside a single read transaction */
1115 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL,
1116 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1117 original_repos_relpath, NULL, NULL,
1118 original_revision, NULL, NULL, NULL,
1119 NULL, NULL,
1120 &op_root, NULL, NULL,
1121 &have_base, &have_more_work, NULL,
1122 wc_ctx->db, local_abspath,
1123 result_pool, scratch_pool));
1124
1125 if (added)
1126 *added = (status == svn_wc__db_status_added);
1127 if (deleted)
1128 *deleted = (status == svn_wc__db_status_deleted);
1129 if (is_op_root)
1130 *is_op_root = op_root;
1131
1132 if (is_replace_root)
1133 {
1134 if (status == svn_wc__db_status_added
1135 && op_root
1136 && (have_base || have_more_work))
1137 SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL,
1138 wc_ctx->db, local_abspath,
1139 scratch_pool));
1140 else
1141 *is_replace_root = FALSE;
1142 }
1143
1144 /* Retrieve some information from BASE which is needed for replacing
1145 and/or deleting BASE nodes. */
1146 if (have_base
1147 && !have_more_work
1148 && op_root
1149 && (revision && !SVN_IS_VALID_REVNUM(*revision)))
1150 {
1151 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
1152 NULL, NULL, NULL, NULL, NULL, NULL,
1153 NULL, NULL, NULL, NULL,
1154 wc_ctx->db, local_abspath,
1155 scratch_pool, scratch_pool));
1156 }
1157
1158 return SVN_NO_ERROR;
1159 }
1160
1161 svn_error_t *
svn_wc__node_get_md5_from_sha1(const svn_checksum_t ** md5_checksum,svn_wc_context_t * wc_ctx,const char * wri_abspath,const svn_checksum_t * sha1_checksum,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1162 svn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum,
1163 svn_wc_context_t *wc_ctx,
1164 const char *wri_abspath,
1165 const svn_checksum_t *sha1_checksum,
1166 apr_pool_t *result_pool,
1167 apr_pool_t *scratch_pool)
1168 {
1169 return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum,
1170 wc_ctx->db,
1171 wri_abspath,
1172 sha1_checksum,
1173 result_pool,
1174 scratch_pool));
1175 }
1176
1177 svn_error_t *
svn_wc__get_not_present_descendants(const apr_array_header_t ** descendants,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1178 svn_wc__get_not_present_descendants(const apr_array_header_t **descendants,
1179 svn_wc_context_t *wc_ctx,
1180 const char *local_abspath,
1181 apr_pool_t *result_pool,
1182 apr_pool_t *scratch_pool)
1183 {
1184 return svn_error_trace(
1185 svn_wc__db_get_not_present_descendants(descendants,
1186 wc_ctx->db,
1187 local_abspath,
1188 result_pool,
1189 scratch_pool));
1190 }
1191
1192 svn_error_t *
svn_wc__rename_wc(svn_wc_context_t * wc_ctx,const char * from_abspath,const char * dst_abspath,apr_pool_t * scratch_pool)1193 svn_wc__rename_wc(svn_wc_context_t *wc_ctx,
1194 const char *from_abspath,
1195 const char *dst_abspath,
1196 apr_pool_t *scratch_pool)
1197 {
1198 const char *wcroot_abspath;
1199 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath,
1200 scratch_pool, scratch_pool));
1201
1202 if (! strcmp(from_abspath, wcroot_abspath))
1203 {
1204 SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
1205
1206 SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
1207 }
1208 else
1209 return svn_error_createf(
1210 SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
1211 _("'%s' is not the root of the working copy '%s'"),
1212 svn_dirent_local_style(from_abspath, scratch_pool),
1213 svn_dirent_local_style(wcroot_abspath, scratch_pool));
1214
1215 return SVN_NO_ERROR;
1216 }
1217
1218 svn_error_t *
svn_wc__check_for_obstructions(svn_wc_notify_state_t * obstruction_state,svn_node_kind_t * kind,svn_boolean_t * deleted,svn_boolean_t * excluded,svn_depth_t * parent_depth,svn_wc_context_t * wc_ctx,const char * local_abspath,svn_boolean_t no_wcroot_check,apr_pool_t * scratch_pool)1219 svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
1220 svn_node_kind_t *kind,
1221 svn_boolean_t *deleted,
1222 svn_boolean_t *excluded,
1223 svn_depth_t *parent_depth,
1224 svn_wc_context_t *wc_ctx,
1225 const char *local_abspath,
1226 svn_boolean_t no_wcroot_check,
1227 apr_pool_t *scratch_pool)
1228 {
1229 svn_wc__db_status_t status;
1230 svn_node_kind_t db_kind;
1231 svn_node_kind_t disk_kind;
1232 svn_error_t *err;
1233
1234 *obstruction_state = svn_wc_notify_state_inapplicable;
1235 if (kind)
1236 *kind = svn_node_none;
1237 if (deleted)
1238 *deleted = FALSE;
1239 if (excluded)
1240 *excluded = FALSE;
1241 if (parent_depth)
1242 *parent_depth = svn_depth_unknown;
1243
1244 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
1245
1246 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
1247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1248 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1249 NULL, NULL, NULL, NULL, NULL,
1250 wc_ctx->db, local_abspath,
1251 scratch_pool, scratch_pool);
1252
1253 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
1254 {
1255 svn_error_clear(err);
1256
1257 if (disk_kind != svn_node_none)
1258 {
1259 /* Nothing in the DB, but something on disk */
1260 *obstruction_state = svn_wc_notify_state_obstructed;
1261 return SVN_NO_ERROR;
1262 }
1263
1264 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
1265 NULL, NULL, NULL, parent_depth, NULL, NULL,
1266 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1267 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1268 NULL,
1269 wc_ctx->db, svn_dirent_dirname(local_abspath,
1270 scratch_pool),
1271 scratch_pool, scratch_pool);
1272
1273 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
1274 {
1275 svn_error_clear(err);
1276 /* No versioned parent; we can't add a node here */
1277 *obstruction_state = svn_wc_notify_state_obstructed;
1278 return SVN_NO_ERROR;
1279 }
1280 else
1281 SVN_ERR(err);
1282
1283 if (db_kind != svn_node_dir
1284 || (status != svn_wc__db_status_normal
1285 && status != svn_wc__db_status_added))
1286 {
1287 /* The parent doesn't allow nodes to be added below it */
1288 *obstruction_state = svn_wc_notify_state_obstructed;
1289 }
1290
1291 return SVN_NO_ERROR;
1292 }
1293 else
1294 SVN_ERR(err);
1295
1296 /* Check for obstructing working copies */
1297 if (!no_wcroot_check
1298 && db_kind == svn_node_dir
1299 && status == svn_wc__db_status_normal)
1300 {
1301 svn_boolean_t is_root;
1302 SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
1303 scratch_pool));
1304
1305 if (is_root)
1306 {
1307 /* Callers should handle this as unversioned */
1308 *obstruction_state = svn_wc_notify_state_obstructed;
1309 return SVN_NO_ERROR;
1310 }
1311 }
1312
1313 if (kind)
1314 SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
1315
1316 switch (status)
1317 {
1318 case svn_wc__db_status_deleted:
1319 if (deleted)
1320 *deleted = TRUE;
1321 /* Fall through to svn_wc__db_status_not_present */
1322 case svn_wc__db_status_not_present:
1323 if (disk_kind != svn_node_none)
1324 *obstruction_state = svn_wc_notify_state_obstructed;
1325 break;
1326
1327 case svn_wc__db_status_excluded:
1328 case svn_wc__db_status_server_excluded:
1329 if (excluded)
1330 *excluded = TRUE;
1331 /* fall through */
1332 case svn_wc__db_status_incomplete:
1333 *obstruction_state = svn_wc_notify_state_missing;
1334 break;
1335
1336 case svn_wc__db_status_added:
1337 case svn_wc__db_status_normal:
1338 if (disk_kind == svn_node_none)
1339 *obstruction_state = svn_wc_notify_state_missing;
1340 else
1341 {
1342 svn_node_kind_t expected_kind;
1343
1344 SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
1345 status, FALSE));
1346
1347 if (disk_kind != expected_kind)
1348 *obstruction_state = svn_wc_notify_state_obstructed;
1349 }
1350 break;
1351 default:
1352 SVN_ERR_MALFUNCTION();
1353 }
1354
1355 return SVN_NO_ERROR;
1356 }
1357
1358
1359 svn_error_t *
svn_wc__node_was_moved_away(const char ** moved_to_abspath,const char ** op_root_abspath,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1360 svn_wc__node_was_moved_away(const char **moved_to_abspath,
1361 const char **op_root_abspath,
1362 svn_wc_context_t *wc_ctx,
1363 const char *local_abspath,
1364 apr_pool_t *result_pool,
1365 apr_pool_t *scratch_pool)
1366 {
1367 svn_boolean_t is_deleted;
1368
1369 if (moved_to_abspath)
1370 *moved_to_abspath = NULL;
1371 if (op_root_abspath)
1372 *op_root_abspath = NULL;
1373
1374 SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath,
1375 scratch_pool));
1376 if (is_deleted)
1377 SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL,
1378 op_root_abspath, wc_ctx->db,
1379 local_abspath,
1380 result_pool, scratch_pool));
1381
1382 return SVN_NO_ERROR;
1383 }
1384
1385
1386 svn_error_t *
svn_wc__node_was_moved_here(const char ** moved_from_abspath,const char ** delete_op_root_abspath,svn_wc_context_t * wc_ctx,const char * local_abspath,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1387 svn_wc__node_was_moved_here(const char **moved_from_abspath,
1388 const char **delete_op_root_abspath,
1389 svn_wc_context_t *wc_ctx,
1390 const char *local_abspath,
1391 apr_pool_t *result_pool,
1392 apr_pool_t *scratch_pool)
1393 {
1394 svn_error_t *err;
1395
1396 if (moved_from_abspath)
1397 *moved_from_abspath = NULL;
1398 if (delete_op_root_abspath)
1399 *delete_op_root_abspath = NULL;
1400
1401 err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL,
1402 delete_op_root_abspath,
1403 wc_ctx->db, local_abspath,
1404 result_pool, scratch_pool);
1405
1406 if (err)
1407 {
1408 /* Return error for not added nodes */
1409 if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
1410 return svn_error_trace(err);
1411
1412 /* Path not moved here */
1413 svn_error_clear(err);
1414 return SVN_NO_ERROR;
1415 }
1416
1417 return SVN_NO_ERROR;
1418 }
1419