in subversion/libsvn_repos/reporter.c [1101:1360]
svn_depth_empty : (depth)
/* Emit edits within directory DIR_BATON (with corresponding path
E_PATH) with the changes from the directory S_REV/S_PATH to the
directory B->t_rev/T_PATH. S_PATH may be NULL if the entry does
not exist in the source.
WC_DEPTH is this path's depth as reported by set_path/link_path.
REQUESTED_DEPTH is derived from the depth set by
svn_repos_begin_report().
When iterating over this directory's entries, the following tables
describe what happens for all possible combinations
of WC_DEPTH/REQUESTED_DEPTH (rows represent WC_DEPTH, columns
represent REQUESTED_DEPTH):
Legend:
X: ignore this entry (it's either below the requested depth, or
if the requested depth is svn_depth_unknown, below the working
copy depth)
o: handle this entry normally
U: handle the entry as if it were a newly added repository path
(the client is upgrading to a deeper wc and doesn't currently
have this entry, but it should be there after the upgrade, so we
need to send the whole thing, not just deltas)
For files:
______________________________________________________________
| req. depth| unknown | empty | files | immediates | infinity |
|wc. depth | | | | | |
|___________|_________|_______|_______|____________|__________|
|empty | X | X | U | U | U |
|___________|_________|_______|_______|____________|__________|
|files | o | X | o | o | o |
|___________|_________|_______|_______|____________|__________|
|immediates | o | X | o | o | o |
|___________|_________|_______|_______|____________|__________|
|infinity | o | X | o | o | o |
|___________|_________|_______|_______|____________|__________|
For directories:
______________________________________________________________
| req. depth| unknown | empty | files | immediates | infinity |
|wc. depth | | | | | |
|___________|_________|_______|_______|____________|__________|
|empty | X | X | X | U | U |
|___________|_________|_______|_______|____________|__________|
|files | X | X | X | U | U |
|___________|_________|_______|_______|____________|__________|
|immediates | o | X | X | o | o |
|___________|_________|_______|_______|____________|__________|
|infinity | o | X | X | o | o |
|___________|_________|_______|_______|____________|__________|
These rules are enforced by the is_depth_upgrade() function and by
various other checks below.
*/
static svn_error_t *
delta_dirs(report_baton_t *b, svn_revnum_t s_rev, const char *s_path,
const char *t_path, void *dir_baton, const char *e_path,
svn_boolean_t start_empty, svn_depth_t wc_depth,
svn_depth_t requested_depth, apr_pool_t *pool)
{
apr_hash_t *s_entries = NULL, *t_entries;
apr_hash_index_t *hi;
apr_pool_t *subpool = svn_pool_create(pool);
apr_array_header_t *t_ordered_entries = NULL;
int i;
/* Compare the property lists. If we're starting empty, pass a NULL
source path so that we add all the properties.
When we support directory locks, we must pass the lock token here. */
SVN_ERR(delta_proplists(b, s_rev, start_empty ? NULL : s_path, t_path,
NULL, change_dir_prop, dir_baton, subpool));
svn_pool_clear(subpool);
if (requested_depth > svn_depth_empty
|| requested_depth == svn_depth_unknown)
{
apr_pool_t *iterpool;
/* Get the list of entries in each of source and target. */
if (s_path && !start_empty)
{
svn_fs_root_t *s_root;
SVN_ERR(get_source_root(b, &s_root, s_rev));
SVN_ERR(svn_fs_dir_entries(&s_entries, s_root, s_path, subpool));
}
SVN_ERR(svn_fs_dir_entries(&t_entries, b->t_root, t_path, subpool));
/* Iterate over the report information for this directory. */
iterpool = svn_pool_create(subpool);
while (1)
{
path_info_t *info;
const char *name, *s_fullpath, *t_fullpath, *e_fullpath;
const svn_fs_dirent_t *s_entry, *t_entry;
svn_pool_clear(iterpool);
SVN_ERR(fetch_path_info(b, &name, &info, e_path, iterpool));
if (!name)
break;
/* Invalid revnum means we should delete, unless this is
just an excluded subpath. */
if (info
&& !SVN_IS_VALID_REVNUM(info->rev)
&& info->depth != svn_depth_exclude)
{
/* We want to perform deletes before non-replacement adds,
for graceful handling of case-only renames on
case-insensitive client filesystems. So, if the report
item is a delete, remove the entry from the source hash,
but don't update the entry yet. */
if (s_entries)
svn_hash_sets(s_entries, name, NULL);
svn_pool_destroy(info->pool);
continue;
}
e_fullpath = svn_relpath_join(e_path, name, iterpool);
t_fullpath = svn_fspath__join(t_path, name, iterpool);
t_entry = svn_hash_gets(t_entries, name);
s_fullpath = s_path ? svn_fspath__join(s_path, name, iterpool) : NULL;
s_entry = s_entries ? svn_hash_gets(s_entries, name) : NULL;
/* The only special cases where we don't process the entry are
- When requested_depth is files but the reported path is
a directory. This is technically a client error, but we
handle it anyway, by skipping the entry.
- When the reported depth is svn_depth_exclude.
*/
if (! ((requested_depth == svn_depth_files
&& ((t_entry && t_entry->kind == svn_node_dir)
|| (s_entry && s_entry->kind == svn_node_dir)))
|| (info && info->depth == svn_depth_exclude)))
SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath,
t_entry, dir_baton, e_fullpath, info,
info ? info->depth
: DEPTH_BELOW_HERE(wc_depth),
DEPTH_BELOW_HERE(requested_depth), iterpool));
/* Don't revisit this name in the target or source entries. */
svn_hash_sets(t_entries, name, NULL);
if (s_entries
/* Keep the entry for later process if it is reported as
excluded and got deleted in repos. */
&& (! info || info->depth != svn_depth_exclude || t_entry))
svn_hash_sets(s_entries, name, NULL);
/* pathinfo entries live in their own subpools due to lookahead,
so we need to clear each one out as we finish with it. */
if (info)
svn_pool_destroy(info->pool);
}
/* Remove any deleted entries. Do this before processing the
target, for graceful handling of case-only renames. */
if (s_entries)
{
for (hi = apr_hash_first(subpool, s_entries);
hi;
hi = apr_hash_next(hi))
{
const svn_fs_dirent_t *s_entry = apr_hash_this_val(hi);
svn_pool_clear(iterpool);
if (svn_hash_gets(t_entries, s_entry->name) == NULL)
{
const char *e_fullpath;
svn_revnum_t deleted_rev;
if (s_entry->kind == svn_node_file
&& wc_depth < svn_depth_files)
continue;
if (s_entry->kind == svn_node_dir
&& (wc_depth < svn_depth_immediates
|| requested_depth == svn_depth_files))
continue;
/* There is no corresponding target entry, so delete. */
e_fullpath = svn_relpath_join(e_path, s_entry->name, iterpool);
SVN_ERR(svn_repos_deleted_rev(svn_fs_root_fs(b->t_root),
svn_fspath__join(t_path,
s_entry->name,
iterpool),
s_rev, b->t_rev,
&deleted_rev, iterpool));
SVN_ERR(b->editor->delete_entry(e_fullpath,
deleted_rev,
dir_baton, iterpool));
}
}
}
/* Loop over the dirents in the target. */
SVN_ERR(svn_fs_dir_optimal_order(&t_ordered_entries, b->t_root,
t_entries, subpool, iterpool));
for (i = 0; i < t_ordered_entries->nelts; ++i)
{
const svn_fs_dirent_t *t_entry
= APR_ARRAY_IDX(t_ordered_entries, i, svn_fs_dirent_t *);
const svn_fs_dirent_t *s_entry;
const char *s_fullpath, *t_fullpath, *e_fullpath;
svn_pool_clear(iterpool);
if (is_depth_upgrade(wc_depth, requested_depth, t_entry->kind))
{
/* We're making the working copy deeper, pretend the source
doesn't exist. */
s_entry = NULL;
s_fullpath = NULL;
}
else
{
if (t_entry->kind == svn_node_file
&& requested_depth == svn_depth_unknown
&& wc_depth < svn_depth_files)
continue;
if (t_entry->kind == svn_node_dir
&& (wc_depth < svn_depth_immediates
|| requested_depth == svn_depth_files))
continue;
/* Look for an entry with the same name in the source dirents. */
s_entry = s_entries ?
svn_hash_gets(s_entries, t_entry->name) : NULL;
s_fullpath = s_entry ?
svn_fspath__join(s_path, t_entry->name, iterpool) : NULL;
}
/* Compose the report, editor, and target paths for this entry. */
e_fullpath = svn_relpath_join(e_path, t_entry->name, iterpool);
t_fullpath = svn_fspath__join(t_path, t_entry->name, iterpool);
SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath,
t_entry, dir_baton, e_fullpath, NULL,
DEPTH_BELOW_HERE(wc_depth),
DEPTH_BELOW_HERE(requested_depth),
iterpool));
}
/* iterpool is destroyed by destroying its parent (subpool) below */
}
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}