]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_wc/node.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_wc / node.c
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 \f
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 *
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 *
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 \f
122 svn_error_t *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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, &copyfrom_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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 }