svn_depth_empty :()

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;
}