⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 props.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * props.c :  routines dealing with properties in the working copy
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */



#include <stdio.h>       /* temporary, for printf() */
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_tables.h>
#include <apr_file_io.h>
#include <apr_strings.h>
#include <apr_lib.h>
#include <apr_general.h>
#include "svn_types.h"
#include "svn_delta.h"
#include "svn_string.h"
#include "svn_pools.h"
#include "svn_path.h"
#include "svn_xml.h"
#include "svn_error.h"
#include "svn_props.h"
#include "svn_io.h"
#include "svn_hash.h"
#include "svn_wc.h"
#include "svn_time.h"
#include "svn_utf.h"

#include "wc.h"
#include "log.h"
#include "adm_files.h"
#include "entries.h"
#include "props.h"
#include "translate.h"
#include "questions.h"

#include "svn_private_config.h"

/*---------------------------------------------------------------------*/

/*** Deducing local changes to properties ***/

/*---------------------------------------------------------------------*/

/*** Detecting a property conflict ***/


/* Given two propchange objects, return TRUE iff they conflict.  If
   there's a conflict, DESCRIPTION will contain an english description
   of the problem. */

/* For note, here's the table being implemented:

              |  update set     |    update delete   |
  ------------|-----------------|--------------------|
  user set    | conflict iff    |      conflict      |
              |  vals differ    |                    |
  ------------|-----------------|--------------------|
  user delete |   conflict      |      merge         |
              |                 |    (no problem)    |
  ----------------------------------------------------

*/
svn_boolean_t
svn_wc__conflicting_propchanges_p (const svn_string_t **description,
                                   const svn_prop_t *local,
                                   const svn_prop_t *update,
                                   apr_pool_t *pool)
{
  /* We're assuming that whoever called this routine has already
     deduced that local and change2 affect the same property name.
     (After all, if they affect different property names, how can they
     possibly conflict?)  But still, let's make this routine
     `complete' by checking anyway. */
  if (strcmp(local->name, update->name) != 0)
    return FALSE;  /* no conflict */

  /* If one change wants to delete a property and the other wants to
     set it, this is a conflict.  This check covers two bases of our
     chi-square. */
  if ((local->value != NULL) && (update->value == NULL))
    {
      *description =
        svn_string_createf
        (pool,
         _("Property '%s' locally changed to '%s', but update deletes it\n"),
         local->name, local->value->data);
      return TRUE;  /* conflict */
    }
  if ((local->value == NULL) && (update->value != NULL))
    {
      *description =
        svn_string_createf
        (pool,
         _("Property '%s' locally deleted, but update sets it to '%s'\n"),
         local->name, update->value->data);
      return TRUE;  /* conflict */
    }

  /* If both changes delete the same property, there's no conflict.
     It's an implicit merge.  :)  */
  if ((local->value == NULL) && (update->value == NULL))
    return FALSE;  /* no conflict */

  /* If both changes set the property, it's a conflict iff the values
     are different */
  else if (! svn_string_compare (local->value, update->value))
    {
      *description =
        svn_string_createf
        (pool, _("Property '%s' locally changed to '%s', "
                 "but update sets it to '%s'\n"),
         local->name, local->value->data, update->value->data);
      return TRUE;  /* conflict */
    }

  /* values are the same, so another implicit merge. */
  return FALSE;  /* no conflict */
}



/*---------------------------------------------------------------------*/

/*** Reading/writing property hashes from disk ***/

/* The real functionality here is part of libsvn_subr, in hashdump.c.
   But these are convenience routines for use in libsvn_wc. */



/* If PROPFILE_PATH exists (and is a file), assume it's full of
   properties and load this file into HASH.  Otherwise, leave HASH
   untouched.  */
