Exemple #1
0
svn_error_t *
svn_wc__fetch_props_func(apr_hash_t **props,
                         void *baton,
                         const char *path,
                         svn_revnum_t base_revision,
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
{
  struct svn_wc__shim_fetch_baton_t *sfb = baton;
  const char *local_abspath = svn_dirent_join(sfb->base_abspath, path,
                                              scratch_pool);
  svn_error_t *err;

  if (sfb->fetch_base)
    err = svn_wc__db_base_get_props(props, sfb->db, local_abspath, result_pool,
                                    scratch_pool);
  else
    err = svn_wc__db_read_props(props, sfb->db, local_abspath,
                                result_pool, scratch_pool);

  /* If the path doesn't exist, just return an empty set of props. */
  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
    {
      svn_error_clear(err);
      *props = apr_hash_make(result_pool);
    }
  else if (err)
    return svn_error_trace(err);

  return SVN_NO_ERROR;
}
Exemple #2
0
/* Implements svn_wc_status_func3_t */
static svn_error_t *
diff_status_callback(void *baton,
                     const char *local_abspath,
                     const svn_wc_status3_t *status,
                     apr_pool_t *scratch_pool)
{
  struct diff_baton *eb = baton;
  svn_wc__db_t *db = eb->db;

  if (! status->versioned)
    return SVN_NO_ERROR; /* unversioned (includes dir externals) */

  if (status->node_status == svn_wc_status_conflicted
      && status->text_status == svn_wc_status_none
      && status->prop_status == svn_wc_status_none)
    {
      /* Node is an actual only node describing a tree conflict */
      return SVN_NO_ERROR;
    }

  /* Not text/prop modified, not copied. Easy out */
  if (status->node_status == svn_wc_status_normal && !status->copied)
    return SVN_NO_ERROR;

  /* Mark all directories where we are no longer inside as closed */
  while (eb->cur
         && !svn_dirent_is_ancestor(eb->cur->local_abspath, local_abspath))
    {
      struct node_state_t *ns = eb->cur;

      if (!ns->skip)
        {
          if (ns->propchanges)
            SVN_ERR(eb->processor->dir_changed(ns->relpath,
                                               ns->left_src,
                                               ns->right_src,
                                               ns->left_props,
                                               ns->right_props,
                                               ns->propchanges,
                                               ns->baton,
                                               eb->processor,
                                               ns->pool));
          else
            SVN_ERR(eb->processor->dir_closed(ns->relpath,
                                              ns->left_src,
                                              ns->right_src,
                                              ns->baton,
                                              eb->processor,
                                              ns->pool));
        }
      eb->cur = ns->parent;
      svn_pool_clear(ns->pool);
    }
  SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
                       FALSE, scratch_pool));

  if (eb->cur && eb->cur->skip_children)
    return SVN_NO_ERROR;

  if (eb->changelist_hash != NULL
      && (!status->changelist
          || ! svn_hash_gets(eb->changelist_hash, status->changelist)))
    return SVN_NO_ERROR; /* Filtered via changelist */

  /* This code does about the same thing as the inner body of
     walk_local_nodes_diff() in diff_editor.c, except that
     it is already filtered by the status walker, doesn't have to
     account for remote changes (and many tiny other details) */

  {
    svn_boolean_t repos_only;
    svn_boolean_t local_only;
    svn_wc__db_status_t db_status;
    svn_boolean_t have_base;
    svn_node_kind_t base_kind;
    svn_node_kind_t db_kind = status->kind;
    svn_depth_t depth_below_here = svn_depth_unknown;

    const char *child_abspath = local_abspath;
    const char *child_relpath = svn_dirent_skip_ancestor(eb->anchor_abspath,
                                                         local_abspath);


    repos_only = FALSE;
    local_only = FALSE;

    /* ### optimize away this call using status info. Should
           be possible in almost every case (except conflict, missing, obst.)*/
    SVN_ERR(svn_wc__db_read_info(&db_status, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL,
                                 &have_base, NULL, NULL,
                                 eb->db, local_abspath,
                                 scratch_pool, scratch_pool));
    if (!have_base)
      {
        local_only = TRUE; /* Only report additions */
      }
    else if (db_status == svn_wc__db_status_normal)
      {
        /* Simple diff */
        base_kind = db_kind;
      }
    else if (db_status == svn_wc__db_status_deleted)
      {
        svn_wc__db_status_t base_status;
        repos_only = TRUE;
        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL,
                                         eb->db, local_abspath,
                                         scratch_pool, scratch_pool));

        if (base_status != svn_wc__db_status_normal)
          return SVN_NO_ERROR;
      }
    else
      {
        /* working status is either added or deleted */
        svn_wc__db_status_t base_status;

        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL, NULL,
                                         eb->db, local_abspath,
                                         scratch_pool, scratch_pool));

        if (base_status != svn_wc__db_status_normal)
          local_only = TRUE;
        else if (base_kind != db_kind || !eb->ignore_ancestry)
          {
            repos_only = TRUE;
            local_only = TRUE;
          }
      }

    if (repos_only)
      {
        /* Report repository form deleted */
        if (base_kind == svn_node_file)
          SVN_ERR(svn_wc__diff_base_only_file(db, child_abspath,
                                              child_relpath,
                                              SVN_INVALID_REVNUM,
                                              eb->processor,
                                              eb->cur ? eb->cur->baton : NULL,
                                              scratch_pool));
        else if (base_kind == svn_node_dir)
          SVN_ERR(svn_wc__diff_base_only_dir(db, child_abspath,
                                             child_relpath,
                                             SVN_INVALID_REVNUM,
                                             depth_below_here,
                                             eb->processor,
                                             eb->cur ? eb->cur->baton : NULL,
                                             eb->cancel_func,
                                             eb->cancel_baton,
                                             scratch_pool));
      }
    else if (!local_only)
      {
        /* Diff base against actual */
        if (db_kind == svn_node_file)
          {
            SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
                                                   child_relpath,
                                                   SVN_INVALID_REVNUM,
                                                   eb->changelist_hash,
                                                   eb->processor,
                                                   eb->cur
                                                        ? eb->cur->baton
                                                        : NULL,
                                                   FALSE,
                                                   eb->cancel_func,
                                                   eb->cancel_baton,
                                                   scratch_pool));
          }
        else if (db_kind == svn_node_dir)
          {
            SVN_ERR(ensure_state(eb, local_abspath, FALSE, scratch_pool));

            if (status->prop_status != svn_wc_status_none
                && status->prop_status != svn_wc_status_normal)
              {
                apr_array_header_t *propchanges;
                SVN_ERR(svn_wc__db_base_get_props(&eb->cur->left_props,
                                                  eb->db, local_abspath,
                                                  eb->cur->pool,
                                                  scratch_pool));
                SVN_ERR(svn_wc__db_read_props(&eb->cur->right_props,
                                              eb->db, local_abspath,
                                              eb->cur->pool,
                                              scratch_pool));

                SVN_ERR(svn_prop_diffs(&propchanges,
                                       eb->cur->right_props,
                                       eb->cur->left_props,
                                       eb->cur->pool));

                eb->cur->propchanges = propchanges;
              }
          }
      }

    if (local_only && (db_status != svn_wc__db_status_deleted))
      {
        if (db_kind == svn_node_file)
          SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
                                               child_relpath,
                                               eb->processor,
                                               eb->cur ? eb->cur->baton : NULL,
                                               eb->changelist_hash,
                                               FALSE,
                                               eb->cancel_func,
                                               eb->cancel_baton,
                                               scratch_pool));
        else if (db_kind == svn_node_dir)
          SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
                                              child_relpath, depth_below_here,
                                              eb->processor,
                                              eb->cur ? eb->cur->baton : NULL,
                                              eb->changelist_hash,
                                              FALSE,
                                              eb->cancel_func,
                                              eb->cancel_baton,
                                              scratch_pool));
      }

    if (db_kind == svn_node_dir && (local_only || repos_only))
      SVN_ERR(ensure_state(eb, local_abspath, TRUE /* skip */, scratch_pool));
  }

  return SVN_NO_ERROR;
}
Exemple #3
0
svn_error_t *
svn_wc__sync_flags_with_props(svn_boolean_t *did_set,
                              svn_wc__db_t *db,
                              const char *local_abspath,
                              apr_pool_t *scratch_pool)
{
  svn_wc__db_status_t status;
  svn_node_kind_t kind;
  svn_wc__db_lock_t *lock;
  apr_hash_t *props = NULL;
  svn_boolean_t had_props;
  svn_boolean_t props_mod;

  if (did_set)
    *did_set = FALSE;

  /* ### We'll consolidate these info gathering statements in a future
         commit. */

  SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                               NULL, &lock, NULL, NULL, NULL, NULL, NULL,
                               &had_props, &props_mod, NULL, NULL, NULL,
                               db, local_abspath,
                               scratch_pool, scratch_pool));

  /* We actually only care about the following flags on files, so just
     early-out for all other types.

     Also bail if there is no in-wc representation of the file. */
  if (kind != svn_node_file
      || (status != svn_wc__db_status_normal
          && status != svn_wc__db_status_added))
    return SVN_NO_ERROR;

  if (props_mod || had_props)
    SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
                                  scratch_pool));
  else
    props = NULL;

  /* If we get this far, we're going to change *something*, so just set
     the flag appropriately. */
  if (did_set)
    *did_set = TRUE;

  /* Handle the read-write bit. */
  if (status != svn_wc__db_status_normal
      || props == NULL
      || ! svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)
      || lock)
    {
      SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
    }
  else
    {
      /* Special case: If we have an uncommitted svn:needs-lock, we don't
         set the file read_only just yet.  That happens upon commit. */
      apr_hash_t *pristine_props;

      if (! props_mod)
        pristine_props = props;
      else if (had_props)
        SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
                                                scratch_pool, scratch_pool));
      else
        pristine_props = NULL;

      if (pristine_props
            && svn_hash_gets(pristine_props, SVN_PROP_NEEDS_LOCK) )
            /*&& props
            && apr_hash_get(props, SVN_PROP_NEEDS_LOCK, APR_HASH_KEY_STRING) )*/
        SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool));
    }

