1251881Speter/*
2251881Speter * node.c:  routines for getting information about nodes in the working copy.
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter/* A note about these functions:
25251881Speter
26251881Speter   We aren't really sure yet which bits of data libsvn_client needs about
27251881Speter   nodes.  In wc-1, we just grab the entry, and then use whatever we want
28251881Speter   from it.  Such a pattern is Bad.
29251881Speter
30251881Speter   This file is intended to hold functions which retrieve specific bits of
31251881Speter   information about a node, and will hopefully give us a better idea about
32251881Speter   what data libsvn_client needs, and how to best provide that data in 1.7
33251881Speter   final.  As such, these functions should only be called from outside
34251881Speter   libsvn_wc; any internal callers are encouraged to use the appropriate
35251881Speter   information fetching function, such as svn_wc__db_read_info().
36251881Speter*/
37251881Speter
38251881Speter#include <apr_pools.h>
39251881Speter#include <apr_time.h>
40251881Speter
41251881Speter#include "svn_pools.h"
42251881Speter#include "svn_dirent_uri.h"
43251881Speter#include "svn_path.h"
44251881Speter#include "svn_hash.h"
45251881Speter#include "svn_types.h"
46251881Speter
47251881Speter#include "wc.h"
48251881Speter#include "props.h"
49251881Speter#include "entries.h"
50251881Speter#include "wc_db.h"
51251881Speter
52251881Speter#include "svn_private_config.h"
53251881Speter#include "private/svn_wc_private.h"
54251881Speter
55251881Speter
56251881Speter/* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining
57251881Speter * each name in REL_CHILDREN onto DIR_ABSPATH.  If SHOW_HIDDEN is false then
58251881Speter * omit any paths that are reported as 'hidden' by svn_wc__db_node_hidden().
59251881Speter *
60251881Speter * Allocate the output array and its elements in RESULT_POOL. */
61251881Speterstatic svn_error_t *
62251881Speterfilter_and_make_absolute(const apr_array_header_t **children_abspaths,
63251881Speter                         svn_wc_context_t *wc_ctx,
64251881Speter                         const char *dir_abspath,
65251881Speter                         const apr_array_header_t *rel_children,
66251881Speter                         svn_boolean_t show_hidden,
67251881Speter                         apr_pool_t *result_pool,
68251881Speter                         apr_pool_t *scratch_pool)
69251881Speter{
70251881Speter  apr_array_header_t *children;
71251881Speter  int i;
72251881Speter
73251881Speter  children = apr_array_make(result_pool, rel_children->nelts,
74251881Speter                            sizeof(const char *));
75251881Speter  for (i = 0; i < rel_children->nelts; i++)
76251881Speter    {
77251881Speter      const char *child_abspath = svn_dirent_join(dir_abspath,
78251881Speter                                                  APR_ARRAY_IDX(rel_children,
79251881Speter                                                                i,
80251881Speter                                                                const char *),
81251881Speter                                                  result_pool);
82251881Speter
83251881Speter      /* Don't add hidden nodes to *CHILDREN if we don't want them. */
84251881Speter      if (!show_hidden)
85251881Speter        {
86251881Speter          svn_boolean_t child_is_hidden;
87251881Speter
88251881Speter          SVN_ERR(svn_wc__db_node_hidden(&child_is_hidden, wc_ctx->db,
89251881Speter                                         child_abspath, scratch_pool));
90251881Speter          if (child_is_hidden)
91251881Speter            continue;
92251881Speter        }
93251881Speter
94251881Speter      APR_ARRAY_PUSH(children, const char *) = child_abspath;
95251881Speter    }
96251881Speter
97251881Speter  *children_abspaths = children;
98251881Speter
99251881Speter  return SVN_NO_ERROR;
100251881Speter}
101251881Speter
102251881Speter
103251881Spetersvn_error_t *
104251881Spetersvn_wc__node_get_children_of_working_node(const apr_array_header_t **children,
105251881Speter                                          svn_wc_context_t *wc_ctx,
106251881Speter                                          const char *dir_abspath,
107251881Speter                                          svn_boolean_t show_hidden,
108251881Speter                                          apr_pool_t *result_pool,
109251881Speter                                          apr_pool_t *scratch_pool)
110251881Speter{
111251881Speter  const apr_array_header_t *rel_children;
112251881Speter
113251881Speter  SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
114251881Speter                                                   wc_ctx->db, dir_abspath,
115251881Speter                                                   scratch_pool, scratch_pool));
116251881Speter  SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
117251881Speter                                   rel_children, show_hidden,
118251881Speter                                   result_pool, scratch_pool));
119251881Speter  return SVN_NO_ERROR;
120251881Speter}
121251881Speter
122251881Spetersvn_error_t *
123251881Spetersvn_wc__node_get_children(const apr_array_header_t **children,
124251881Speter                          svn_wc_context_t *wc_ctx,
125251881Speter                          const char *dir_abspath,
126251881Speter                          svn_boolean_t show_hidden,
127251881Speter                          apr_pool_t *result_pool,
128251881Speter                          apr_pool_t *scratch_pool)
129251881Speter{
130251881Speter  const apr_array_header_t *rel_children;
131251881Speter
132251881Speter  SVN_ERR(svn_wc__db_read_children(&rel_children, wc_ctx->db, dir_abspath,
133251881Speter                                   scratch_pool, scratch_pool));
134251881Speter  SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
135251881Speter                                   rel_children, show_hidden,
136251881Speter                                   result_pool, scratch_pool));
137251881Speter  return SVN_NO_ERROR;
138251881Speter}
139251881Speter
140251881Speter
141251881Spetersvn_error_t *
142251881Spetersvn_wc__internal_get_repos_info(svn_revnum_t *revision,
143251881Speter                                const char **repos_relpath,
144251881Speter                                const char **repos_root_url,
145251881Speter                                const char **repos_uuid,
146251881Speter                                svn_wc__db_t *db,
147251881Speter                                const char *local_abspath,
148251881Speter                                apr_pool_t *result_pool,
149251881Speter                                apr_pool_t *scratch_pool)
150251881Speter{
151251881Speter  svn_wc__db_status_t status;
152251881Speter  svn_boolean_t have_work;
153251881Speter
154251881Speter  SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
155251881Speter                               repos_root_url, repos_uuid,
156251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL,
157251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL,
158251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL,
159251881Speter                               NULL, NULL, &have_work,
160251881Speter                               db, local_abspath,
161251881Speter                               result_pool, scratch_pool));
162251881Speter
163251881Speter  if ((repos_relpath ? *repos_relpath != NULL : TRUE)
164251881Speter      && (repos_root_url ? *repos_root_url  != NULL: TRUE)
165251881Speter      && (repos_uuid ? *repos_uuid != NULL : TRUE))
166251881Speter    return SVN_NO_ERROR; /* We got the requested information */
167251881Speter
168251881Speter  if (!have_work) /* not-present, (server-)excluded? */
169251881Speter    {
170251881Speter      return SVN_NO_ERROR; /* Can't fetch more */
171251881Speter    }
172251881Speter
173251881Speter  if (status == svn_wc__db_status_deleted)
174251881Speter    {
175251881Speter      const char *base_del_abspath, *wrk_del_abspath;
176251881Speter
177251881Speter      SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL,
178251881Speter                                       &wrk_del_abspath, NULL,
179251881Speter                                       db, local_abspath,
180251881Speter                                       scratch_pool, scratch_pool));
181251881Speter
182251881Speter      if (base_del_abspath)
183251881Speter        {
184251881Speter          SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, repos_relpath,
185251881Speter                                           repos_root_url, repos_uuid, NULL,
186251881Speter                                           NULL, NULL, NULL, NULL, NULL, NULL,
187251881Speter                                           NULL, NULL, NULL,
188251881Speter                                           db, base_del_abspath,
189251881Speter                                           result_pool, scratch_pool));
190251881Speter
191251881Speter          /* If we have a repos_relpath, it is of the op-root */
192251881Speter          if (repos_relpath)
193251881Speter            *repos_relpath = svn_relpath_join(*repos_relpath,
194251881Speter                                svn_dirent_skip_ancestor(base_del_abspath,
195251881Speter                                                         local_abspath),
196251881Speter                                              result_pool);
197251881Speter          /* We keep revision as SVN_INVALID_REVNUM */
198251881Speter        }
199251881Speter      else if (wrk_del_abspath)
200251881Speter        {
201251881Speter          const char *op_root_abspath = NULL;
202251881Speter
203251881Speter          SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
204251881Speter                                                    ? &op_root_abspath : NULL,
205251881Speter                                           repos_relpath, repos_root_url,
206251881Speter                                           repos_uuid, NULL, NULL, NULL, NULL,
207251881Speter                                           db, svn_dirent_dirname(
208251881Speter                                                   wrk_del_abspath,
209251881Speter                                                   scratch_pool),
210251881Speter                                           result_pool, scratch_pool));
211251881Speter
212251881Speter          /* If we have a repos_relpath, it is of the op-root */
213251881Speter          if (repos_relpath)
214251881Speter            *repos_relpath = svn_relpath_join(
215251881Speter                                    *repos_relpath,
216251881Speter                                    svn_dirent_skip_ancestor(op_root_abspath,
217251881Speter                                                             local_abspath),
218251881Speter                                    result_pool);
219251881Speter        }
220251881Speter    }
221251881Speter  else /* added, or WORKING incomplete */
222251881Speter    {
223251881Speter      const char *op_root_abspath = NULL;
224251881Speter
225251881Speter      /* We have an addition. scan_addition() will find the intended
226251881Speter         repository location by scanning up the tree.  */
227251881Speter      SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
228251881Speter                                                    ? &op_root_abspath : NULL,
229251881Speter                                       repos_relpath, repos_root_url,
230251881Speter                                       repos_uuid, NULL, NULL, NULL, NULL,
231251881Speter                                       db, local_abspath,
232251881Speter                                       result_pool, scratch_pool));
233251881Speter    }
234251881Speter
235251881Speter  SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL);
236251881Speter  SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL);
237251881Speter  return SVN_NO_ERROR;
238251881Speter}
239251881Speter
240251881Spetersvn_error_t *
241251881Spetersvn_wc__node_get_repos_info(svn_revnum_t *revision,
242251881Speter                            const char **repos_relpath,
243251881Speter                            const char **repos_root_url,
244251881Speter                            const char **repos_uuid,
245251881Speter                            svn_wc_context_t *wc_ctx,
246251881Speter                            const char *local_abspath,
247251881Speter                            apr_pool_t *result_pool,
248251881Speter                            apr_pool_t *scratch_pool)
249251881Speter{
250251881Speter  return svn_error_trace(
251251881Speter            svn_wc__internal_get_repos_info(revision,
252251881Speter                                            repos_relpath,
253251881Speter                                            repos_root_url,
254251881Speter                                            repos_uuid,
255251881Speter                                            wc_ctx->db, local_abspath,
256251881Speter                                            result_pool, scratch_pool));
257251881Speter}
258251881Speter
259251881Speter/* Convert DB_KIND into the appropriate NODE_KIND value.
260251881Speter * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB
261251881Speter * even if DB_STATUS indicates that the node is hidden.
262251881Speter * Else, return svn_node_none for such nodes.
263251881Speter *
264251881Speter * ### This is a bit ugly. We should consider promoting svn_kind_t
265251881Speter * ### to the de-facto node kind type instead of converting between them
266251881Speter * ### in non-backwards compat code.
267251881Speter * ### See also comments at the definition of svn_kind_t.
268251881Speter *
269251881Speter * ### In reality, the previous comment is out of date, as there is
270251881Speter * ### now only one enumeration for node kinds, and that is
271251881Speter * ### svn_node_kind_t (svn_kind_t was merged with that). But it's
272251881Speter * ### still ugly.
273251881Speter */
274251881Speterstatic svn_error_t *
275251881Speterconvert_db_kind_to_node_kind(svn_node_kind_t *node_kind,
276251881Speter                             svn_node_kind_t db_kind,
277251881Speter                             svn_wc__db_status_t db_status,
278251881Speter                             svn_boolean_t show_hidden)
279251881Speter{
280251881Speter  *node_kind = db_kind;
281251881Speter
282251881Speter  /* Make sure hidden nodes return svn_node_none. */
283251881Speter  if (! show_hidden)
284251881Speter    switch (db_status)
285251881Speter      {
286251881Speter        case svn_wc__db_status_not_present:
287251881Speter        case svn_wc__db_status_server_excluded:
288251881Speter        case svn_wc__db_status_excluded:
289251881Speter          *node_kind = svn_node_none;
290251881Speter
291251881Speter        default:
292251881Speter          break;
293251881Speter      }
294251881Speter
295251881Speter  return SVN_NO_ERROR;
296251881Speter}
297251881Speter
298251881Spetersvn_error_t *
299251881Spetersvn_wc_read_kind2(svn_node_kind_t *kind,
300251881Speter                  svn_wc_context_t *wc_ctx,
301251881Speter                  const char *local_abspath,
302251881Speter                  svn_boolean_t show_deleted,
303251881Speter                  svn_boolean_t show_hidden,
304251881Speter                  apr_pool_t *scratch_pool)
305251881Speter{
306251881Speter  svn_node_kind_t db_kind;
307251881Speter
308251881Speter  SVN_ERR(svn_wc__db_read_kind(&db_kind,
309251881Speter                               wc_ctx->db, local_abspath,
310251881Speter                               TRUE,
311251881Speter                               show_deleted,
312251881Speter                               show_hidden,
313251881Speter                               scratch_pool));
314251881Speter
315251881Speter  if (db_kind == svn_node_dir)
316251881Speter    *kind = svn_node_dir;
317251881Speter  else if (db_kind == svn_node_file || db_kind == svn_node_symlink)
318251881Speter    *kind = svn_node_file;
319251881Speter  else
320251881Speter    *kind = svn_node_none;
321251881Speter
322251881Speter  return SVN_NO_ERROR;
323251881Speter}
324251881Speter
325251881Spetersvn_error_t *
326251881Spetersvn_wc__node_get_depth(svn_depth_t *depth,
327251881Speter                       svn_wc_context_t *wc_ctx,
328251881Speter                       const char *local_abspath,
329251881Speter                       apr_pool_t *scratch_pool)
330251881Speter{
331251881Speter  return svn_error_trace(
332251881Speter    svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
333251881Speter                         NULL, NULL, depth, NULL, NULL, NULL, NULL,
334251881Speter                         NULL, NULL, NULL, NULL, NULL, NULL, NULL,
335251881Speter                         NULL, NULL, NULL, NULL, NULL, NULL,
336251881Speter                         wc_ctx->db, local_abspath, scratch_pool,
337251881Speter                         scratch_pool));
338251881Speter}
339251881Speter
340251881Spetersvn_error_t *
341251881Spetersvn_wc__node_get_changed_info(svn_revnum_t *changed_rev,
342251881Speter                              apr_time_t *changed_date,
343251881Speter                              const char **changed_author,
344251881Speter                              svn_wc_context_t *wc_ctx,
345251881Speter                              const char *local_abspath,
346251881Speter                              apr_pool_t *result_pool,
347251881Speter                              apr_pool_t *scratch_pool)
348251881Speter{
349251881Speter  return svn_error_trace(
350251881Speter    svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev,
351251881Speter                         changed_date, changed_author, NULL, NULL, NULL,
352251881Speter                         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
353251881Speter                         NULL, NULL, NULL, NULL, NULL, NULL, NULL,
354251881Speter                         wc_ctx->db, local_abspath, result_pool,
355251881Speter                         scratch_pool));
356251881Speter}
357251881Speter
358251881Spetersvn_error_t *
359251881Spetersvn_wc__node_get_url(const char **url,
360251881Speter                     svn_wc_context_t *wc_ctx,
361251881Speter                     const char *local_abspath,
362251881Speter                     apr_pool_t *result_pool,
363251881Speter                     apr_pool_t *scratch_pool)
364251881Speter{
365251881Speter  return svn_error_trace(svn_wc__db_read_url(url, wc_ctx->db, local_abspath,
366251881Speter                                             result_pool, scratch_pool));
367251881Speter}
368251881Speter
369251881Speter/* A recursive node-walker, helper for svn_wc__internal_walk_children().
370251881Speter *
371251881Speter * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of
372251881Speter * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a
373251881Speter * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else
374251881Speter * ignore them. Restrict the depth of the walk to DEPTH.
375251881Speter *
376251881Speter * ### Is it possible for a subdirectory to be hidden and known to be a
377251881Speter *     directory?  If so, and if show_hidden is true, this will try to
378251881Speter *     recurse into it.  */
379251881Speterstatic svn_error_t *
380251881Speterwalker_helper(svn_wc__db_t *db,
381251881Speter              const char *dir_abspath,
382251881Speter              svn_boolean_t show_hidden,
383251881Speter              const apr_hash_t *changelist_filter,
384251881Speter              svn_wc__node_found_func_t walk_callback,
385251881Speter              void *walk_baton,
386251881Speter              svn_depth_t depth,
387251881Speter              svn_cancel_func_t cancel_func,
388251881Speter              void *cancel_baton,
389251881Speter              apr_pool_t *scratch_pool)
390251881Speter{
391251881Speter  apr_hash_t *rel_children_info;
392251881Speter  apr_hash_index_t *hi;
393251881Speter  apr_pool_t *iterpool;
394251881Speter
395251881Speter  if (depth == svn_depth_empty)
396251881Speter    return SVN_NO_ERROR;
397251881Speter
398251881Speter  SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db,
399251881Speter                                               dir_abspath, scratch_pool,
400251881Speter                                               scratch_pool));
401251881Speter
402251881Speter
403251881Speter  iterpool = svn_pool_create(scratch_pool);
404251881Speter  for (hi = apr_hash_first(scratch_pool, rel_children_info);
405251881Speter       hi;
406251881Speter       hi = apr_hash_next(hi))
407251881Speter    {
408251881Speter      const char *child_name = svn__apr_hash_index_key(hi);
409251881Speter      struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi);
410251881Speter      svn_node_kind_t child_kind = wi->kind;
411251881Speter      svn_wc__db_status_t child_status = wi->status;
412251881Speter      const char *child_abspath;
413251881Speter
414251881Speter      svn_pool_clear(iterpool);
415251881Speter
416251881Speter      /* See if someone wants to cancel this operation. */
417251881Speter      if (cancel_func)
418251881Speter        SVN_ERR(cancel_func(cancel_baton));
419251881Speter
420251881Speter      child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
421251881Speter
422251881Speter      if (!show_hidden)
423251881Speter        switch (child_status)
424251881Speter          {
425251881Speter            case svn_wc__db_status_not_present:
426251881Speter            case svn_wc__db_status_server_excluded:
427251881Speter            case svn_wc__db_status_excluded:
428251881Speter              continue;
429251881Speter            default:
430251881Speter              break;
431251881Speter          }
432251881Speter
433251881Speter      /* Return the child, if appropriate. */
434251881Speter      if ( (child_kind == svn_node_file
435251881Speter             || depth >= svn_depth_immediates)
436251881Speter           && svn_wc__internal_changelist_match(db, child_abspath,
437251881Speter                                                changelist_filter,
438251881Speter                                                scratch_pool) )
439251881Speter        {
440251881Speter          svn_node_kind_t kind;
441251881Speter
442251881Speter          SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind,
443251881Speter                                               child_status, show_hidden));
444251881Speter          /* ### We might want to pass child_status as well because at least
445251881Speter           * ### one callee is asking for it.
446251881Speter           * ### But is it OK to use an svn_wc__db type in this API?
447251881Speter           * ###    Not yet, we need to get the node walker
448251881Speter           * ###    libsvn_wc-internal first. -hkw */
449251881Speter          SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool));
450251881Speter        }
451251881Speter
452251881Speter      /* Recurse into this directory, if appropriate. */
453251881Speter      if (child_kind == svn_node_dir
454251881Speter            && depth >= svn_depth_immediates)
455251881Speter        {
456251881Speter          svn_depth_t depth_below_here = depth;
457251881Speter
458251881Speter          if (depth == svn_depth_immediates)
459251881Speter            depth_below_here = svn_depth_empty;
460251881Speter
461251881Speter          SVN_ERR(walker_helper(db, child_abspath, show_hidden,
462251881Speter                                changelist_filter,
463251881Speter                                walk_callback, walk_baton,
464251881Speter                                depth_below_here,
465251881Speter                                cancel_func, cancel_baton,
466251881Speter                                iterpool));
467251881Speter        }
468251881Speter    }
469251881Speter
470251881Speter  svn_pool_destroy(iterpool);
471251881Speter
472251881Speter  return SVN_NO_ERROR;
473251881Speter}
474251881Speter
475251881Speter
476251881Spetersvn_error_t *
477251881Spetersvn_wc__internal_walk_children(svn_wc__db_t *db,
478251881Speter                               const char *local_abspath,
479251881Speter                               svn_boolean_t show_hidden,
480251881Speter                               const apr_array_header_t *changelist_filter,
481251881Speter                               svn_wc__node_found_func_t walk_callback,
482251881Speter                               void *walk_baton,
483251881Speter                               svn_depth_t walk_depth,
484251881Speter                               svn_cancel_func_t cancel_func,
485251881Speter                               void *cancel_baton,
486251881Speter                               apr_pool_t *scratch_pool)
487251881Speter{
488251881Speter  svn_node_kind_t db_kind;
489251881Speter  svn_node_kind_t kind;
490251881Speter  svn_wc__db_status_t status;
491251881Speter  apr_hash_t *changelist_hash = NULL;
492251881Speter
493251881Speter  SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
494251881Speter                 && walk_depth <= svn_depth_infinity);
495251881Speter
496251881Speter  if (changelist_filter && changelist_filter->nelts)
497251881Speter    SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
498251881Speter                                       scratch_pool));
499251881Speter
500251881Speter  /* Check if the node exists before the first callback */
501251881Speter  SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
502251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL,
503251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
504251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
505251881Speter                               db, local_abspath, scratch_pool, scratch_pool));
506251881Speter
507251881Speter  SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
508251881Speter
509251881Speter  if (svn_wc__internal_changelist_match(db, local_abspath,
510251881Speter                                        changelist_hash, scratch_pool))
511251881Speter    SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
512251881Speter
513251881Speter  if (db_kind == svn_node_file
514251881Speter      || status == svn_wc__db_status_not_present
515251881Speter      || status == svn_wc__db_status_excluded
516251881Speter      || status == svn_wc__db_status_server_excluded)
517251881Speter    return SVN_NO_ERROR;
518251881Speter
519251881Speter  if (db_kind == svn_node_dir)
520251881Speter    {
521251881Speter      return svn_error_trace(
522251881Speter        walker_helper(db, local_abspath, show_hidden, changelist_hash,
523251881Speter                      walk_callback, walk_baton,
524251881Speter                      walk_depth, cancel_func, cancel_baton, scratch_pool));
525251881Speter    }
526251881Speter
527251881Speter  return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
528251881Speter                           _("'%s' has an unrecognized node kind"),
529251881Speter                           svn_dirent_local_style(local_abspath,
530251881Speter                                                  scratch_pool));
531251881Speter}
532251881Speter
533251881Spetersvn_error_t *
534251881Spetersvn_wc__node_is_status_deleted(svn_boolean_t *is_deleted,
535251881Speter                               svn_wc_context_t *wc_ctx,
536251881Speter                               const char *local_abspath,
537251881Speter                               apr_pool_t *scratch_pool)
538251881Speter{
539251881Speter  svn_wc__db_status_t status;
540251881Speter
541251881Speter  SVN_ERR(svn_wc__db_read_info(&status,
542251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
543251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
544251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
545251881Speter                               NULL, NULL, NULL, NULL, NULL,
546251881Speter                               wc_ctx->db, local_abspath,
547251881Speter                               scratch_pool, scratch_pool));
548251881Speter
549251881Speter  *is_deleted = (status == svn_wc__db_status_deleted);
550251881Speter
551251881Speter  return SVN_NO_ERROR;
552251881Speter}
553251881Speter
554251881Spetersvn_error_t *
555251881Spetersvn_wc__node_get_deleted_ancestor(const char **deleted_ancestor_abspath,
556251881Speter                                  svn_wc_context_t *wc_ctx,
557251881Speter                                  const char *local_abspath,
558251881Speter                                  apr_pool_t *result_pool,
559251881Speter                                  apr_pool_t *scratch_pool)
560251881Speter{
561251881Speter  svn_wc__db_status_t status;
562251881Speter
563251881Speter  *deleted_ancestor_abspath = NULL;
564251881Speter
565251881Speter  SVN_ERR(svn_wc__db_read_info(&status,
566251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
567251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
568251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
569251881Speter                               NULL, NULL, NULL, NULL, NULL,
570251881Speter                               wc_ctx->db, local_abspath,
571251881Speter                               scratch_pool, scratch_pool));
572251881Speter
573251881Speter  if (status == svn_wc__db_status_deleted)
574251881Speter    SVN_ERR(svn_wc__db_scan_deletion(deleted_ancestor_abspath, NULL, NULL,
575251881Speter                                     NULL, wc_ctx->db, local_abspath,
576251881Speter                                     result_pool, scratch_pool));
577251881Speter
578251881Speter  return SVN_NO_ERROR;
579251881Speter}
580251881Speter
581251881Spetersvn_error_t *
582251881Spetersvn_wc__node_is_not_present(svn_boolean_t *is_not_present,
583251881Speter                            svn_boolean_t *is_excluded,
584251881Speter                            svn_boolean_t *is_server_excluded,
585251881Speter                            svn_wc_context_t *wc_ctx,
586251881Speter                            const char *local_abspath,
587251881Speter                            svn_boolean_t base_only,
588251881Speter                            apr_pool_t *scratch_pool)
589251881Speter{
590251881Speter  svn_wc__db_status_t status;
591251881Speter
592251881Speter  if (base_only)
593251881Speter    {
594251881Speter      SVN_ERR(svn_wc__db_base_get_info(&status,
595251881Speter                                       NULL, NULL, NULL, NULL, NULL, NULL,
596251881Speter                                       NULL, NULL, NULL, NULL, NULL, NULL,
597251881Speter                                       NULL, NULL, NULL,
598251881Speter                                       wc_ctx->db, local_abspath,
599251881Speter                                       scratch_pool, scratch_pool));
600251881Speter    }
601251881Speter  else
602251881Speter    {
603251881Speter      SVN_ERR(svn_wc__db_read_info(&status,
604251881Speter                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
605251881Speter                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
606251881Speter                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
607251881Speter                                   NULL, NULL, NULL, NULL, NULL,
608251881Speter                                   wc_ctx->db, local_abspath,
609251881Speter                                   scratch_pool, scratch_pool));
610251881Speter    }
611251881Speter
612251881Speter  if (is_not_present)
613251881Speter    *is_not_present = (status == svn_wc__db_status_not_present);
614251881Speter
615251881Speter  if (is_excluded)
616251881Speter    *is_excluded = (status == svn_wc__db_status_excluded);
617251881Speter
618251881Speter  if (is_server_excluded)
619251881Speter    *is_server_excluded = (status == svn_wc__db_status_server_excluded);
620251881Speter
621251881Speter  return SVN_NO_ERROR;
622251881Speter}
623251881Speter
624251881Spetersvn_error_t *
625251881Spetersvn_wc__node_is_added(svn_boolean_t *is_added,
626251881Speter                      svn_wc_context_t *wc_ctx,
627251881Speter                      const char *local_abspath,
628251881Speter                      apr_pool_t *scratch_pool)
629251881Speter{
630251881Speter  svn_wc__db_status_t status;
631251881Speter
632251881Speter  SVN_ERR(svn_wc__db_read_info(&status,
633251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
634251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
635251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
636251881Speter                               NULL, NULL, NULL, NULL, NULL,
637251881Speter                               wc_ctx->db, local_abspath,
638251881Speter                               scratch_pool, scratch_pool));
639251881Speter  *is_added = (status == svn_wc__db_status_added);
640251881Speter
641251881Speter  return SVN_NO_ERROR;
642251881Speter}
643251881Speter
644251881Spetersvn_error_t *
645251881Spetersvn_wc__node_has_working(svn_boolean_t *has_working,
646251881Speter                         svn_wc_context_t *wc_ctx,
647251881Speter                         const char *local_abspath,
648251881Speter                         apr_pool_t *scratch_pool)
649251881Speter{
650251881Speter  svn_wc__db_status_t status;
651251881Speter
652251881Speter  SVN_ERR(svn_wc__db_read_info(&status,
653251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
654251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
655251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
656251881Speter                               NULL, NULL, NULL, NULL, has_working,
657251881Speter                               wc_ctx->db, local_abspath,
658251881Speter                               scratch_pool, scratch_pool));
659251881Speter
660251881Speter  return SVN_NO_ERROR;
661251881Speter}
662251881Speter
663251881Speter
664251881Spetersvn_error_t *
665251881Spetersvn_wc__node_get_base(svn_node_kind_t *kind,
666251881Speter                      svn_revnum_t *revision,
667251881Speter                      const char **repos_relpath,
668251881Speter                      const char **repos_root_url,
669251881Speter                      const char **repos_uuid,
670251881Speter                      const char **lock_token,
671251881Speter                      svn_wc_context_t *wc_ctx,
672251881Speter                      const char *local_abspath,
673251881Speter                      svn_boolean_t ignore_enoent,
674251881Speter                      svn_boolean_t show_hidden,
675251881Speter                      apr_pool_t *result_pool,
676251881Speter                      apr_pool_t *scratch_pool)
677251881Speter{
678251881Speter  svn_error_t *err;
679251881Speter  svn_wc__db_status_t status;
680251881Speter  svn_wc__db_lock_t *lock;
681251881Speter  svn_node_kind_t db_kind;
682251881Speter
683251881Speter  err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath,
684251881Speter                                 repos_root_url, repos_uuid, NULL,
685251881Speter                                 NULL, NULL, NULL, NULL, NULL,
686251881Speter                                 lock_token ? &lock : NULL,
687251881Speter                                 NULL, NULL, NULL,
688251881Speter                                 wc_ctx->db, local_abspath,
689251881Speter                                 result_pool, scratch_pool);
690251881Speter
691251881Speter  if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
692251881Speter    return svn_error_trace(err);
693251881Speter  else if (err
694251881Speter           || (!err && !show_hidden
695251881Speter               && (status != svn_wc__db_status_normal
696251881Speter                   && status != svn_wc__db_status_incomplete)))
697251881Speter    {
698251881Speter      if (!ignore_enoent)
699251881Speter        {
700251881Speter          if (err)
701251881Speter            return svn_error_trace(err);
702251881Speter          else
703251881Speter            return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
704251881Speter                                     _("The node '%s' was not found."),
705251881Speter                                     svn_dirent_local_style(local_abspath,
706251881Speter                                                            scratch_pool));
707251881Speter        }
708251881Speter      svn_error_clear(err);
709251881Speter
710251881Speter      if (kind)
711251881Speter        *kind = svn_node_unknown;
712251881Speter      if (revision)
713251881Speter        *revision = SVN_INVALID_REVNUM;
714251881Speter      if (repos_relpath)
715251881Speter        *repos_relpath = NULL;
716251881Speter      if (repos_root_url)
717251881Speter        *repos_root_url = NULL;
718251881Speter      if (repos_uuid)
719251881Speter        *repos_uuid = NULL;
720251881Speter      if (lock_token)
721251881Speter        *lock_token = NULL;
722251881Speter      return SVN_NO_ERROR;
723251881Speter    }
724251881Speter
725251881Speter  if (kind)
726251881Speter    *kind = db_kind;
727251881Speter  if (lock_token)
728251881Speter    *lock_token = lock ? lock->token : NULL;
729251881Speter
730251881Speter  SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision));
731251881Speter  SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
732251881Speter  SVN_ERR_ASSERT(!repos_root_url || *repos_root_url);
733251881Speter  SVN_ERR_ASSERT(!repos_uuid || *repos_uuid);
734251881Speter  return SVN_NO_ERROR;
735251881Speter}
736251881Speter
737251881Spetersvn_error_t *
738251881Spetersvn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision,
739251881Speter                                   svn_revnum_t *changed_rev,
740251881Speter                                   apr_time_t *changed_date,
741251881Speter                                   const char **changed_author,
742251881Speter                                   svn_wc_context_t *wc_ctx,
743251881Speter                                   const char *local_abspath,
744251881Speter                                   apr_pool_t *result_pool,
745251881Speter                                   apr_pool_t *scratch_pool)
746251881Speter{
747251881Speter  svn_wc__db_status_t status;
748251881Speter  svn_boolean_t have_base, have_more_work, have_work;
749251881Speter
750251881Speter  SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL,
751251881Speter                               changed_rev, changed_date, changed_author,
752251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
753251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
754251881Speter                               &have_base, &have_more_work, &have_work,
755251881Speter                               wc_ctx->db, local_abspath,
756251881Speter                               result_pool, scratch_pool));
757251881Speter
758251881Speter  if (!have_work
759251881Speter      || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev))
760251881Speter          && (!revision || SVN_IS_VALID_REVNUM(*revision)))
761251881Speter      || ((status != svn_wc__db_status_added)
762251881Speter          && (status != svn_wc__db_status_deleted)))
763251881Speter    {
764251881Speter      return SVN_NO_ERROR; /* We got everything we need */
765251881Speter    }
766251881Speter
767251881Speter  if (have_base && !have_more_work)
768251881Speter    SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
769251881Speter                                     changed_rev, changed_date, changed_author,
770251881Speter                                     NULL, NULL, NULL,
771251881Speter                                     NULL, NULL, NULL, NULL,
772251881Speter                                     wc_ctx->db, local_abspath,
773251881Speter                                     result_pool, scratch_pool));
774251881Speter  else if (status == svn_wc__db_status_deleted)
775251881Speter    /* Check the information below a WORKING delete */
776251881Speter    SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev,
777251881Speter                                          changed_date, changed_author, NULL,
778251881Speter                                          NULL, NULL, NULL, NULL,
779251881Speter                                          wc_ctx->db, local_abspath,
780251881Speter                                          result_pool, scratch_pool));
781251881Speter
782251881Speter  return SVN_NO_ERROR;
783251881Speter}
784251881Speter
785251881Spetersvn_error_t *
786251881Spetersvn_wc__internal_node_get_schedule(svn_wc_schedule_t *schedule,
787251881Speter                                   svn_boolean_t *copied,
788251881Speter                                   svn_wc__db_t *db,
789251881Speter                                   const char *local_abspath,
790251881Speter                                   apr_pool_t *scratch_pool)
791251881Speter{
792251881Speter  svn_wc__db_status_t status;
793251881Speter  svn_boolean_t op_root;
794251881Speter  svn_boolean_t have_base;
795251881Speter  svn_boolean_t have_work;
796251881Speter  svn_boolean_t have_more_work;
797251881Speter  const char *copyfrom_relpath;
798251881Speter
799251881Speter  if (schedule)
800251881Speter    *schedule = svn_wc_schedule_normal;
801251881Speter  if (copied)
802251881Speter    *copied = FALSE;
803251881Speter
804251881Speter  SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
805251881Speter                               NULL, NULL, NULL, NULL, NULL, &copyfrom_relpath,
806251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
807251881Speter                               &op_root, NULL, NULL,
808251881Speter                               &have_base, &have_more_work, &have_work,
809251881Speter                               db, local_abspath, scratch_pool, scratch_pool));
810251881Speter
811251881Speter  switch (status)
812251881Speter    {
813251881Speter      case svn_wc__db_status_not_present:
814251881Speter      case svn_wc__db_status_server_excluded:
815251881Speter      case svn_wc__db_status_excluded:
816251881Speter        /* We used status normal in the entries world. */
817251881Speter        if (schedule)
818251881Speter          *schedule = svn_wc_schedule_normal;
819251881Speter        break;
820251881Speter      case svn_wc__db_status_normal:
821251881Speter      case svn_wc__db_status_incomplete:
822251881Speter        break;
823251881Speter
824251881Speter      case svn_wc__db_status_deleted:
825251881Speter        {
826251881Speter          if (schedule)
827251881Speter            *schedule = svn_wc_schedule_delete;
828251881Speter
829251881Speter          if (!copied)
830251881Speter            break;
831251881Speter
832251881Speter          if (have_more_work || !have_base)
833251881Speter            *copied = TRUE;
834251881Speter          else
835251881Speter            {
836251881Speter              const char *work_del_abspath;
837251881Speter
838251881Speter              /* Find out details of our deletion.  */
839251881Speter              SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
840251881Speter                                               &work_del_abspath, NULL,
841251881Speter                                               db, local_abspath,
842251881Speter                                               scratch_pool, scratch_pool));
843251881Speter
844251881Speter              if (work_del_abspath)
845251881Speter                *copied = TRUE; /* Working deletion */
846251881Speter            }
847251881Speter          break;
848251881Speter        }
849251881Speter      case svn_wc__db_status_added:
850251881Speter        {
851251881Speter          if (!op_root)
852251881Speter            {
853251881Speter              if (copied)
854251881Speter                *copied = TRUE;
855251881Speter
856251881Speter              if (schedule)
857251881Speter                *schedule = svn_wc_schedule_normal;
858251881Speter
859251881Speter              break;
860251881Speter            }
861251881Speter
862251881Speter          if (copied)
863251881Speter            *copied = (copyfrom_relpath != NULL);
864251881Speter
865251881Speter          if (schedule)
866251881Speter            *schedule = svn_wc_schedule_add;
867251881Speter          else
868251881Speter            break;
869251881Speter
870251881Speter          /* Check for replaced */
871251881Speter          if (have_base || have_more_work)
872251881Speter            {
873251881Speter              svn_wc__db_status_t below_working;
874251881Speter              SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
875251881Speter                                                    &below_working,
876251881Speter                                                    db, local_abspath,
877251881Speter                                                    scratch_pool));
878251881Speter
879251881Speter              /* If the node is not present or deleted (read: not present
880251881Speter                 in working), then the node is not a replacement */
881251881Speter              if (below_working != svn_wc__db_status_not_present
882251881Speter                  && below_working != svn_wc__db_status_deleted)
883251881Speter                {
884251881Speter                  *schedule = svn_wc_schedule_replace;
885251881Speter                  break;
886251881Speter                }
887251881Speter            }
888251881Speter          break;
889251881Speter        }
890251881Speter      default:
891251881Speter        SVN_ERR_MALFUNCTION();
892251881Speter    }
893251881Speter
894251881Speter  return SVN_NO_ERROR;
895251881Speter}
896251881Speter
897251881Spetersvn_error_t *
898251881Spetersvn_wc__node_get_schedule(svn_wc_schedule_t *schedule,
899251881Speter                          svn_boolean_t *copied,
900251881Speter                          svn_wc_context_t *wc_ctx,
901251881Speter                          const char *local_abspath,
902251881Speter                          apr_pool_t *scratch_pool)
903251881Speter{
904251881Speter  return svn_error_trace(
905251881Speter           svn_wc__internal_node_get_schedule(schedule,
906251881Speter                                              copied,
907251881Speter                                              wc_ctx->db,
908251881Speter                                              local_abspath,
909251881Speter                                              scratch_pool));
910251881Speter}
911251881Speter
912251881Spetersvn_error_t *
913251881Spetersvn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx,
914251881Speter                                       const char *local_abspath,
915251881Speter                                       apr_pool_t *scratch_pool)
916251881Speter{
917251881Speter  return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive(
918251881Speter                              wc_ctx->db, local_abspath, scratch_pool));
919251881Speter}
920251881Speter
921251881Speter
922251881Spetersvn_error_t *
923251881Spetersvn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens,
924251881Speter                                       svn_wc_context_t *wc_ctx,
925251881Speter                                       const char *local_abspath,
926251881Speter                                       apr_pool_t *result_pool,
927251881Speter                                       apr_pool_t *scratch_pool)
928251881Speter{
929251881Speter  return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive(
930251881Speter                              lock_tokens, wc_ctx->db, local_abspath,
931251881Speter                              result_pool, scratch_pool));
932251881Speter}
933251881Speter
934251881Spetersvn_error_t *
935251881Spetersvn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees,
936251881Speter                              svn_wc_context_t *wc_ctx,
937251881Speter                              const char *local_abspath,
938251881Speter                              apr_pool_t *result_pool,
939251881Speter                              apr_pool_t *scratch_pool)
940251881Speter{
941251881Speter  return svn_error_trace(
942251881Speter           svn_wc__db_get_excluded_subtrees(server_excluded_subtrees,
943251881Speter                                            wc_ctx->db,
944251881Speter                                            local_abspath,
945251881Speter                                            result_pool,
946251881Speter                                            scratch_pool));
947251881Speter}
948251881Speter
949251881Spetersvn_error_t *
950251881Spetersvn_wc__internal_get_origin(svn_boolean_t *is_copy,
951251881Speter                            svn_revnum_t *revision,
952251881Speter                            const char **repos_relpath,
953251881Speter                            const char **repos_root_url,
954251881Speter                            const char **repos_uuid,
955251881Speter                            const char **copy_root_abspath,
956251881Speter                            svn_wc__db_t *db,
957251881Speter                            const char *local_abspath,
958251881Speter                            svn_boolean_t scan_deleted,
959251881Speter                            apr_pool_t *result_pool,
960251881Speter                            apr_pool_t *scratch_pool)
961251881Speter{
962251881Speter  const char *original_repos_relpath;
963251881Speter  const char *original_repos_root_url;
964251881Speter  const char *original_repos_uuid;
965251881Speter  svn_revnum_t original_revision;
966251881Speter  svn_wc__db_status_t status;
967251881Speter
968251881Speter  const char *tmp_repos_relpath;
969251881Speter
970251881Speter  if (!repos_relpath)
971251881Speter    repos_relpath = &tmp_repos_relpath;
972251881Speter
973251881Speter  SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
974251881Speter                               repos_root_url, repos_uuid, NULL, NULL, NULL,
975251881Speter                               NULL, NULL, NULL,
976251881Speter                               &original_repos_relpath,
977251881Speter                               &original_repos_root_url,
978251881Speter                               &original_repos_uuid, &original_revision,
979251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
980251881Speter                               NULL, NULL, is_copy,
981251881Speter                               db, local_abspath, result_pool, scratch_pool));
982251881Speter
983251881Speter  if (*repos_relpath)
984251881Speter    {
985251881Speter      return SVN_NO_ERROR; /* Returned BASE information */
986251881Speter    }
987251881Speter
988251881Speter  if (status == svn_wc__db_status_deleted && !scan_deleted)
989251881Speter    {
990251881Speter      if (is_copy)
991251881Speter        *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */
992251881Speter
993251881Speter      return SVN_NO_ERROR; /* No info */
994251881Speter    }
995251881Speter
996251881Speter  if (original_repos_relpath)
997251881Speter    {
998251881Speter      *repos_relpath = original_repos_relpath;
999251881Speter      if (revision)
1000251881Speter        *revision = original_revision;
1001251881Speter      if (repos_root_url)
1002251881Speter        *repos_root_url = original_repos_root_url;
1003251881Speter      if (repos_uuid)
1004251881Speter        *repos_uuid = original_repos_uuid;
1005251881Speter
1006251881Speter      if (copy_root_abspath == NULL)
1007251881Speter        return SVN_NO_ERROR;
1008251881Speter    }
1009251881Speter
1010251881Speter  {
1011251881Speter    svn_boolean_t scan_working = FALSE;
1012251881Speter
1013251881Speter    if (status == svn_wc__db_status_added)
1014251881Speter      scan_working = TRUE;
1015251881Speter    else if (status == svn_wc__db_status_deleted)
1016251881Speter      {
1017251881Speter        svn_boolean_t have_base;
1018251881Speter        /* Is this a BASE or a WORKING delete? */
1019251881Speter        SVN_ERR(svn_wc__db_info_below_working(&have_base, &scan_working,
1020251881Speter                                              &status, db, local_abspath,
1021251881Speter                                              scratch_pool));
1022251881Speter      }
1023251881Speter
1024251881Speter    if (scan_working)
1025251881Speter      {
1026251881Speter        const char *op_root_abspath;
1027251881Speter
1028251881Speter        SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL,
1029251881Speter                                         NULL, NULL, &original_repos_relpath,
1030251881Speter                                         repos_root_url,
1031251881Speter                                         repos_uuid, revision,
1032251881Speter                                         db, local_abspath,
1033251881Speter                                         result_pool, scratch_pool));
1034251881Speter
1035251881Speter        if (status == svn_wc__db_status_added)
1036251881Speter          {
1037251881Speter            if (is_copy)
1038251881Speter              *is_copy = FALSE;
1039251881Speter            return SVN_NO_ERROR; /* Local addition */
1040251881Speter          }
1041251881Speter
1042251881Speter        /* We don't know how the following error condition can be fulfilled
1043251881Speter         * but we have seen that happening in the wild.  Better to create
1044251881Speter         * an error than a SEGFAULT. */
1045251881Speter        if (status == svn_wc__db_status_incomplete && !original_repos_relpath)
1046251881Speter          return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
1047251881Speter                               _("Incomplete copy information on path '%s'."),
1048251881Speter                                   svn_dirent_local_style(local_abspath,
1049251881Speter                                                          scratch_pool));
1050251881Speter
1051251881Speter        *repos_relpath = svn_relpath_join(
1052251881Speter                                original_repos_relpath,
1053251881Speter                                svn_dirent_skip_ancestor(op_root_abspath,
1054251881Speter                                                         local_abspath),
1055251881Speter                                result_pool);
1056251881Speter        if (copy_root_abspath)
1057251881Speter          *copy_root_abspath = op_root_abspath;
1058251881Speter      }
1059251881Speter    else /* Deleted, excluded, not-present, server-excluded, ... */
1060251881Speter      {
1061251881Speter        if (is_copy)
1062251881Speter          *is_copy = FALSE;
1063251881Speter
1064251881Speter        SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath,
1065251881Speter                                         repos_root_url, repos_uuid, NULL,
1066251881Speter                                         NULL, NULL, NULL, NULL, NULL, NULL,
1067251881Speter                                         NULL, NULL, NULL,
1068251881Speter                                         db, local_abspath,
1069251881Speter                                         result_pool, scratch_pool));
1070251881Speter      }
1071251881Speter
1072251881Speter    return SVN_NO_ERROR;
1073251881Speter  }
1074251881Speter}
1075251881Speter
1076251881Spetersvn_error_t *
1077251881Spetersvn_wc__node_get_origin(svn_boolean_t *is_copy,
1078251881Speter                        svn_revnum_t *revision,
1079251881Speter                        const char **repos_relpath,
1080251881Speter                        const char **repos_root_url,
1081251881Speter                        const char **repos_uuid,
1082251881Speter                        const char **copy_root_abspath,
1083251881Speter                        svn_wc_context_t *wc_ctx,
1084251881Speter                        const char *local_abspath,
1085251881Speter                        svn_boolean_t scan_deleted,
1086251881Speter                        apr_pool_t *result_pool,
1087251881Speter                        apr_pool_t *scratch_pool)
1088251881Speter{
1089251881Speter  return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision,
1090251881Speter                           repos_relpath, repos_root_url, repos_uuid,
1091251881Speter                           copy_root_abspath,
1092251881Speter                           wc_ctx->db, local_abspath, scan_deleted,
1093251881Speter                           result_pool, scratch_pool));
1094251881Speter}
1095251881Speter
1096251881Spetersvn_error_t *
1097251881Spetersvn_wc__node_get_commit_status(svn_boolean_t *added,
1098251881Speter                               svn_boolean_t *deleted,
1099251881Speter                               svn_boolean_t *is_replace_root,
1100251881Speter                               svn_boolean_t *is_op_root,
1101251881Speter                               svn_revnum_t *revision,
1102251881Speter                               svn_revnum_t *original_revision,
1103251881Speter                               const char **original_repos_relpath,
1104251881Speter                               svn_wc_context_t *wc_ctx,
1105251881Speter                               const char *local_abspath,
1106251881Speter                               apr_pool_t *result_pool,
1107251881Speter                               apr_pool_t *scratch_pool)
1108251881Speter{
1109251881Speter  svn_wc__db_status_t status;
1110251881Speter  svn_boolean_t have_base;
1111251881Speter  svn_boolean_t have_more_work;
1112251881Speter  svn_boolean_t op_root;
1113251881Speter
1114251881Speter  /* ### All of this should be handled inside a single read transaction */
1115251881Speter  SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL,
1116251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1117251881Speter                               original_repos_relpath, NULL, NULL,
1118251881Speter                               original_revision, NULL, NULL, NULL,
1119251881Speter                               NULL, NULL,
1120251881Speter                               &op_root, NULL, NULL,
1121251881Speter                               &have_base, &have_more_work, NULL,
1122251881Speter                               wc_ctx->db, local_abspath,
1123251881Speter                               result_pool, scratch_pool));
1124251881Speter
1125251881Speter  if (added)
1126251881Speter    *added = (status == svn_wc__db_status_added);
1127251881Speter  if (deleted)
1128251881Speter    *deleted = (status == svn_wc__db_status_deleted);
1129251881Speter  if (is_op_root)
1130251881Speter    *is_op_root = op_root;
1131251881Speter
1132251881Speter  if (is_replace_root)
1133251881Speter    {
1134251881Speter      if (status == svn_wc__db_status_added
1135251881Speter          && op_root
1136251881Speter          && (have_base || have_more_work))
1137251881Speter        SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL,
1138251881Speter                                              wc_ctx->db, local_abspath,
1139251881Speter                                              scratch_pool));
1140251881Speter      else
1141251881Speter        *is_replace_root = FALSE;
1142251881Speter    }
1143251881Speter
1144251881Speter  /* Retrieve some information from BASE which is needed for replacing
1145251881Speter     and/or deleting BASE nodes. */
1146251881Speter  if (have_base
1147251881Speter      && !have_more_work
1148251881Speter      && op_root
1149251881Speter      && (revision && !SVN_IS_VALID_REVNUM(*revision)))
1150251881Speter    {
1151251881Speter      SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
1152251881Speter                                       NULL, NULL, NULL, NULL, NULL, NULL,
1153251881Speter                                       NULL, NULL, NULL, NULL,
1154251881Speter                                       wc_ctx->db, local_abspath,
1155251881Speter                                       scratch_pool, scratch_pool));
1156251881Speter    }
1157251881Speter
1158251881Speter  return SVN_NO_ERROR;
1159251881Speter}
1160251881Speter
1161251881Spetersvn_error_t *
1162251881Spetersvn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum,
1163251881Speter                               svn_wc_context_t *wc_ctx,
1164251881Speter                               const char *wri_abspath,
1165251881Speter                               const svn_checksum_t *sha1_checksum,
1166251881Speter                               apr_pool_t *result_pool,
1167251881Speter                               apr_pool_t *scratch_pool)
1168251881Speter{
1169251881Speter  return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum,
1170251881Speter                                                     wc_ctx->db,
1171251881Speter                                                     wri_abspath,
1172251881Speter                                                     sha1_checksum,
1173251881Speter                                                     result_pool,
1174251881Speter                                                     scratch_pool));
1175251881Speter}
1176251881Speter
1177251881Spetersvn_error_t *
1178251881Spetersvn_wc__get_not_present_descendants(const apr_array_header_t **descendants,
1179251881Speter                                    svn_wc_context_t *wc_ctx,
1180251881Speter                                    const char *local_abspath,
1181251881Speter                                    apr_pool_t *result_pool,
1182251881Speter                                    apr_pool_t *scratch_pool)
1183251881Speter{
1184251881Speter  return svn_error_trace(
1185251881Speter                svn_wc__db_get_not_present_descendants(descendants,
1186251881Speter                                                       wc_ctx->db,
1187251881Speter                                                       local_abspath,
1188251881Speter                                                       result_pool,
1189251881Speter                                                       scratch_pool));
1190251881Speter}
1191251881Speter
1192251881Spetersvn_error_t *
1193251881Spetersvn_wc__rename_wc(svn_wc_context_t *wc_ctx,
1194251881Speter                  const char *from_abspath,
1195251881Speter                  const char *dst_abspath,
1196251881Speter                  apr_pool_t *scratch_pool)
1197251881Speter{
1198251881Speter  const char *wcroot_abspath;
1199251881Speter  SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath,
1200251881Speter                                scratch_pool, scratch_pool));
1201251881Speter
1202251881Speter  if (! strcmp(from_abspath, wcroot_abspath))
1203251881Speter    {
1204251881Speter      SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
1205251881Speter
1206251881Speter      SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
1207251881Speter    }
1208251881Speter  else
1209251881Speter    return svn_error_createf(
1210251881Speter                    SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
1211251881Speter                    _("'%s' is not the root of the working copy '%s'"),
1212251881Speter                    svn_dirent_local_style(from_abspath, scratch_pool),
1213251881Speter                    svn_dirent_local_style(wcroot_abspath, scratch_pool));
1214251881Speter
1215251881Speter  return SVN_NO_ERROR;
1216251881Speter}
1217251881Speter
1218251881Spetersvn_error_t *
1219251881Spetersvn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
1220251881Speter                               svn_node_kind_t *kind,
1221251881Speter                               svn_boolean_t *deleted,
1222251881Speter                               svn_boolean_t *excluded,
1223251881Speter                               svn_depth_t *parent_depth,
1224251881Speter                               svn_wc_context_t *wc_ctx,
1225251881Speter                               const char *local_abspath,
1226251881Speter                               svn_boolean_t no_wcroot_check,
1227251881Speter                               apr_pool_t *scratch_pool)
1228251881Speter{
1229251881Speter  svn_wc__db_status_t status;
1230251881Speter  svn_node_kind_t db_kind;
1231251881Speter  svn_node_kind_t disk_kind;
1232251881Speter  svn_error_t *err;
1233251881Speter
1234251881Speter  *obstruction_state = svn_wc_notify_state_inapplicable;
1235251881Speter  if (kind)
1236251881Speter    *kind = svn_node_none;
1237251881Speter  if (deleted)
1238251881Speter    *deleted = FALSE;
1239251881Speter  if (excluded)
1240251881Speter    *excluded = FALSE;
1241251881Speter  if (parent_depth)
1242251881Speter    *parent_depth = svn_depth_unknown;
1243251881Speter
1244251881Speter  SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
1245251881Speter
1246251881Speter  err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
1247251881Speter                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1248251881Speter                             NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1249251881Speter                             NULL, NULL, NULL, NULL, NULL,
1250251881Speter                             wc_ctx->db, local_abspath,
1251251881Speter                             scratch_pool, scratch_pool);
1252251881Speter
1253251881Speter  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
1254251881Speter    {
1255251881Speter      svn_error_clear(err);
1256251881Speter
1257251881Speter      if (disk_kind != svn_node_none)
1258251881Speter        {
1259251881Speter          /* Nothing in the DB, but something on disk */
1260251881Speter          *obstruction_state = svn_wc_notify_state_obstructed;
1261251881Speter          return SVN_NO_ERROR;
1262251881Speter        }
1263251881Speter
1264251881Speter      err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
1265251881Speter                                 NULL, NULL, NULL, parent_depth, NULL, NULL,
1266251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1267251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1268251881Speter                                 NULL,
1269251881Speter                                 wc_ctx->db, svn_dirent_dirname(local_abspath,
1270251881Speter                                                                scratch_pool),
1271251881Speter                                 scratch_pool, scratch_pool);
1272251881Speter
1273251881Speter      if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
1274251881Speter        {
1275251881Speter          svn_error_clear(err);
1276251881Speter          /* No versioned parent; we can't add a node here */
1277251881Speter          *obstruction_state = svn_wc_notify_state_obstructed;
1278251881Speter          return SVN_NO_ERROR;
1279251881Speter        }
1280251881Speter      else
1281251881Speter        SVN_ERR(err);
1282251881Speter
1283251881Speter      if (db_kind != svn_node_dir
1284251881Speter          || (status != svn_wc__db_status_normal
1285251881Speter              && status != svn_wc__db_status_added))
1286251881Speter        {
1287251881Speter          /* The parent doesn't allow nodes to be added below it */
1288251881Speter          *obstruction_state = svn_wc_notify_state_obstructed;
1289251881Speter        }
1290251881Speter
1291251881Speter      return SVN_NO_ERROR;
1292251881Speter    }
1293251881Speter  else
1294251881Speter    SVN_ERR(err);
1295251881Speter
1296251881Speter  /* Check for obstructing working copies */
1297251881Speter  if (!no_wcroot_check
1298251881Speter      && db_kind == svn_node_dir
1299251881Speter      && status == svn_wc__db_status_normal)
1300251881Speter    {
1301251881Speter      svn_boolean_t is_root;
1302251881Speter      SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
1303251881Speter                                   scratch_pool));
1304251881Speter
1305251881Speter      if (is_root)
1306251881Speter        {
1307251881Speter          /* Callers should handle this as unversioned */
1308251881Speter          *obstruction_state = svn_wc_notify_state_obstructed;
1309251881Speter          return SVN_NO_ERROR;
1310251881Speter        }
1311251881Speter    }
1312251881Speter
1313251881Speter  if (kind)
1314251881Speter    SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
1315251881Speter
1316251881Speter  switch (status)
1317251881Speter    {
1318251881Speter      case svn_wc__db_status_deleted:
1319251881Speter        if (deleted)
1320251881Speter          *deleted = TRUE;
1321251881Speter        /* Fall through to svn_wc__db_status_not_present */
1322251881Speter      case svn_wc__db_status_not_present:
1323251881Speter        if (disk_kind != svn_node_none)
1324251881Speter          *obstruction_state = svn_wc_notify_state_obstructed;
1325251881Speter        break;
1326251881Speter
1327251881Speter      case svn_wc__db_status_excluded:
1328251881Speter      case svn_wc__db_status_server_excluded:
1329251881Speter        if (excluded)
1330251881Speter          *excluded = TRUE;
1331251881Speter        /* fall through */
1332251881Speter      case svn_wc__db_status_incomplete:
1333251881Speter        *obstruction_state = svn_wc_notify_state_missing;
1334251881Speter        break;
1335251881Speter
1336251881Speter      case svn_wc__db_status_added:
1337251881Speter      case svn_wc__db_status_normal:
1338251881Speter        if (disk_kind == svn_node_none)
1339251881Speter          *obstruction_state = svn_wc_notify_state_missing;
1340251881Speter        else
1341251881Speter          {
1342251881Speter            svn_node_kind_t expected_kind;
1343251881Speter
1344251881Speter            SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
1345251881Speter                                                 status, FALSE));
1346251881Speter
1347251881Speter            if (disk_kind != expected_kind)
1348251881Speter              *obstruction_state = svn_wc_notify_state_obstructed;
1349251881Speter          }
1350251881Speter        break;
1351251881Speter      default:
1352251881Speter        SVN_ERR_MALFUNCTION();
1353251881Speter    }
1354251881Speter
1355251881Speter  return SVN_NO_ERROR;
1356251881Speter}
1357251881Speter
1358251881Speter
1359251881Spetersvn_error_t *
1360251881Spetersvn_wc__node_was_moved_away(const char **moved_to_abspath,
1361251881Speter                            const char **op_root_abspath,
1362251881Speter                            svn_wc_context_t *wc_ctx,
1363251881Speter                            const char *local_abspath,
1364251881Speter                            apr_pool_t *result_pool,
1365251881Speter                            apr_pool_t *scratch_pool)
1366251881Speter{
1367251881Speter  svn_boolean_t is_deleted;
1368251881Speter
1369251881Speter  if (moved_to_abspath)
1370251881Speter    *moved_to_abspath = NULL;
1371251881Speter  if (op_root_abspath)
1372251881Speter    *op_root_abspath = NULL;
1373251881Speter
1374251881Speter  SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath,
1375251881Speter                                         scratch_pool));
1376251881Speter  if (is_deleted)
1377251881Speter    SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL,
1378251881Speter                                     op_root_abspath, wc_ctx->db,
1379251881Speter                                     local_abspath,
1380251881Speter                                     result_pool, scratch_pool));
1381251881Speter
1382251881Speter  return SVN_NO_ERROR;
1383251881Speter}
1384251881Speter
1385251881Speter
1386251881Spetersvn_error_t *
1387251881Spetersvn_wc__node_was_moved_here(const char **moved_from_abspath,
1388251881Speter                            const char **delete_op_root_abspath,
1389251881Speter                            svn_wc_context_t *wc_ctx,
1390251881Speter                            const char *local_abspath,
1391251881Speter                            apr_pool_t *result_pool,
1392251881Speter                            apr_pool_t *scratch_pool)
1393251881Speter{
1394251881Speter  svn_error_t *err;
1395251881Speter
1396251881Speter  if (moved_from_abspath)
1397251881Speter    *moved_from_abspath = NULL;
1398251881Speter  if (delete_op_root_abspath)
1399251881Speter    *delete_op_root_abspath = NULL;
1400251881Speter
1401251881Speter  err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL,
1402251881Speter                              delete_op_root_abspath,
1403251881Speter                              wc_ctx->db, local_abspath,
1404251881Speter                              result_pool, scratch_pool);
1405251881Speter
1406251881Speter  if (err)
1407251881Speter    {
1408251881Speter      /* Return error for not added nodes */
1409251881Speter      if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
1410251881Speter        return svn_error_trace(err);
1411251881Speter
1412251881Speter      /* Path not moved here */
1413251881Speter      svn_error_clear(err);
1414251881Speter      return SVN_NO_ERROR;
1415251881Speter    }
1416251881Speter
1417251881Speter  return SVN_NO_ERROR;
1418251881Speter}
1419