svn_error_t *
svn_wc__load_prop_file (const char *propfile_path,
                        apr_hash_t *hash,
                        apr_pool_t *pool)
{
  svn_node_kind_t kind;

  SVN_ERR (svn_io_check_path (propfile_path, &kind, pool));

  if (kind == svn_node_file)
    {
      /* Ah, this file already has on-disk properties.  Load 'em. */
      apr_file_t *propfile = NULL;

      SVN_ERR (svn_io_file_open (&propfile, propfile_path,
                                 APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
                                 pool));

      SVN_ERR_W (svn_hash_read (hash, propfile, pool),
                 apr_psprintf (pool, _("Can't parse '%s'"), propfile_path));

      SVN_ERR (svn_io_file_close (propfile, pool));
    }

  return SVN_NO_ERROR;
}



/* Given a HASH full of property name/values, write them to a file
   located at PROPFILE_PATH.  */
svn_error_t *
svn_wc__save_prop_file (const char *propfile_path,
                        apr_hash_t *hash,
                        apr_pool_t *pool)
{
  apr_file_t *prop_tmp;

  SVN_ERR (svn_io_file_open (&prop_tmp, propfile_path,
                             (APR_WRITE | APR_CREATE | APR_TRUNCATE
                              | APR_BUFFERED), 
                             APR_OS_DEFAULT, pool));

  SVN_ERR_W (svn_hash_write (hash, prop_tmp, pool),
             apr_psprintf (pool, 
                           _("Can't write property hash to '%s'"),
                           propfile_path));

  SVN_ERR (svn_io_file_close (prop_tmp, pool));

  return SVN_NO_ERROR;
}


/*---------------------------------------------------------------------*/

/*** Misc ***/

/* Assuming FP is a filehandle already open for appending, write
   CONFLICT_DESCRIPTION to file. */
static svn_error_t *
append_prop_conflict (apr_file_t *fp,
                      const svn_string_t *conflict_description,
                      apr_pool_t *pool)
{
  /* TODO:  someday, perhaps prefix each conflict_description with a
     timestamp or something? */
  apr_size_t written;
  const svn_string_t *conflict_description_native;

  SVN_ERR (svn_utf_string_from_utf8 (&conflict_description_native,
                                     conflict_description,
                                     pool));

  SVN_ERR (svn_io_file_write_full (fp, conflict_description_native->data,
                                   conflict_description_native->len, &written,
                                   pool));

  return SVN_NO_ERROR;
}


/* ### not used outside this file. make it static? */
svn_error_t *
svn_wc__get_existing_prop_reject_file (const char **reject_file,
                                       svn_wc_adm_access_t *adm_access,
                                       const char *name,
                                       apr_pool_t *pool)
{
  apr_hash_t *entries;
  const svn_wc_entry_t *the_entry;

  SVN_ERR (svn_wc_entries_read (&entries, adm_access, FALSE, pool));
  the_entry = apr_hash_get (entries, name, APR_HASH_KEY_STRING);

  if (! the_entry)
    return svn_error_createf
      (SVN_ERR_ENTRY_NOT_FOUND, NULL,
       _("Can't find entry '%s' in '%s'"),
       name, svn_wc_adm_access_path (adm_access));

  *reject_file = the_entry->prejfile 
                 ? apr_pstrdup (pool, the_entry->prejfile)
                 : NULL;
  return SVN_NO_ERROR;
}



/*---------------------------------------------------------------------*/

/*** Merging propchanges into the working copy ***/

