summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/status.c')
-rw-r--r--subversion/libsvn_wc/status.c1244
1 files changed, 756 insertions, 488 deletions
diff --git a/subversion/libsvn_wc/status.c b/subversion/libsvn_wc/status.c
index 51471d3..fa57b0a 100644
--- a/subversion/libsvn_wc/status.c
+++ b/subversion/libsvn_wc/status.c
@@ -53,6 +53,7 @@
#include "private/svn_wc_private.h"
#include "private/svn_fspath.h"
+#include "private/svn_editor.h"
@@ -241,70 +242,7 @@ struct file_baton
/** Code **/
-/* Fill in *INFO with the information it would contain if it were
- obtained from svn_wc__db_read_children_info. */
-static svn_error_t *
-read_info(const struct svn_wc__db_info_t **info,
- const char *local_abspath,
- svn_wc__db_t *db,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- struct svn_wc__db_info_t *mtb = apr_pcalloc(result_pool, sizeof(*mtb));
- const svn_checksum_t *checksum;
-
- SVN_ERR(svn_wc__db_read_info(&mtb->status, &mtb->kind,
- &mtb->revnum, &mtb->repos_relpath,
- &mtb->repos_root_url, &mtb->repos_uuid,
- &mtb->changed_rev, &mtb->changed_date,
- &mtb->changed_author, &mtb->depth,
- &checksum, NULL, NULL, NULL, NULL,
- NULL, &mtb->lock, &mtb->recorded_size,
- &mtb->recorded_mod_time, &mtb->changelist,
- &mtb->conflicted, &mtb->op_root,
- &mtb->had_props, &mtb->props_mod,
- &mtb->have_base, &mtb->have_more_work, NULL,
- db, local_abspath,
- result_pool, scratch_pool));
-
- SVN_ERR(svn_wc__db_wclocked(&mtb->locked, db, local_abspath, scratch_pool));
-
- /* Maybe we have to get some shadowed lock from BASE to make our test suite
- happy... (It might be completely unrelated, but...) */
- if (mtb->have_base
- && (mtb->status == svn_wc__db_status_added
- || mtb->status == svn_wc__db_status_deleted))
- {
- SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- &mtb->lock, NULL, NULL,
- db, local_abspath,
- result_pool, scratch_pool));
- }
-
- mtb->has_checksum = (checksum != NULL);
-
-#ifdef HAVE_SYMLINK
- if (mtb->kind == svn_wc__db_kind_file
- && (mtb->had_props || mtb->props_mod))
- {
- apr_hash_t *properties;
- if (mtb->props_mod)
- SVN_ERR(svn_wc__db_read_props(&properties, db, local_abspath,
- scratch_pool, scratch_pool));
- else
- SVN_ERR(svn_wc__db_read_pristine_props(&properties, db, local_abspath,
- scratch_pool, scratch_pool));
-
- mtb->special = (NULL != apr_hash_get(properties, SVN_PROP_SPECIAL,
- APR_HASH_KEY_STRING));
- }
-#endif
- *info = mtb;
-
- return SVN_NO_ERROR;
-}
/* Return *REPOS_RELPATH and *REPOS_ROOT_URL for LOCAL_ABSPATH using
information in INFO if available, falling back on
@@ -325,9 +263,9 @@ get_repos_root_url_relpath(const char **repos_relpath,
{
if (info->repos_relpath && info->repos_root_url)
{
- *repos_relpath = info->repos_relpath;
- *repos_root_url = info->repos_root_url;
- *repos_uuid = info->repos_uuid;
+ *repos_relpath = apr_pstrdup(result_pool, info->repos_relpath);
+ *repos_root_url = apr_pstrdup(result_pool, info->repos_root_url);
+ *repos_uuid = apr_pstrdup(result_pool, info->repos_uuid);
}
else if (parent_repos_relpath && parent_repos_root_url)
{
@@ -335,8 +273,8 @@ get_repos_root_url_relpath(const char **repos_relpath,
svn_dirent_basename(local_abspath,
NULL),
result_pool);
- *repos_root_url = parent_repos_root_url;
- *repos_uuid = parent_repos_uuid;
+ *repos_root_url = apr_pstrdup(result_pool, parent_repos_root_url);
+ *repos_uuid = apr_pstrdup(result_pool, parent_repos_uuid);
}
else if (info->status == svn_wc__db_status_added)
{
@@ -346,13 +284,42 @@ get_repos_root_url_relpath(const char **repos_relpath,
db, local_abspath,
result_pool, scratch_pool));
}
- else if (info->have_base)
+ else if (info->status == svn_wc__db_status_deleted
+ && !info->have_more_work
+ && info->have_base)
{
SVN_ERR(svn_wc__db_scan_base_repos(repos_relpath, repos_root_url,
repos_uuid,
db, local_abspath,
result_pool, scratch_pool));
}
+ else if (info->status == svn_wc__db_status_deleted)
+ {
+ const char *work_del_abspath;
+ const char *add_abspath;
+
+ /* Handles working DELETE and the special case where there is just
+ svn_wc__db_status_not_present in WORKING */
+
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL, &work_del_abspath, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ /* The parent of what has been deleted must be added */
+ add_abspath = svn_dirent_dirname(work_del_abspath, scratch_pool);
+
+ SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, repos_relpath,
+ repos_root_url, repos_uuid, NULL,
+ NULL, NULL, NULL,
+ db, add_abspath,
+ result_pool, scratch_pool));
+
+ *repos_relpath = svn_relpath_join(*repos_relpath,
+ svn_dirent_skip_ancestor(
+ add_abspath,
+ local_abspath),
+ result_pool);
+ }
else
{
*repos_relpath = NULL;
@@ -372,7 +339,7 @@ internal_status(svn_wc_status3_t **status,
/* Fill in *STATUS for LOCAL_ABSPATH, using DB. Allocate *STATUS in
RESULT_POOL and use SCRATCH_POOL for temporary allocations.
- PARENT_REPOS_ROOT_URL and PARENT_REPOS_RELPATH are the the repository root
+ PARENT_REPOS_ROOT_URL and PARENT_REPOS_RELPATH are the repository root
and repository relative path of the parent of LOCAL_ABSPATH or NULL if
LOCAL_ABSPATH doesn't have a versioned parent directory.
@@ -406,10 +373,7 @@ assemble_status(svn_wc_status3_t **status,
svn_boolean_t switched_p = FALSE;
svn_boolean_t copied = FALSE;
svn_boolean_t conflicted;
- svn_error_t *err;
- const char *repos_relpath;
- const char *repos_root_url;
- const char *repos_uuid;
+ const char *moved_from_abspath = NULL;
svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file))
? dirent->filesize
: SVN_INVALID_FILESIZE;
@@ -421,7 +385,8 @@ assemble_status(svn_wc_status3_t **status,
if (!info)
- SVN_ERR(read_info(&info, local_abspath, db, result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_single_info(&info, db, local_abspath,
+ result_pool, scratch_pool));
if (!info->repos_relpath || !parent_repos_relpath)
switched_p = FALSE;
@@ -430,58 +395,48 @@ assemble_status(svn_wc_status3_t **status,
/* A node is switched if it doesn't have the implied repos_relpath */
const char *name = svn_relpath_skip_ancestor(parent_repos_relpath,
info->repos_relpath);
- switched_p = !name || (strcmp(name, svn_dirent_basename(local_abspath, NULL)) != 0);
+ switched_p = !name || (strcmp(name,
+ svn_dirent_basename(local_abspath, NULL))
+ != 0);
}
- /* Examine whether our target is missing or obstructed or missing.
-
- While we are not completely in single-db mode yet, data about
- obstructed or missing nodes might be incomplete here. This is
- reported by svn_wc_db_status_obstructed_XXXX. In single-db
- mode these obstructions are no longer reported and we have
- to detect obstructions by looking at the on disk status in DIRENT.
- */
- if (info->kind == svn_wc__db_kind_dir)
+ if (info->status == svn_wc__db_status_incomplete || info->incomplete)
{
- if (info->status == svn_wc__db_status_incomplete || info->incomplete)
- {
- /* Highest precedence. */
- node_status = svn_wc_status_incomplete;
- }
- else if (info->status == svn_wc__db_status_deleted)
- {
- node_status = svn_wc_status_deleted;
+ /* Highest precedence. */
+ node_status = svn_wc_status_incomplete;
+ }
+ else if (info->status == svn_wc__db_status_deleted)
+ {
+ node_status = svn_wc_status_deleted;
- if (!info->have_base)
- copied = TRUE;
- else
- SVN_ERR(svn_wc__internal_node_get_schedule(NULL, &copied,
- db, local_abspath,
- scratch_pool));
- }
- else if (!dirent || dirent->kind != svn_node_dir)
+ if (!info->have_base || info->have_more_work || info->copied)
+ copied = TRUE;
+ else if (!info->have_more_work && info->have_base)
+ copied = FALSE;
+ else
{
- /* A present or added directory should be on disk, so it is
- reported missing or obstructed. */
- if (!dirent || dirent->kind == svn_node_none)
- node_status = svn_wc_status_missing;
- else
- node_status = svn_wc_status_obstructed;
+ const char *work_del_abspath;
+
+ /* Find out details of our deletion. */
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
+ &work_del_abspath, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ if (work_del_abspath)
+ copied = TRUE; /* Working deletion */
}
}
else
{
- if (info->status == svn_wc__db_status_deleted)
- {
- node_status = svn_wc_status_deleted;
+ /* Examine whether our target is missing or obstructed. To detect
+ * obstructions, we have to look at the on-disk status in DIRENT. */
+ svn_node_kind_t expected_kind = (info->kind == svn_node_dir)
+ ? svn_node_dir
+ : svn_node_file;
- SVN_ERR(svn_wc__internal_node_get_schedule(NULL, &copied,
- db, local_abspath,
- scratch_pool));
- }
- else if (!dirent || dirent->kind != svn_node_file)
+ if (!dirent || dirent->kind != expected_kind)
{
- /* A present or added file should be on disk, so it is
+ /* A present or added node should be on disk, so it is
reported missing or obstructed. */
if (!dirent || dirent->kind == svn_node_none)
node_status = svn_wc_status_missing;
@@ -504,7 +459,7 @@ assemble_status(svn_wc_status3_t **status,
If it was changed, then the subdir is incomplete or missing/obstructed.
*/
- if (info->kind != svn_wc__db_kind_dir
+ if (info->kind != svn_node_dir
&& node_status == svn_wc_status_normal)
{
svn_boolean_t text_modified_p = FALSE;
@@ -516,8 +471,8 @@ assemble_status(svn_wc_status3_t **status,
precedence over M. */
/* If the entry is a file, check for textual modifications */
- if ((info->kind == svn_wc__db_kind_file
- || info->kind == svn_wc__db_kind_symlink)
+ if ((info->kind == svn_node_file
+ || info->kind == svn_node_symlink)
#ifdef HAVE_SYMLINK
&& (info->special == (dirent && dirent->special))
#endif /* HAVE_SYMLINK */
@@ -533,12 +488,13 @@ assemble_status(svn_wc_status3_t **status,
else if (ignore_text_mods
||(dirent
&& info->recorded_size != SVN_INVALID_FILESIZE
- && info->recorded_mod_time != 0
+ && info->recorded_time != 0
&& info->recorded_size == dirent->filesize
- && info->recorded_mod_time == dirent->mtime))
+ && info->recorded_time == dirent->mtime))
text_modified_p = FALSE;
else
{
+ svn_error_t *err;
err = svn_wc__internal_file_modified_p(&text_modified_p,
db, local_abspath,
FALSE, scratch_pool);
@@ -590,31 +546,59 @@ assemble_status(svn_wc_status3_t **status,
override a C text status.*/
if (info->status == svn_wc__db_status_added)
{
+ copied = info->copied;
if (!info->op_root)
- copied = TRUE; /* And keep status normal */
- else if (info->kind == svn_wc__db_kind_file
- && !info->have_base && !info->have_more_work)
+ { /* Keep status normal */ }
+ else if (!info->have_base && !info->have_more_work)
{
/* Simple addition or copy, no replacement */
node_status = svn_wc_status_added;
- /* If an added node has a pristine file, it was copied */
- copied = info->has_checksum;
}
else
{
- svn_wc_schedule_t schedule;
- SVN_ERR(svn_wc__internal_node_get_schedule(&schedule, &copied,
- db, local_abspath,
- scratch_pool));
-
- if (schedule == svn_wc_schedule_add)
+ svn_wc__db_status_t below_working;
+ svn_boolean_t have_base, have_work;
+
+ SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
+ &below_working,
+ db, local_abspath,
+ scratch_pool));
+
+ /* If the node is not present or deleted (read: not present
+ in working), then the node is not a replacement */
+ if (below_working != svn_wc__db_status_not_present
+ && below_working != svn_wc__db_status_deleted)
+ {
+ node_status = svn_wc_status_replaced;
+ }
+ else
node_status = svn_wc_status_added;
- else if (schedule == svn_wc_schedule_replace)
- node_status = svn_wc_status_replaced;
+ }
+
+ /* Get moved-from info (only for potential op-roots of a move). */
+ if (info->moved_here && info->op_root)
+ {
+ svn_error_t *err;
+ err = svn_wc__db_scan_moved(&moved_from_abspath, NULL, NULL, NULL,
+ db, local_abspath,
+ result_pool, scratch_pool);
+
+ if (err)
+ {
+ if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+ return svn_error_trace(err);
+
+ svn_error_clear(err);
+ /* We are no longer moved... So most likely we are somehow
+ changing the db for things like resolving conflicts. */
+
+ moved_from_abspath = NULL;
+ }
}
}
}
+
if (node_status == svn_wc_status_normal)
node_status = text_status;
@@ -640,28 +624,20 @@ assemble_status(svn_wc_status3_t **status,
return SVN_NO_ERROR;
}
- SVN_ERR(get_repos_root_url_relpath(&repos_relpath, &repos_root_url,
- &repos_uuid, info,
- parent_repos_relpath,
- parent_repos_root_url,
- parent_repos_uuid,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
/* 6. Build and return a status structure. */
stat = apr_pcalloc(result_pool, sizeof(**status));
switch (info->kind)
{
- case svn_wc__db_kind_dir:
+ case svn_node_dir:
stat->kind = svn_node_dir;
break;
- case svn_wc__db_kind_file:
- case svn_wc__db_kind_symlink:
+ case svn_node_file:
+ case svn_node_symlink:
stat->kind = svn_node_file;
break;
- case svn_wc__db_kind_unknown:
+ case svn_node_unknown:
default:
stat->kind = svn_node_unknown;
}
@@ -678,7 +654,8 @@ assemble_status(svn_wc_status3_t **status,
stat->repos_lock = repos_lock;
stat->revision = info->revnum;
stat->changed_rev = info->changed_rev;
- stat->changed_author = info->changed_author;
+ if (info->changed_author)
+ stat->changed_author = apr_pstrdup(result_pool, info->changed_author);
stat->changed_date = info->changed_date;
stat->ood_kind = svn_node_none;
@@ -686,10 +663,19 @@ assemble_status(svn_wc_status3_t **status,
stat->ood_changed_date = 0;
stat->ood_changed_author = NULL;
+ SVN_ERR(get_repos_root_url_relpath(&stat->repos_relpath,
+ &stat->repos_root_url,
+ &stat->repos_uuid, info,
+ parent_repos_relpath,
+ parent_repos_root_url,
+ parent_repos_uuid,
+ db, local_abspath,
+ result_pool, scratch_pool));
+
if (info->lock)
{
- svn_lock_t *lck = apr_pcalloc(result_pool, sizeof(*lck));
- lck->path = repos_relpath;
+ svn_lock_t *lck = svn_lock_create(result_pool);
+ lck->path = stat->repos_relpath;
lck->token = info->lock->token;
lck->owner = info->lock->owner;
lck->comment = info->lock->comment;
@@ -702,10 +688,17 @@ assemble_status(svn_wc_status3_t **status,
stat->locked = info->locked;
stat->conflicted = conflicted;
stat->versioned = TRUE;
- stat->changelist = info->changelist;
- stat->repos_root_url = repos_root_url;
- stat->repos_relpath = repos_relpath;
- stat->repos_uuid = repos_uuid;
+ if (info->changelist)
+ stat->changelist = apr_pstrdup(result_pool, info->changelist);
+
+ stat->moved_from_abspath = moved_from_abspath;
+
+ /* ### TODO: Handle multiple moved_to values properly */
+ if (info->moved_to)
+ stat->moved_to_abspath = apr_pstrdup(result_pool,
+ info->moved_to->moved_to_abspath);
+
+ stat->file_external = info->file_external;
*status = stat;
@@ -817,10 +810,9 @@ send_status_structure(const struct walk_status_baton *wb,
{
/* repos_lock still uses the deprecated filesystem absolute path
format */
- repos_lock = apr_hash_get(wb->repos_locks,
- svn_fspath__join("/", repos_relpath,
- scratch_pool),
- APR_HASH_KEY_STRING);
+ repos_lock = svn_hash_gets(wb->repos_locks,
+ svn_fspath__join("/", repos_relpath,
+ scratch_pool));
}
}
@@ -838,9 +830,10 @@ send_status_structure(const struct walk_status_baton *wb,
}
-/* Store in PATTERNS a list of all svn:ignore properties from
- the working copy directory, including the default ignores
- passed in as IGNORES.
+/* Store in *PATTERNS a list of ignores collected from svn:ignore properties
+ on LOCAL_ABSPATH and svn:global-ignores on LOCAL_ABSPATH and its
+ repository ancestors (as cached in the working copy), including the default
+ ignores passed in as IGNORES.
Upon return, *PATTERNS will contain zero or more (const char *)
patterns from the value of the SVN_PROP_IGNORE property set on
@@ -849,7 +842,7 @@ send_status_structure(const struct walk_status_baton *wb,
IGNORES is a list of patterns to include; typically this will
be the default ignores as, for example, specified in a config file.
- LOCAL_ABSPATH and DB control how to access the ignore information.
+ DB, LOCAL_ABSPATH is used to access the working copy.
Allocate results in RESULT_POOL, temporary stuffs in SCRATCH_POOL.
@@ -864,7 +857,9 @@ collect_ignore_patterns(apr_array_header_t **patterns,
apr_pool_t *scratch_pool)
{
int i;
- const svn_string_t *value;
+ apr_hash_t *props;
+ apr_array_header_t *inherited_props;
+ svn_error_t *err;
/* ### assert we are passed a directory? */
@@ -878,12 +873,47 @@ collect_ignore_patterns(apr_array_header_t **patterns,
ignore);
}
- /* Then add any svn:ignore globs to the PATTERNS array. */
- SVN_ERR(svn_wc__internal_propget(&value, db, local_abspath, SVN_PROP_IGNORE,
- scratch_pool, scratch_pool));
- if (value != NULL)
- svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
- result_pool);
+ err = svn_wc__db_read_inherited_props(&inherited_props, &props,
+ db, local_abspath,
+ SVN_PROP_INHERITABLE_IGNORES,
+ scratch_pool, scratch_pool);
+
+ if (err)
+ {
+ if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+ return svn_error_trace(err);
+
+ svn_error_clear(err);
+ return SVN_NO_ERROR;
+ }
+
+ if (props)
+ {
+ const svn_string_t *value;
+
+ value = svn_hash_gets(props, SVN_PROP_IGNORE);
+ if (value)
+ svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
+ result_pool);
+
+ value = svn_hash_gets(props, SVN_PROP_INHERITABLE_IGNORES);
+ if (value)
+ svn_cstring_split_append(*patterns, value->data, "\n\r", FALSE,
+ result_pool);
+ }
+
+ for (i = 0; i < inherited_props->nelts; i++)
+ {
+ svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
+ inherited_props, i, svn_prop_inherited_item_t *);
+ const svn_string_t *value;
+
+ value = svn_hash_gets(elt->prop_hash, SVN_PROP_INHERITABLE_IGNORES);
+
+ if (value)
+ svn_cstring_split_append(*patterns, value->data,
+ "\n\r", FALSE, result_pool);
+ }
return SVN_NO_ERROR;
}
@@ -901,7 +931,7 @@ is_external_path(apr_hash_t *externals,
apr_hash_index_t *hi;
/* First try: does the path exist as a key in the hash? */
- if (apr_hash_get(externals, local_abspath, APR_HASH_KEY_STRING))
+ if (svn_hash_gets(externals, local_abspath))
return TRUE;
/* Failing that, we need to check if any external is a child of
@@ -928,13 +958,12 @@ is_external_path(apr_hash_t *externals,
requested. PATH_KIND is the node kind of NAME as determined by the
caller. PATH_SPECIAL is the special status of the path, also determined
by the caller.
- PATTERNS points to a list of filename patterns which are marked as
- ignored. None of these parameter may be NULL. EXTERNALS is a hash
- of known externals definitions for this status run.
+ PATTERNS points to a list of filename patterns which are marked as ignored.
+ None of these parameter may be NULL.
- If NO_IGNORE is non-zero, the item will be added regardless of
+ If NO_IGNORE is TRUE, the item will be added regardless of
whether it is ignored; otherwise we will only add the item if it
- does not match any of the patterns in PATTERNS.
+ does not match any of the patterns in PATTERN or INHERITED_IGNORES.
Allocate everything in POOL.
*/
@@ -952,14 +981,13 @@ send_unversioned_item(const struct walk_status_baton *wb,
svn_boolean_t is_ignored;
svn_boolean_t is_external;
svn_wc_status3_t *status;
+ const char *base_name = svn_dirent_basename(local_abspath, NULL);
- is_ignored = svn_wc_match_ignore_list(
- svn_dirent_basename(local_abspath, NULL),
- patterns, scratch_pool);
-
+ is_ignored = svn_wc_match_ignore_list(base_name, patterns, scratch_pool);
SVN_ERR(assemble_unversioned(&status,
wb->db, local_abspath,
- dirent, tree_conflicted, is_ignored,
+ dirent, tree_conflicted,
+ is_ignored,
scratch_pool, scratch_pool));
is_external = is_external_path(wb->externals, local_abspath, scratch_pool);
@@ -974,36 +1002,198 @@ send_unversioned_item(const struct walk_status_baton *wb,
/* If we aren't ignoring it, or if it's an externals path, pass this
entry to the status func. */
- if (no_ignore || (! is_ignored) || is_external)
+ if (no_ignore
+ || !is_ignored
+ || is_external)
return svn_error_trace((*status_func)(status_baton, local_abspath,
status, scratch_pool));
return SVN_NO_ERROR;
}
-/* Send svn_wc_status3_t * structures for the directory LOCAL_ABSPATH and
- for all its entries through STATUS_FUNC/STATUS_BATON, or, if SELECTED
- is non-NULL, only for that directory entry.
+static svn_error_t *
+get_dir_status(const struct walk_status_baton *wb,
+ const char *local_abspath,
+ svn_boolean_t skip_this_dir,
+ const char *parent_repos_root_url,
+ const char *parent_repos_relpath,
+ const char *parent_repos_uuid,
+ const struct svn_wc__db_info_t *dir_info,
+ const svn_io_dirent2_t *dirent,
+ const apr_array_header_t *ignore_patterns,
+ svn_depth_t depth,
+ svn_boolean_t get_all,
+ svn_boolean_t no_ignore,
+ svn_wc_status_func4_t status_func,
+ void *status_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool);
- PARENT_ENTRY is the entry for the parent of the directory or NULL
- if LOCAL_ABSPATH is a working copy root.
+/* Send out a status structure according to the information gathered on one
+ * child node. (Basically this function is the guts of the loop in
+ * get_dir_status() and of get_child_status().)
+ *
+ * Send a status structure of LOCAL_ABSPATH. PARENT_ABSPATH must be the
+ * dirname of LOCAL_ABSPATH.
+ *
+ * INFO should reflect the information on LOCAL_ABSPATH; LOCAL_ABSPATH must
+ * be an unversioned file or dir, or a versioned file. For versioned
+ * directories use get_dir_status() instead.
+ *
+ * INFO may be NULL for an unversioned node. If such node has a tree conflict,
+ * UNVERSIONED_TREE_CONFLICTED may be set to TRUE. If INFO is non-NULL,
+ * UNVERSIONED_TREE_CONFLICTED is ignored.
+ *
+ * DIRENT should reflect LOCAL_ABSPATH's dirent information.
+ *
+ * DIR_REPOS_* should reflect LOCAL_ABSPATH's parent URL, i.e. LOCAL_ABSPATH's
+ * URL treated with svn_uri_dirname(). ### TODO verify this (externals)
+ *
+ * If *COLLECTED_IGNORE_PATTERNS is NULL and ignore patterns are needed in this
+ * call, then *COLLECTED_IGNORE_PATTERNS will be set to an apr_array_header_t*
+ * containing all ignore patterns, as returned by collect_ignore_patterns() on
+ * PARENT_ABSPATH and IGNORE_PATTERNS. If *COLLECTED_IGNORE_PATTERNS is passed
+ * non-NULL, it is assumed it already holds those results.
+ * This speeds up repeated calls with the same PARENT_ABSPATH.
+ *
+ * *COLLECTED_IGNORE_PATTERNS will be allocated in RESULT_POOL. All other
+ * allocations are made in SCRATCH_POOL.
+ *
+ * The remaining parameters correspond to get_dir_status(). */
+static svn_error_t *
+one_child_status(const struct walk_status_baton *wb,
+ const char *local_abspath,
+ const char *parent_abspath,
+ const struct svn_wc__db_info_t *info,
+ const svn_io_dirent2_t *dirent,
+ const char *dir_repos_root_url,
+ const char *dir_repos_relpath,
+ const char *dir_repos_uuid,
+ svn_boolean_t unversioned_tree_conflicted,
+ apr_array_header_t **collected_ignore_patterns,
+ const apr_array_header_t *ignore_patterns,
+ svn_depth_t depth,
+ svn_boolean_t get_all,
+ svn_boolean_t no_ignore,
+ svn_wc_status_func4_t status_func,
+ void *status_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t conflicted = info ? info->conflicted
+ : unversioned_tree_conflicted;
+
+ if (info
+ && info->status != svn_wc__db_status_not_present
+ && info->status != svn_wc__db_status_excluded
+ && info->status != svn_wc__db_status_server_excluded
+ && !(info->kind == svn_node_unknown
+ && info->status == svn_wc__db_status_normal))
+ {
+ if (depth == svn_depth_files
+ && info->kind == svn_node_dir)
+ {
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(send_status_structure(wb, local_abspath,
+ dir_repos_root_url,
+ dir_repos_relpath,
+ dir_repos_uuid,
+ info, dirent, get_all,
+ status_func, status_baton,
+ scratch_pool));
+
+ /* Descend in subdirectories. */
+ if (depth == svn_depth_infinity
+ && info->kind == svn_node_dir)
+ {
+ SVN_ERR(get_dir_status(wb, local_abspath, TRUE,
+ dir_repos_root_url, dir_repos_relpath,
+ dir_repos_uuid, info,
+ dirent, ignore_patterns,
+ svn_depth_infinity, get_all,
+ no_ignore,
+ status_func, status_baton,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+ }
+
+ /* If conflicted, fall right through to unversioned.
+ * With depth_files, show all conflicts, even if their report is only
+ * about directories. A tree conflict may actually report two different
+ * kinds, so it's not so easy to define what depth=files means. We could go
+ * look up the kinds in the conflict ... just show all. */
+ if (! conflicted)
+ {
+ /* Selected node, but not found */
+ if (dirent == NULL)
+ return SVN_NO_ERROR;
+
+ if (depth == svn_depth_files && dirent->kind == svn_node_dir)
+ return SVN_NO_ERROR;
+
+ if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, NULL),
+ scratch_pool))
+ return SVN_NO_ERROR;
+ }
+
+ /* The node exists on disk but there is no versioned information about it,
+ * or it doesn't exist but is a tree conflicted path or should be
+ * reported not-present. */
+
+ /* Why pass ignore patterns on a tree conflicted node, even if it should
+ * always show up in clients' status reports anyway? Because the calling
+ * client decides whether to ignore, and thus this flag needs to be
+ * determined. For example, in 'svn status', plain unversioned nodes show
+ * as '? C', where ignored ones show as 'I C'. */
+
+ if (ignore_patterns && ! *collected_ignore_patterns)
+ SVN_ERR(collect_ignore_patterns(collected_ignore_patterns,
+ wb->db, parent_abspath, ignore_patterns,
+ result_pool, scratch_pool));
+
+ SVN_ERR(send_unversioned_item(wb,
+ local_abspath,
+ dirent,
+ conflicted,
+ *collected_ignore_patterns,
+ no_ignore,
+ status_func, status_baton,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Send svn_wc_status3_t * structures for the directory LOCAL_ABSPATH and
+ for all its child nodes (according to DEPTH) through STATUS_FUNC /
+ STATUS_BATON.
If SKIP_THIS_DIR is TRUE, the directory's own status will not be reported.
- However, upon recursing, all subdirs *will* be reported, regardless of this
+ All subdirs reached by recursion will be reported regardless of this
parameter's value.
- DIRENT is LOCAL_ABSPATH's own dirent and is only needed if it is reported,
- so if SKIP_THIS_DIR or SELECTED is not-NULL DIRENT can be left NULL.
+ PARENT_REPOS_* parameters can be set to refer to LOCAL_ABSPATH's parent's
+ URL, i.e. the URL the WC reflects at the dirname of LOCAL_ABSPATH, to avoid
+ retrieving them again. Otherwise they must be NULL.
DIR_INFO can be set to the information of LOCAL_ABSPATH, to avoid retrieving
- it again.
+ it again. Otherwise it must be NULL.
+
+ DIRENT is LOCAL_ABSPATH's own dirent and is only needed if it is reported,
+ so if SKIP_THIS_DIR is TRUE, DIRENT can be left NULL.
Other arguments are the same as those passed to
svn_wc_get_status_editor5(). */
static svn_error_t *
get_dir_status(const struct walk_status_baton *wb,
const char *local_abspath,
- const char *selected,
svn_boolean_t skip_this_dir,
const char *parent_repos_root_url,
const char *parent_repos_relpath,
@@ -1024,9 +1214,9 @@ get_dir_status(const struct walk_status_baton *wb,
const char *dir_repos_relpath;
const char *dir_repos_uuid;
apr_hash_t *dirents, *nodes, *conflicts, *all_children;
- apr_array_header_t *patterns = NULL;
apr_array_header_t *sorted_children;
- apr_pool_t *iterpool, *subpool = svn_pool_create(scratch_pool);
+ apr_array_header_t *collected_ignore_patterns = NULL;
+ apr_pool_t *iterpool;
svn_error_t *err;
int i;
@@ -1036,83 +1226,78 @@ get_dir_status(const struct walk_status_baton *wb,
if (depth == svn_depth_unknown)
depth = svn_depth_infinity;
- iterpool = svn_pool_create(subpool);
+ iterpool = svn_pool_create(scratch_pool);
- err = svn_io_get_dirents3(&dirents, local_abspath, FALSE, subpool, iterpool);
+ err = svn_io_get_dirents3(&dirents, local_abspath, FALSE, scratch_pool,
+ iterpool);
if (err
&& (APR_STATUS_IS_ENOENT(err->apr_err)
|| SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
{
svn_error_clear(err);
- dirents = apr_hash_make(subpool);
+ dirents = apr_hash_make(scratch_pool);
}
else
SVN_ERR(err);
if (!dir_info)
- SVN_ERR(read_info(&dir_info, local_abspath, wb->db,
- subpool, iterpool));
+ SVN_ERR(svn_wc__db_read_single_info(&dir_info, wb->db, local_abspath,
+ scratch_pool, iterpool));
SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
&dir_repos_uuid, dir_info,
parent_repos_relpath,
parent_repos_root_url, parent_repos_uuid,
wb->db, local_abspath,
- subpool, iterpool));
- if (selected == NULL)
- {
- /* Create a hash containing all children. The source hashes
- don't all map the same types, but only the keys of the result
- hash are subsequently used. */
- SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
- wb->db, local_abspath,
- subpool, iterpool));
+ scratch_pool, iterpool));
- all_children = apr_hash_overlay(subpool, nodes, dirents);
- if (apr_hash_count(conflicts) > 0)
- all_children = apr_hash_overlay(subpool, conflicts, all_children);
- }
- else
- {
- const struct svn_wc__db_info_t *info;
- const char *selected_abspath = svn_dirent_join(local_abspath, selected,
- iterpool);
- /* Create a hash containing just selected */
- all_children = apr_hash_make(subpool);
- nodes = apr_hash_make(subpool);
- conflicts = apr_hash_make(subpool);
+ /* Create a hash containing all children. The source hashes
+ don't all map the same types, but only the keys of the result
+ hash are subsequently used. */
+ SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
+ wb->db, local_abspath,
+ scratch_pool, iterpool));
- err = read_info(&info, selected_abspath, wb->db, subpool, iterpool);
+ all_children = apr_hash_overlay(scratch_pool, nodes, dirents);
+ if (apr_hash_count(conflicts) > 0)
+ all_children = apr_hash_overlay(scratch_pool, conflicts, all_children);
- if (err)
- {
- if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
- return svn_error_trace(err);
- svn_error_clear(err);
- /* The node is neither a tree conflict nor a versioned node */
- }
- else
+ /* Handle "this-dir" first. */
+ if (! skip_this_dir)
+ {
+ /* This code is not conditional on HAVE_SYMLINK as some systems that do
+ not allow creating symlinks (!HAVE_SYMLINK) can still encounter
+ symlinks (or in case of Windows also 'Junctions') created by other
+ methods.
+
+ Without this block a working copy in the root of a junction is
+ reported as an obstruction, because the junction itself is reported as
+ special.
+
+ Systems that have no symlink support at all, would always see
+ dirent->special as FALSE, so even there enabling this code shouldn't
+ produce problems.
+ */
+ if (dirent->special)
{
- if (!info->conflicted
- || info->status != svn_wc__db_status_normal
- || info->kind != svn_wc__db_kind_unknown)
- {
- /* The node is a normal versioned node */
- apr_hash_set(nodes, selected, APR_HASH_KEY_STRING, info);
- }
-
- /* Drop it in the list of possible conflicts */
- if (info->conflicted)
- apr_hash_set(conflicts, selected, APR_HASH_KEY_STRING, info);
+ svn_io_dirent2_t *this_dirent = svn_io_dirent2_dup(dirent, iterpool);
+
+ /* We're being pointed to "this-dir" via a symlink.
+ * Get the real node kind and pretend the path is not a symlink.
+ * This prevents send_status_structure() from treating this-dir
+ * as a directory obstructed by a file. */
+ SVN_ERR(svn_io_check_resolved_path(local_abspath,
+ &this_dirent->kind, iterpool));
+ this_dirent->special = FALSE;
+ SVN_ERR(send_status_structure(wb, local_abspath,
+ parent_repos_root_url,
+ parent_repos_relpath,
+ parent_repos_uuid,
+ dir_info, this_dirent, get_all,
+ status_func, status_baton,
+ iterpool));
}
-
- apr_hash_set(all_children, selected, APR_HASH_KEY_STRING, selected);
- }
-
- if (!selected)
- {
- /* Handle "this-dir" first. */
- if (! skip_this_dir)
+ else
SVN_ERR(send_status_structure(wb, local_abspath,
parent_repos_root_url,
parent_repos_relpath,
@@ -1120,24 +1305,24 @@ get_dir_status(const struct walk_status_baton *wb,
dir_info, dirent, get_all,
status_func, status_baton,
iterpool));
-
- /* If the requested depth is empty, we only need status on this-dir. */
- if (depth == svn_depth_empty)
- return SVN_NO_ERROR;
}
+ /* If the requested depth is empty, we only need status on this-dir. */
+ if (depth == svn_depth_empty)
+ return SVN_NO_ERROR;
+
/* Walk all the children of this directory. */
sorted_children = svn_sort__hash(all_children,
svn_sort_compare_items_lexically,
- subpool);
+ scratch_pool);
for (i = 0; i < sorted_children->nelts; i++)
{
const void *key;
apr_ssize_t klen;
- const char *node_abspath;
- svn_io_dirent2_t *dirent_p;
- const struct svn_wc__db_info_t *info;
svn_sort__item_t item;
+ const char *child_abspath;
+ svn_io_dirent2_t *child_dirent;
+ const struct svn_wc__db_info_t *child_info;
svn_pool_clear(iterpool);
@@ -1145,97 +1330,113 @@ get_dir_status(const struct walk_status_baton *wb,
key = item.key;
klen = item.klen;
- node_abspath = svn_dirent_join(local_abspath, key, iterpool);
- dirent_p = apr_hash_get(dirents, key, klen);
-
- info = apr_hash_get(nodes, key, klen);
- if (info)
- {
- if (info->status != svn_wc__db_status_not_present
- && info->status != svn_wc__db_status_excluded
- && info->status != svn_wc__db_status_server_excluded)
- {
- if (depth == svn_depth_files
- && info->kind == svn_wc__db_kind_dir)
- {
- continue;
- }
-
- SVN_ERR(send_status_structure(wb, node_abspath,
- dir_repos_root_url,
- dir_repos_relpath,
- dir_repos_uuid,
- info, dirent_p, get_all,
- status_func, status_baton,
- iterpool));
-
- /* Descend in subdirectories. */
- if (depth == svn_depth_infinity
- && info->kind == svn_wc__db_kind_dir)
- {
- SVN_ERR(get_dir_status(wb, node_abspath, NULL, TRUE,
- dir_repos_root_url, dir_repos_relpath,
- dir_repos_uuid, info,
- dirent_p, ignore_patterns,
- svn_depth_infinity, get_all,
- no_ignore,
- status_func, status_baton,
- cancel_func, cancel_baton,
- iterpool));
- }
-
- continue;
- }
- }
-
- if (apr_hash_get(conflicts, key, klen))
- {
- /* Tree conflict */
-
- if (ignore_patterns && ! patterns)
- SVN_ERR(collect_ignore_patterns(&patterns, wb->db, local_abspath,
- ignore_patterns, subpool,
- iterpool));
-
- SVN_ERR(send_unversioned_item(wb,
- node_abspath,
- dirent_p, TRUE,
- patterns,
- no_ignore,
- status_func,
- status_baton,
- iterpool));
+ child_abspath = svn_dirent_join(local_abspath, key, iterpool);
+ child_dirent = apr_hash_get(dirents, key, klen);
+ child_info = apr_hash_get(nodes, key, klen);
+
+ SVN_ERR(one_child_status(wb,
+ child_abspath,
+ local_abspath,
+ child_info,
+ child_dirent,
+ dir_repos_root_url,
+ dir_repos_relpath,
+ dir_repos_uuid,
+ apr_hash_get(conflicts, key, klen) != NULL,
+ &collected_ignore_patterns,
+ ignore_patterns,
+ depth,
+ get_all,
+ no_ignore,
+ status_func,
+ status_baton,
+ cancel_func,
+ cancel_baton,
+ scratch_pool,
+ iterpool));
+ }
- continue;
- }
+ /* Destroy our subpools. */
+ svn_pool_destroy(iterpool);
- /* Unversioned node */
- if (dirent_p == NULL)
- continue; /* Selected node, but not found */
+ return SVN_NO_ERROR;
+}
- if (depth == svn_depth_files && dirent_p->kind == svn_node_dir)
- continue;
+/* Send an svn_wc_status3_t * structure for the versioned file, or for the
+ * unversioned file or directory, LOCAL_ABSPATH, which is not ignored (an
+ * explicit target). Does not recurse.
+ *
+ * INFO should reflect LOCAL_ABSPATH's information, but should be NULL for
+ * unversioned nodes. An unversioned and tree-conflicted node however should
+ * pass a non-NULL INFO as returned by read_info() (INFO->CONFLICTED = TRUE).
+ *
+ * DIRENT should reflect LOCAL_ABSPATH.
+ *
+ * All allocations made in SCRATCH_POOL.
+ *
+ * The remaining parameters correspond to get_dir_status(). */
+static svn_error_t *
+get_child_status(const struct walk_status_baton *wb,
+ const char *local_abspath,
+ const struct svn_wc__db_info_t *info,
+ const svn_io_dirent2_t *dirent,
+ const apr_array_header_t *ignore_patterns,
+ svn_boolean_t get_all,
+ svn_wc_status_func4_t status_func,
+ void *status_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ const char *dir_repos_root_url;
+ const char *dir_repos_relpath;
+ const char *dir_repos_uuid;
+ const struct svn_wc__db_info_t *dir_info;
+ apr_array_header_t *collected_ignore_patterns = NULL;
+ const char *parent_abspath = svn_dirent_dirname(local_abspath,
+ scratch_pool);
- if (svn_wc_is_adm_dir(key, iterpool))
- continue;
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
- if (ignore_patterns && ! patterns)
- SVN_ERR(collect_ignore_patterns(&patterns, wb->db, local_abspath,
- ignore_patterns, subpool,
- iterpool));
+ if (dirent->kind == svn_node_none)
+ dirent = NULL;
- SVN_ERR(send_unversioned_item(wb,
- node_abspath,
- dirent_p, FALSE,
- patterns,
- no_ignore || selected,
- status_func, status_baton,
- iterpool));
- }
+ SVN_ERR(svn_wc__db_read_single_info(&dir_info,
+ wb->db, parent_abspath,
+ scratch_pool, scratch_pool));
- /* Destroy our subpools. */
- svn_pool_destroy(subpool);
+ SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
+ &dir_repos_uuid, dir_info,
+ NULL, NULL, NULL,
+ wb->db, parent_abspath,
+ scratch_pool, scratch_pool));
+ /* An unversioned node with a tree conflict will see an INFO != NULL here,
+ * in which case the FALSE passed for UNVERSIONED_TREE_CONFLICTED has no
+ * effect and INFO->CONFLICTED counts.
+ * ### Maybe svn_wc__db_read_children_info() and read_info() should be more
+ * ### alike? */
+ SVN_ERR(one_child_status(wb,
+ local_abspath,
+ parent_abspath,
+ info,
+ dirent,
+ dir_repos_root_url,
+ dir_repos_relpath,
+ dir_repos_uuid,
+ FALSE, /* unversioned_tree_conflicted */
+ &collected_ignore_patterns,
+ ignore_patterns,
+ svn_depth_empty,
+ get_all,
+ TRUE, /* no_ignore. This is an explicit target. */
+ status_func,
+ status_baton,
+ cancel_func,
+ cancel_baton,
+ scratch_pool,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -1254,9 +1455,9 @@ hash_stash(void *baton,
{
apr_hash_t *stat_hash = baton;
apr_pool_t *hash_pool = apr_hash_pool_get(stat_hash);
- assert(! apr_hash_get(stat_hash, path, APR_HASH_KEY_STRING));
- apr_hash_set(stat_hash, apr_pstrdup(hash_pool, path),
- APR_HASH_KEY_STRING, svn_wc_dup_status3(status, hash_pool));
+ assert(! svn_hash_gets(stat_hash, path));
+ svn_hash_sets(stat_hash, apr_pstrdup(hash_pool, path),
+ svn_wc_dup_status3(status, hash_pool));
return SVN_NO_ERROR;
}
@@ -1297,7 +1498,6 @@ tweak_statushash(void *baton,
svn_boolean_t is_dir_baton,
svn_wc__db_t *db,
const char *local_abspath,
- svn_boolean_t is_dir,
enum svn_wc_status_kind repos_node_status,
enum svn_wc_status_kind repos_text_status,
enum svn_wc_status_kind repos_prop_status,
@@ -1316,7 +1516,7 @@ tweak_statushash(void *baton,
pool = apr_hash_pool_get(statushash);
/* Is PATH already a hash-key? */
- statstruct = apr_hash_get(statushash, local_abspath, APR_HASH_KEY_STRING);
+ statstruct = svn_hash_gets(statushash, local_abspath);
/* If not, make it so. */
if (! statstruct)
@@ -1339,8 +1539,7 @@ tweak_statushash(void *baton,
SVN_ERR(internal_status(&statstruct, db, local_abspath, pool,
scratch_pool));
statstruct->repos_lock = repos_lock;
- apr_hash_set(statushash, apr_pstrdup(pool, local_abspath),
- APR_HASH_KEY_STRING, statstruct);
+ svn_hash_sets(statushash, apr_pstrdup(pool, local_abspath), statstruct);
}
/* Merge a repos "delete" + "add" into a single "replace". */
@@ -1376,9 +1575,9 @@ tweak_statushash(void *baton,
else
statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath);
- statstruct->repos_root_url =
+ statstruct->repos_root_url =
b->edit_baton->anchor_status->repos_root_url;
- statstruct->repos_uuid =
+ statstruct->repos_uuid =
b->edit_baton->anchor_status->repos_uuid;
}
@@ -1386,7 +1585,7 @@ tweak_statushash(void *baton,
isn't available. */
if (statstruct->repos_node_status == svn_wc_status_deleted)
{
- statstruct->ood_kind = is_dir ? svn_node_dir : svn_node_file;
+ statstruct->ood_kind = statstruct->kind;
/* Pre 1.5 servers don't provide the revision a path was deleted.
So we punt and use the last committed revision of the path's
@@ -1442,9 +1641,8 @@ find_dir_repos_relpath(const struct dir_baton *db, apr_pool_t *pool)
{
const char *repos_relpath;
struct dir_baton *pb = db->parent_baton;
- const svn_wc_status3_t *status = apr_hash_get(pb->statii,
- db->local_abspath,
- APR_HASH_KEY_STRING);
+ const svn_wc_status3_t *status = svn_hash_gets(pb->statii,
+ db->local_abspath);
/* Note that status->repos_relpath could be NULL in the case of a missing
* directory, which means we need to recurse up another level to get
* a useful relpath. */
@@ -1464,32 +1662,40 @@ make_dir_baton(void **dir_baton,
const char *path,
struct edit_baton *edit_baton,
struct dir_baton *parent_baton,
- apr_pool_t *pool)
+ apr_pool_t *result_pool)
{
struct dir_baton *pb = parent_baton;
struct edit_baton *eb = edit_baton;
- struct dir_baton *d = apr_pcalloc(pool, sizeof(*d));
+ struct dir_baton *d;
const char *local_abspath;
const svn_wc_status3_t *status_in_parent;
+ apr_pool_t *dir_pool;
+
+ if (parent_baton)
+ dir_pool = svn_pool_create(parent_baton->pool);
+ else
+ dir_pool = svn_pool_create(result_pool);
+
+ d = apr_pcalloc(dir_pool, sizeof(*d));
SVN_ERR_ASSERT(path || (! pb));
/* Construct the absolute path of this directory. */
if (pb)
- local_abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
+ local_abspath = svn_dirent_join(eb->anchor_abspath, path, dir_pool);
else
local_abspath = eb->anchor_abspath;
/* Finish populating the baton members. */
+ d->pool = dir_pool;
d->local_abspath = local_abspath;
- d->name = path ? svn_dirent_basename(path, pool) : NULL;
+ d->name = path ? svn_dirent_basename(path, dir_pool) : NULL;
d->edit_baton = edit_baton;
d->parent_baton = parent_baton;
- d->pool = pool;
- d->statii = apr_hash_make(pool);
+ d->statii = apr_hash_make(dir_pool);
d->ood_changed_rev = SVN_INVALID_REVNUM;
d->ood_changed_date = 0;
- d->repos_relpath = apr_pstrdup(pool, find_dir_repos_relpath(d, pool));
+ d->repos_relpath = find_dir_repos_relpath(d, dir_pool);
d->ood_kind = svn_node_dir;
d->ood_changed_author = NULL;
@@ -1516,8 +1722,7 @@ make_dir_baton(void **dir_baton,
/* Get the status for this path's children. Of course, we only want
to do this if the path is versioned as a directory. */
if (pb)
- status_in_parent = apr_hash_get(pb->statii, d->local_abspath,
- APR_HASH_KEY_STRING);
+ status_in_parent = svn_hash_gets(pb->statii, d->local_abspath);
else
status_in_parent = eb->anchor_status;
@@ -1534,7 +1739,7 @@ make_dir_baton(void **dir_baton,
const svn_wc_status3_t *this_dir_status;
const apr_array_header_t *ignores = eb->ignores;
- SVN_ERR(get_dir_status(&eb->wb, local_abspath, NULL, TRUE,
+ SVN_ERR(get_dir_status(&eb->wb, local_abspath, TRUE,
status_in_parent->repos_root_url,
NULL /*parent_repos_relpath*/,
status_in_parent->repos_uuid,
@@ -1546,11 +1751,10 @@ make_dir_baton(void **dir_baton,
TRUE, TRUE,
hash_stash, d->statii,
eb->cancel_func, eb->cancel_baton,
- pool));
+ dir_pool));
/* If we found a depth here, it should govern. */
- this_dir_status = apr_hash_get(d->statii, d->local_abspath,
- APR_HASH_KEY_STRING);
+ this_dir_status = svn_hash_gets(d->statii, d->local_abspath);
if (this_dir_status && this_dir_status->versioned
&& (d->depth == svn_depth_unknown
|| d->depth > status_in_parent->depth))
@@ -1719,7 +1923,7 @@ handle_statii(struct edit_baton *eb,
|| depth == svn_depth_infinity))
{
SVN_ERR(get_dir_status(&eb->wb,
- local_abspath, NULL, TRUE,
+ local_abspath, TRUE,
dir_repos_root_url, dir_repos_relpath,
dir_repos_uuid,
NULL,
@@ -1747,7 +1951,7 @@ handle_statii(struct edit_baton *eb,
/*** The callbacks we'll plug into an svn_delta_editor_t structure. ***/
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
set_target_revision(void *edit_baton,
svn_revnum_t target_revision,
@@ -1759,7 +1963,7 @@ set_target_revision(void *edit_baton,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
open_root(void *edit_baton,
svn_revnum_t base_revision,
@@ -1772,7 +1976,7 @@ open_root(void *edit_baton,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
delete_entry(const char *path,
svn_revnum_t revision,
@@ -1782,16 +1986,13 @@ delete_entry(const char *path,
struct dir_baton *db = parent_baton;
struct edit_baton *eb = db->edit_baton;
const char *local_abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
- svn_wc__db_kind_t kind;
/* Note: when something is deleted, it's okay to tweak the
statushash immediately. No need to wait until close_file or
close_dir, because there's no risk of having to honor the 'added'
flag. We already know this item exists in the working copy. */
-
- SVN_ERR(svn_wc__db_read_kind(&kind, eb->db, local_abspath, FALSE, pool));
SVN_ERR(tweak_statushash(db, db, TRUE, eb->db,
- local_abspath, kind == svn_wc__db_kind_dir,
+ local_abspath,
svn_wc_status_deleted, 0, 0, revision, NULL, pool));
/* Mark the parent dir -- it lost an entry (unless that parent dir
@@ -1800,7 +2001,6 @@ delete_entry(const char *path,
if (db->parent_baton && (! *eb->target_basename))
SVN_ERR(tweak_statushash(db->parent_baton, db, TRUE,eb->db,
db->local_abspath,
- kind == svn_wc__db_kind_dir,
svn_wc_status_modified, svn_wc_status_modified,
0, SVN_INVALID_REVNUM, NULL, pool));
@@ -1808,7 +2008,7 @@ delete_entry(const char *path,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
add_directory(const char *path,
void *parent_baton,
@@ -1834,7 +2034,7 @@ add_directory(const char *path,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
open_directory(const char *path,
void *parent_baton,
@@ -1847,7 +2047,7 @@ open_directory(const char *path,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
change_dir_prop(void *dir_baton,
const char *name,
@@ -1878,7 +2078,7 @@ change_dir_prop(void *dir_baton,
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
close_directory(void *dir_baton,
apr_pool_t *pool)
@@ -1886,6 +2086,7 @@ close_directory(void *dir_baton,
struct dir_baton *db = dir_baton;
struct dir_baton *pb = db->parent_baton;
struct edit_baton *eb = db->edit_baton;
+ apr_pool_t *scratch_pool = db->pool;
/* If nothing has changed and directory has no out of
date descendants, return. */
@@ -1900,7 +2101,7 @@ close_directory(void *dir_baton,
if (db->added)
{
repos_node_status = svn_wc_status_added;
- repos_text_status = svn_wc_status_added;
+ repos_text_status = svn_wc_status_none;
repos_prop_status = db->prop_changed ? svn_wc_status_added
: svn_wc_status_none;
}
@@ -1923,9 +2124,9 @@ close_directory(void *dir_baton,
/* ### When we add directory locking, we need to find a
### directory lock here. */
SVN_ERR(tweak_statushash(pb, db, TRUE, eb->db, db->local_abspath,
- TRUE, repos_node_status, repos_text_status,
+ repos_node_status, repos_text_status,
repos_prop_status, SVN_INVALID_REVNUM, NULL,
- pool));
+ scratch_pool));
}
else
{
@@ -1956,8 +2157,7 @@ close_directory(void *dir_baton,
const svn_wc_status3_t *dir_status;
/* See if the directory was deleted or replaced. */
- dir_status = apr_hash_get(pb->statii, db->local_abspath,
- APR_HASH_KEY_STRING);
+ dir_status = svn_hash_gets(pb->statii, db->local_abspath);
if (dir_status &&
((dir_status->repos_node_status == svn_wc_status_deleted)
|| (dir_status->repos_node_status == svn_wc_status_replaced)))
@@ -1968,12 +2168,12 @@ close_directory(void *dir_baton,
dir_status ? dir_status->repos_root_url : NULL,
dir_status ? dir_status->repos_relpath : NULL,
dir_status ? dir_status->repos_uuid : NULL,
- db->statii, was_deleted, db->depth, pool));
+ db->statii, was_deleted, db->depth, scratch_pool));
if (dir_status && is_sendable_status(dir_status, eb->no_ignore,
eb->get_all))
SVN_ERR((eb->status_func)(eb->status_baton, db->local_abspath,
- dir_status, pool));
- apr_hash_set(pb->statii, db->local_abspath, APR_HASH_KEY_STRING, NULL);
+ dir_status, scratch_pool));
+ svn_hash_sets(pb->statii, db->local_abspath, NULL);
}
else if (! pb)
{
@@ -1983,15 +2183,14 @@ close_directory(void *dir_baton,
{
const svn_wc_status3_t *tgt_status;
- tgt_status = apr_hash_get(db->statii, eb->target_abspath,
- APR_HASH_KEY_STRING);
+ tgt_status = svn_hash_gets(db->statii, eb->target_abspath);
if (tgt_status)
{
if (tgt_status->versioned
&& tgt_status->kind == svn_node_dir)
{
SVN_ERR(get_dir_status(&eb->wb,
- eb->target_abspath, NULL, TRUE,
+ eb->target_abspath, TRUE,
NULL, NULL, NULL, NULL,
NULL /* dirent */,
eb->ignores,
@@ -1999,11 +2198,11 @@ close_directory(void *dir_baton,
eb->get_all, eb->no_ignore,
eb->status_func, eb->status_baton,
eb->cancel_func, eb->cancel_baton,
- pool));
+ scratch_pool));
}
if (is_sendable_status(tgt_status, eb->no_ignore, eb->get_all))
SVN_ERR((eb->status_func)(eb->status_baton, eb->target_abspath,
- tgt_status, pool));
+ tgt_status, scratch_pool));
}
}
else
@@ -2015,20 +2214,24 @@ close_directory(void *dir_baton,
eb->anchor_status->repos_root_url,
eb->anchor_status->repos_relpath,
eb->anchor_status->repos_uuid,
- db->statii, FALSE, eb->default_depth, pool));
+ db->statii, FALSE, eb->default_depth,
+ scratch_pool));
if (is_sendable_status(eb->anchor_status, eb->no_ignore,
eb->get_all))
SVN_ERR((eb->status_func)(eb->status_baton, db->local_abspath,
- eb->anchor_status, pool));
+ eb->anchor_status, scratch_pool));
eb->anchor_status = NULL;
}
}
+
+ svn_pool_clear(scratch_pool); /* Clear baton and its pool */
+
return SVN_NO_ERROR;
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
add_file(const char *path,
void *parent_baton,
@@ -2051,7 +2254,7 @@ add_file(const char *path,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
open_file(const char *path,
void *parent_baton,
@@ -2067,7 +2270,7 @@ open_file(const char *path,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
apply_textdelta(void *file_baton,
const char *base_checksum,
@@ -2088,7 +2291,7 @@ apply_textdelta(void *file_baton,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
change_file_prop(void *file_baton,
const char *name,
@@ -2120,7 +2323,7 @@ change_file_prop(void *file_baton,
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
close_file(void *file_baton,
const char *text_checksum, /* ignored, as we receive no data */
@@ -2140,8 +2343,10 @@ close_file(void *file_baton,
if (fb->added)
{
repos_node_status = svn_wc_status_added;
- repos_text_status = svn_wc_status_added;
- repos_prop_status = fb->prop_changed ? svn_wc_status_added : 0;
+ repos_text_status = fb->text_changed ? svn_wc_status_modified
+ : 0 /* don't tweak */;
+ repos_prop_status = fb->prop_changed ? svn_wc_status_modified
+ : 0 /* don't tweak */;
if (fb->edit_baton->wb.repos_locks)
{
@@ -2153,27 +2358,29 @@ close_file(void *file_baton,
const char *repos_relpath = svn_relpath_join(dir_repos_relpath,
fb->name, pool);
- repos_lock = apr_hash_get(fb->edit_baton->wb.repos_locks,
- svn_fspath__join("/", repos_relpath,
- pool),
- APR_HASH_KEY_STRING);
+ repos_lock = svn_hash_gets(fb->edit_baton->wb.repos_locks,
+ svn_fspath__join("/", repos_relpath,
+ pool));
}
}
else
{
repos_node_status = (fb->text_changed || fb->prop_changed)
- ? svn_wc_status_modified : 0;
- repos_text_status = fb->text_changed ? svn_wc_status_modified : 0;
- repos_prop_status = fb->prop_changed ? svn_wc_status_modified : 0;
+ ? svn_wc_status_modified
+ : 0 /* don't tweak */;
+ repos_text_status = fb->text_changed ? svn_wc_status_modified
+ : 0 /* don't tweak */;
+ repos_prop_status = fb->prop_changed ? svn_wc_status_modified
+ : 0 /* don't tweak */;
}
return tweak_statushash(fb, NULL, FALSE, fb->edit_baton->db,
- fb->local_abspath, FALSE, repos_node_status,
+ fb->local_abspath, repos_node_status,
repos_text_status, repos_prop_status,
SVN_INVALID_REVNUM, repos_lock, pool);
}
-/* */
+/* An svn_delta_editor_t function. */
static svn_error_t *
close_edit(void *edit_baton,
apr_pool_t *pool)
@@ -2207,7 +2414,7 @@ close_edit(void *edit_baton,
/*** Public API ***/
svn_error_t *
-svn_wc_get_status_editor5(const svn_delta_editor_t **editor,
+svn_wc__get_status_editor(const svn_delta_editor_t **editor,
void **edit_baton,
void **set_locks_baton,
svn_revnum_t *edit_revision,
@@ -2230,7 +2437,10 @@ svn_wc_get_status_editor5(const svn_delta_editor_t **editor,
struct edit_baton *eb;
svn_delta_editor_t *tree_editor = svn_delta_default_editor(result_pool);
void *inner_baton;
+ struct svn_wc__shim_fetch_baton_t *sfb;
const svn_delta_editor_t *inner_editor;
+ svn_delta_shim_callbacks_t *shim_callbacks =
+ svn_delta_shim_callbacks_default(result_pool);
/* Construct an edit baton. */
eb = apr_pcalloc(result_pool, sizeof(*eb));
@@ -2318,9 +2528,50 @@ svn_wc_get_status_editor5(const svn_delta_editor_t **editor,
if (set_locks_baton)
*set_locks_baton = eb;
+ sfb = apr_palloc(result_pool, sizeof(*sfb));
+ sfb->db = wc_ctx->db;
+ sfb->base_abspath = eb->anchor_abspath;
+ sfb->fetch_base = FALSE;
+
+ shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
+ shim_callbacks->fetch_props_func = svn_wc__fetch_props_func;
+ shim_callbacks->fetch_base_func = svn_wc__fetch_base_func;
+ shim_callbacks->fetch_baton = sfb;
+
+ SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+ NULL, NULL, shim_callbacks,
+ result_pool, scratch_pool));
+
return SVN_NO_ERROR;
}
+/* Like svn_io_stat_dirent, but works case sensitive inside working
+ copies. Before 1.8 we handled this with a selection filter inside
+ a directory */
+static svn_error_t *
+stat_wc_dirent_case_sensitive(const svn_io_dirent2_t **dirent,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t is_wcroot;
+
+ /* The wcroot is "" inside the wc; handle it as not in the wc, as
+ the case of the root is indifferent to us. */
+
+ /* Note that for performance this is really just a few hashtable lookups,
+ as we just used local_abspath for a db call in both our callers */
+ SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath,
+ scratch_pool));
+
+ return svn_error_trace(
+ svn_io_stat_dirent2(dirent, local_abspath,
+ ! is_wcroot /* verify_truename */,
+ TRUE /* ignore_enoent */,
+ result_pool, scratch_pool));
+}
+
svn_error_t *
svn_wc__internal_walk_status(svn_wc__db_t *db,
const char *local_abspath,
@@ -2337,9 +2588,7 @@ svn_wc__internal_walk_status(svn_wc__db_t *db,
{
struct walk_status_baton wb;
const svn_io_dirent2_t *dirent;
- const char *anchor_abspath, *target_name;
- svn_boolean_t skip_root;
- const struct svn_wc__db_info_t *dir_info;
+ const struct svn_wc__db_info_t *info;
svn_error_t *err;
wb.db = db;
@@ -2348,9 +2597,6 @@ svn_wc__internal_walk_status(svn_wc__db_t *db,
wb.repos_root = NULL;
wb.repos_locks = NULL;
- SVN_ERR(svn_wc__db_externals_defined_below(&wb.externals, db, local_abspath,
- scratch_pool, scratch_pool));
-
/* Use the caller-provided ignore patterns if provided; the build-time
configured defaults otherwise. */
if (!ignore_patterns)
@@ -2361,71 +2607,81 @@ svn_wc__internal_walk_status(svn_wc__db_t *db,
ignore_patterns = ignores;
}
- err = read_info(&dir_info, local_abspath, db, scratch_pool, scratch_pool);
+ err = svn_wc__db_read_single_info(&info, db, local_abspath,
+ scratch_pool, scratch_pool);
- if (!err
- && dir_info->kind == svn_wc__db_kind_dir
- && dir_info->status != svn_wc__db_status_not_present
- && dir_info->status != svn_wc__db_status_excluded
- && dir_info->status != svn_wc__db_status_server_excluded)
+ if (err)
{
- anchor_abspath = local_abspath;
- target_name = NULL;
- skip_root = FALSE;
+ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ info = NULL;
+ }
+ else
+ return svn_error_trace(err);
+
+ wb.externals = apr_hash_make(scratch_pool);
+
+ SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, TRUE,
+ scratch_pool, scratch_pool));
}
- else if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
- return svn_error_trace(err);
else
{
- svn_error_clear(err);
- dir_info = NULL; /* Don't pass information of the child */
+ SVN_ERR(svn_wc__db_externals_defined_below(&wb.externals,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
- /* Walk the status of the parent of LOCAL_ABSPATH, but only report
- status on its child LOCAL_ABSPATH. */
- anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
- target_name = svn_dirent_basename(local_abspath, NULL);
- skip_root = TRUE;
+ SVN_ERR(stat_wc_dirent_case_sensitive(&dirent, db, local_abspath,
+ scratch_pool, scratch_pool));
}
- SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
- scratch_pool, scratch_pool));
-
-#ifdef HAVE_SYMLINK
- if (dirent->special && !skip_root)
+ if (info
+ && info->kind == svn_node_dir
+ && info->status != svn_wc__db_status_not_present
+ && info->status != svn_wc__db_status_excluded
+ && info->status != svn_wc__db_status_server_excluded)
{
- svn_io_dirent2_t *this_dirent = svn_io_dirent2_dup(dirent,
- scratch_pool);
-
- /* We're being pointed to the status root via a symlink.
- * Get the real node kind and pretend the path is not a symlink.
- * This prevents send_status_structure() from treating the root
- * as a directory obstructed by a file. */
- SVN_ERR(svn_io_check_resolved_path(local_abspath,
- &this_dirent->kind, scratch_pool));
- this_dirent->special = FALSE;
- SVN_ERR(send_status_structure(&wb, local_abspath,
- NULL, NULL, NULL,
- dir_info, this_dirent, get_all,
- status_func, status_baton,
- scratch_pool));
- skip_root = TRUE;
+ SVN_ERR(get_dir_status(&wb,
+ local_abspath,
+ FALSE /* skip_root */,
+ NULL, NULL, NULL,
+ info,
+ dirent,
+ ignore_patterns,
+ depth,
+ get_all,
+ no_ignore,
+ status_func, status_baton,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ }
+ else
+ {
+ /* It may be a file or an unversioned item. And this is an explicit
+ * target, so no ignoring. An unversioned item (file or dir) shows a
+ * status like '?', and can yield a tree conflicted path. */
+ err = get_child_status(&wb,
+ local_abspath,
+ info,
+ dirent,
+ ignore_patterns,
+ get_all,
+ status_func, status_baton,
+ cancel_func, cancel_baton,
+ scratch_pool);
+
+ if (!info && err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ /* The parent is also not versioned, but it is not nice to show
+ an error about a path a user didn't intend to touch. */
+ svn_error_clear(err);
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("The node '%s' was not found."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ SVN_ERR(err);
}
-#endif
-
- SVN_ERR(get_dir_status(&wb,
- anchor_abspath,
- target_name,
- skip_root,
- NULL, NULL, NULL,
- dir_info,
- dirent,
- ignore_patterns,
- depth,
- get_all,
- no_ignore,
- status_func, status_baton,
- cancel_func, cancel_baton,
- scratch_pool));
return SVN_NO_ERROR;
}
@@ -2480,9 +2736,9 @@ svn_wc_get_default_ignores(apr_array_header_t **patterns,
apr_hash_t *config,
apr_pool_t *pool)
{
- svn_config_t *cfg = config ? apr_hash_get(config,
- SVN_CONFIG_CATEGORY_CONFIG,
- APR_HASH_KEY_STRING) : NULL;
+ svn_config_t *cfg = config
+ ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG)
+ : NULL;
const char *val;
/* Check the Subversion run-time configuration for global ignores.
@@ -2507,7 +2763,7 @@ internal_status(svn_wc_status3_t **status,
apr_pool_t *scratch_pool)
{
const svn_io_dirent2_t *dirent;
- svn_wc__db_kind_t node_kind;
+ svn_node_kind_t node_kind;
const char *parent_repos_relpath;
const char *parent_repos_root_url;
const char *parent_repos_uuid;
@@ -2518,9 +2774,6 @@ internal_status(svn_wc_status3_t **status,
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
- scratch_pool, scratch_pool));
-
err = svn_wc__db_read_info(&node_status, &node_kind, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, &conflicted,
@@ -2528,26 +2781,33 @@ internal_status(svn_wc_status3_t **status,
db, local_abspath,
scratch_pool, scratch_pool);
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ if (err)
{
+ if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+ return svn_error_trace(err);
+
svn_error_clear(err);
- node_kind = svn_wc__db_kind_unknown;
+ node_kind = svn_node_unknown;
/* Ensure conflicted is always set, but don't hide tree conflicts
on 'hidden' nodes. */
conflicted = FALSE;
+
+ SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, TRUE,
+ scratch_pool, scratch_pool));
}
- else if (err)
- {
- return svn_error_trace(err);
- }
- else if (node_status == svn_wc__db_status_not_present
- || node_status == svn_wc__db_status_server_excluded
- || node_status == svn_wc__db_status_excluded)
+ else
+ SVN_ERR(stat_wc_dirent_case_sensitive(&dirent, db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (node_kind != svn_node_unknown
+ && (node_status == svn_wc__db_status_not_present
+ || node_status == svn_wc__db_status_server_excluded
+ || node_status == svn_wc__db_status_excluded))
{
- node_kind = svn_wc__db_kind_unknown;
+ node_kind = svn_node_unknown;
}
- if (node_kind == svn_wc__db_kind_unknown)
+ if (node_kind == svn_node_unknown)
return svn_error_trace(assemble_unversioned(status,
db, local_abspath,
dirent, conflicted,
@@ -2655,6 +2915,14 @@ svn_wc_dup_status3(const svn_wc_status3_t *orig_stat,
new_stat->repos_uuid
= apr_pstrdup(pool, orig_stat->repos_uuid);
+ if (orig_stat->moved_from_abspath)
+ new_stat->moved_from_abspath
+ = apr_pstrdup(pool, orig_stat->moved_from_abspath);
+
+ if (orig_stat->moved_to_abspath)
+ new_stat->moved_to_abspath
+ = apr_pstrdup(pool, orig_stat->moved_to_abspath);
+
/* Return the new hotness. */
return new_stat;
}