/* Windows doesn't care about the execute bit. */
#ifndef WIN32

  if (props == NULL
      || ! svn_hash_gets(props, SVN_PROP_EXECUTABLE))
    {
      /* Turn off the execute bit */
      SVN_ERR(svn_io_set_file_executable(local_abspath, FALSE, FALSE,
                                         scratch_pool));
    }
  else
    SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE,
                                       scratch_pool));
#endif

  return SVN_NO_ERROR;
}
Exemple #4
0
/* Diff the file PATH against its text base.  At this
 * stage we are dealing with a file that does exist in the working copy.
 *
 * DIR_BATON is the parent directory baton, PATH is the path to the file to
 * be compared.
 *
 * Do all allocation in POOL.
 *
 * ### TODO: Need to work on replace if the new filename used to be a
 * directory.
 */
static svn_error_t *
file_diff(struct diff_baton *eb,
          const char *local_abspath,
          const char *path,
          apr_pool_t *scratch_pool)
{
    svn_wc__db_t *db = eb->db;
    const char *empty_file;
    const char *original_repos_relpath;
    svn_wc__db_status_t status;
    svn_kind_t kind;
    svn_revnum_t revision;
    const svn_checksum_t *checksum;
    svn_boolean_t op_root;
    svn_boolean_t had_props, props_mod;
    svn_boolean_t have_base, have_more_work;
    svn_boolean_t replaced = FALSE;
    svn_boolean_t base_replace = FALSE;
    svn_wc__db_status_t base_status;
    svn_revnum_t base_revision = SVN_INVALID_REVNUM;
    const svn_checksum_t *base_checksum;
    const char *pristine_abspath;

    SVN_ERR(svn_wc__db_read_info(&status, &kind, &revision, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, &checksum, NULL,
                                 &original_repos_relpath, NULL, NULL, NULL,
                                 NULL, NULL, NULL, NULL, NULL,
                                 &op_root, &had_props, &props_mod,
                                 &have_base, &have_more_work, NULL,
                                 db, local_abspath, scratch_pool, scratch_pool));

    if ((status == svn_wc__db_status_added) && (have_base || have_more_work))
    {
        SVN_ERR(svn_wc__db_node_check_replace(&replaced, &base_replace,
                                              NULL, db, local_abspath,
                                              scratch_pool));

        if (replaced && base_replace /* && !have_more_work */)
        {
            svn_kind_t base_kind;
            SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind,
                                             &base_revision,
                                             NULL, NULL, NULL, NULL, NULL, NULL,
                                             NULL, &base_checksum, NULL,
                                             NULL, NULL, NULL,
                                             db, local_abspath,
                                             scratch_pool, scratch_pool));

            if (base_status != svn_wc__db_status_normal
                    || base_kind != kind)
            {
                /* We can't show a replacement here */
                replaced = FALSE;
                base_replace = FALSE;
            }
        }
        else
        {
            /* We can't look in this middle working layer (yet).
               We just report the change itself.

               And if we could look at it, how would we report the addition
               of this middle layer (and maybe different layers below that)?

               For 1.7 we just do what we did before: Ignore this layering
               problem and just show how the current file got in your wc.
             */
            replaced = FALSE;
            base_replace = FALSE;
        }
    }

    /* Now refine ADDED to one of: ADDED, COPIED, MOVED_HERE. Note that only
       the latter two have corresponding pristine info to diff against.  */
    if (status == svn_wc__db_status_added)
        SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
                                         &original_repos_relpath, NULL, NULL,
                                         NULL, NULL, NULL, db, local_abspath,
                                         scratch_pool, scratch_pool));


    SVN_ERR(get_empty_file(eb, &empty_file, scratch_pool));

    /* When we show a delete, we show a diff of the original pristine against
     * an empty file.
     * A base-replace is treated like a delete plus an add.
     *
     * For this kind of diff we prefer to show the deletion of what was checked
     * out over showing what was actually deleted (if that was defined by
     * a higher layer). */
    if (status == svn_wc__db_status_deleted ||
            (base_replace && ! eb->ignore_ancestry))
    {
        apr_hash_t *del_props;
        const svn_checksum_t *del_checksum;
        const char *del_text_abspath;
        const char *del_mimetype;

        if (base_replace && ! eb->ignore_ancestry)
        {
            /* We show a deletion of the information in the BASE layer */
            SVN_ERR(svn_wc__db_base_get_props(&del_props, db, local_abspath,
                                              scratch_pool, scratch_pool));

            del_checksum = base_checksum;
        }
        else
        {
            /* We show a deletion of what was actually deleted */
            SVN_ERR_ASSERT(status == svn_wc__db_status_deleted);

            SVN_ERR(svn_wc__get_pristine_props(&del_props, db, local_abspath,
                                               scratch_pool, scratch_pool));

            SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL,
                                                  NULL, &del_checksum, NULL,
                                                  NULL, db, local_abspath,
                                                  scratch_pool, scratch_pool));
        }

        SVN_ERR_ASSERT(del_checksum != NULL);

        SVN_ERR(svn_wc__db_pristine_get_path(&del_text_abspath, db,
                                             local_abspath, del_checksum,
                                             scratch_pool, scratch_pool));

        if (del_props == NULL)
            del_props = apr_hash_make(scratch_pool);

        del_mimetype = get_prop_mimetype(del_props);

        SVN_ERR(eb->callbacks->file_deleted(NULL, NULL, path,
                                            del_text_abspath,
                                            empty_file,
                                            del_mimetype,
                                            NULL,
                                            del_props,
                                            eb->callback_baton,
                                            scratch_pool));

        if (status == svn_wc__db_status_deleted)
        {
            /* We're here only for showing a delete, so we're done. */
            return SVN_NO_ERROR;
        }
    }

    if (checksum != NULL)
        SVN_ERR(svn_wc__db_pristine_get_path(&pristine_abspath, db, local_abspath,
                                             checksum,
                                             scratch_pool, scratch_pool));
    else if (base_replace && eb->ignore_ancestry)
        SVN_ERR(svn_wc__db_pristine_get_path(&pristine_abspath, db, local_abspath,
                                             base_checksum,
                                             scratch_pool, scratch_pool));
    else
        pristine_abspath = empty_file;

    /* Now deal with showing additions, or the add-half of replacements.
     * If the item is schedule-add *with history*, then we usually want
     * to see the usual working vs. text-base comparison, which will show changes
     * made since the file was copied.  But in case we're showing copies as adds,
     * we need to compare the copied file to the empty file. If we're doing a git
     * diff, and the file was copied, we need to report the file as added and
     * diff it against the text base, so that a "copied" git diff header, and
     * possibly a diff against the copy source, will be generated for it. */
    if ((! base_replace && status == svn_wc__db_status_added) ||
            (base_replace && ! eb->ignore_ancestry) ||
            ((status == svn_wc__db_status_copied ||
              status == svn_wc__db_status_moved_here) &&
             (eb->show_copies_as_adds || eb->use_git_diff_format)))
    {
        const char *translated = NULL;
        apr_hash_t *pristine_props;
        apr_hash_t *actual_props;
        const char *actual_mimetype;
        apr_array_header_t *propchanges;


        /* Get svn:mime-type from ACTUAL props of PATH. */
        SVN_ERR(svn_wc__get_actual_props(&actual_props, db, local_abspath,
                                         scratch_pool, scratch_pool));
        actual_mimetype = get_prop_mimetype(actual_props);

        /* Set the original properties to empty, then compute "changes" from
           that. Essentially, all ACTUAL props will be "added".  */
        pristine_props = apr_hash_make(scratch_pool);
        SVN_ERR(svn_prop_diffs(&propchanges, actual_props, pristine_props,
                               scratch_pool));

        SVN_ERR(svn_wc__internal_translated_file(
                    &translated, local_abspath, db, local_abspath,
                    SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,
                    eb->cancel_func, eb->cancel_baton,
                    scratch_pool, scratch_pool));

        SVN_ERR(eb->callbacks->file_added(NULL, NULL, NULL, path,
                                          (! eb->show_copies_as_adds &&
                                           eb->use_git_diff_format &&
                                           status != svn_wc__db_status_added) ?
                                          pristine_abspath : empty_file,
                                          translated,
                                          0, revision,
                                          NULL,
                                          actual_mimetype,
                                          original_repos_relpath,
                                          SVN_INVALID_REVNUM, propchanges,
                                          pristine_props, eb->callback_baton,
                                          scratch_pool));
    }
    else
    {
        const char *translated = NULL;
        apr_hash_t *pristine_props;
        const char *pristine_mimetype;
        const char *actual_mimetype;
        apr_hash_t *actual_props;
        apr_array_header_t *propchanges;
        svn_boolean_t modified;

        /* Here we deal with showing pure modifications. */
        SVN_ERR(svn_wc__internal_file_modified_p(&modified, db, local_abspath,
                FALSE, scratch_pool));
        if (modified)
        {
            /* Note that this might be the _second_ time we translate
               the file, as svn_wc__text_modified_internal_p() might have used a
               tmp translated copy too.  But what the heck, diff is
               already expensive, translating twice for the sake of code
               modularity is liveable. */
            SVN_ERR(svn_wc__internal_translated_file(
                        &translated, local_abspath, db, local_abspath,
                        SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,
                        eb->cancel_func, eb->cancel_baton,
                        scratch_pool, scratch_pool));
        }

        /* Get the properties, the svn:mime-type values, and compute the
           differences between the two.  */
        if (base_replace
                && eb->ignore_ancestry)
        {
            /* We don't want the normal pristine properties (which are
               from the WORKING tree). We want the pristines associated
               with the BASE tree, which are saved as "revert" props.  */
            SVN_ERR(svn_wc__db_base_get_props(&pristine_props,
                                              db, local_abspath,
                                              scratch_pool, scratch_pool));
        }
        else
        {
            /* We can only fetch the pristine props (from BASE or WORKING) if
               the node has not been replaced, or it was copied/moved here.  */
            SVN_ERR_ASSERT(!replaced
                           || status == svn_wc__db_status_copied
                           || status == svn_wc__db_status_moved_here);

            SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db,
                                                   local_abspath,
                                                   scratch_pool, scratch_pool));

            /* baseprops will be NULL for added nodes */
            if (!pristine_props)
                pristine_props = apr_hash_make(scratch_pool);
        }
        pristine_mimetype = get_prop_mimetype(pristine_props);

        SVN_ERR(svn_wc__db_read_props(&actual_props, db, local_abspath,
                                      scratch_pool, scratch_pool));
        actual_mimetype = get_prop_mimetype(actual_props);

        SVN_ERR(svn_prop_diffs(&propchanges, actual_props, pristine_props,
                               scratch_pool));

        if (modified || propchanges->nelts > 0)
        {
            SVN_ERR(eb->callbacks->file_changed(NULL, NULL, NULL,
                                                path,
                                                modified ? pristine_abspath
                                                : NULL,
                                                translated,
                                                revision,
                                                SVN_INVALID_REVNUM,
                                                pristine_mimetype,
                                                actual_mimetype,
                                                propchanges,
                                                pristine_props,
                                                eb->callback_baton,
                                                scratch_pool));
        }
    }

    return SVN_NO_ERROR;
}