svn_error_t *
svn_wc_merge_prop_diffs (svn_wc_notify_state_t *state,
                         const char *path,
                         svn_wc_adm_access_t *adm_access,
                         const apr_array_header_t *propchanges,
                         svn_boolean_t base_merge,
                         svn_boolean_t dry_run,
                         apr_pool_t *pool)
{
  const svn_wc_entry_t *entry;
  const char *parent, *base_name;
  svn_stringbuf_t *log_accum;
  apr_file_t *log_fp = NULL;

  SVN_ERR (svn_wc_entry (&entry, path, adm_access, FALSE, pool));
  if (entry == NULL)
    return svn_error_createf (SVN_ERR_UNVERSIONED_RESOURCE, NULL,
                              _("'%s' is not under version control"), path);

  /* Notice that we're not using svn_path_split_if_file(), because
     that looks at the actual working file.  It's existence shouldn't
     matter, so we're looking at entry->kind instead. */
  switch (entry->kind)
    {
    case svn_node_dir:
      parent = path;
      base_name = NULL;
      break;
    case svn_node_file:
      svn_path_split (path, &parent, &base_name, pool);
      break;
    default:
      return SVN_NO_ERROR; /* ### svn_node_none or svn_node_unknown */
    }

  if (! dry_run)
    {
      SVN_ERR (svn_wc__open_adm_file (&log_fp, parent, SVN_WC__ADM_LOG,
                                      (APR_WRITE | APR_CREATE), /* not excl */
                                      pool));
      log_accum = svn_stringbuf_create ("", pool);
    }
  
  /* Note that while this routine does the "real" work, it's only
     prepping tempfiles and writing log commands.  */
  SVN_ERR (svn_wc__merge_prop_diffs (state, adm_access, base_name,
                                     propchanges, base_merge, dry_run,
                                     pool, &log_accum));

  if (! dry_run)
    {
      SVN_ERR_W (svn_io_file_write_full (log_fp, log_accum->data, 
                                         log_accum->len, NULL, pool),
                 apr_psprintf (pool, _("Error writing log for '%s'"), path));

      SVN_ERR (svn_wc__close_adm_file (log_fp, parent, SVN_WC__ADM_LOG,
                                       1, /* sync */ pool));
      SVN_ERR (svn_wc__run_log (adm_access, NULL, pool));
    }

  return SVN_NO_ERROR;
}


svn_error_t *
svn_wc__merge_prop_diffs (svn_wc_notify_state_t *state,
                          svn_wc_adm_access_t *adm_access,
                          const char *name,
                          const apr_array_header_t *propchanges,
                          svn_boolean_t base_merge,
                          svn_boolean_t dry_run,
                          apr_pool_t *pool,
                          svn_stringbuf_t **entry_accum)
{
  int i;
  svn_boolean_t is_dir;
  
  /* Zillions of pathnames to compute!  yeargh!  */
  const char *base_propfile_path, *local_propfile_path;
  const char *base_prop_tmp_path, *local_prop_tmp_path;
  const char *tmp_prop_base, *real_prop_base;
  const char *tmp_props, *real_props;

  const char *access_path = svn_wc_adm_access_path (adm_access);
  int access_len = strlen (access_path);
  int slash;

  const char *entryname;
  const char *full_path;
  
  apr_array_header_t *local_propchanges; /* propchanges that the user
                                            has made since last update */
  apr_hash_t *localhash;   /* all `working' properties */
  apr_hash_t *basehash;    /* all `pristine' properties */

  /* For writing conflicts to a .prej file */
  apr_file_t *reject_fp = NULL;           /* the real conflicts file */
  const char *reject_path = NULL;

  apr_file_t *reject_tmp_fp = NULL;       /* the temporary conflicts file */
  const char *reject_tmp_path = NULL;

  /* Empty path and paths ending in / don't need an extra slash removed */
  if (access_len == 0 || access_path[access_len - 1] == '/')
    slash = 0;
  else
    slash = 1;

  if (name == NULL)
    {
      /* We must be merging props on the directory PATH  */
      entryname = SVN_WC_ENTRY_THIS_DIR;
      full_path = access_path;
      is_dir = TRUE;
    }
  else
    {
      /* We must be merging props on the file PATH/NAME */
      entryname = name;
      full_path = svn_path_join (access_path, name, pool);
      is_dir = FALSE;
    }

  /* Get paths to the local and pristine property files. */
  SVN_ERR (svn_wc__prop_path (&local_propfile_path, full_path, adm_access,
                              FALSE, pool));
  
  SVN_ERR (svn_wc__prop_base_path (&base_propfile_path, full_path, adm_access,
                                   FALSE, pool));

  /* Load the base & working property files into hashes */
  localhash = apr_hash_make (pool);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -