📄 props.c
字号:
/* * props.c : routines dealing with properties in the working copy * * ==================================================================== * Copyright (c) 2000-2006 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_general.h>#include "svn_types.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_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 "lock.h"#include "svn_private_config.h"/*---------------------------------------------------------------------*//*** Deducing local changes to properties ***//*---------------------------------------------------------------------*//*** 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_error_t *err; apr_file_t *propfile = NULL; err = svn_io_file_open(&propfile, propfile_path, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool); if (err && (APR_STATUS_IS_ENOENT(err->apr_err) || APR_STATUS_IS_ENOTDIR(err->apr_err))) { svn_error_clear(err); return SVN_NO_ERROR; } SVN_ERR(err); SVN_ERR_W(svn_hash_read(hash, propfile, pool), apr_psprintf(pool, _("Can't parse '%s'"), svn_path_local_style(propfile_path, pool))); 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)); if (apr_hash_count(hash) != 0) SVN_ERR_W(svn_hash_write(hash, prop_tmp, pool), apr_psprintf(pool, _("Can't write property hash to '%s'"), svn_path_local_style(propfile_path, pool))); SVN_ERR(svn_io_file_close(prop_tmp, pool)); return SVN_NO_ERROR;}/*---------------------------------------------------------------------*//*** Misc ***//* Opens reject temporary file for FULL_PATH. */static svn_error_t *open_reject_tmp_file(apr_file_t **fp, const char **reject_tmp_path, const char *full_path, svn_wc_adm_access_t *adm_access, svn_boolean_t is_dir, apr_pool_t *pool){ const char *tmp_path, *tmp_name; /* Get path to /temporary/ local prop file */ SVN_ERR(svn_wc__prop_path(&tmp_path, full_path, is_dir ? svn_node_dir : svn_node_file, TRUE, pool)); /* Reserve a .prej file based on it. */ SVN_ERR(svn_io_open_unique_file2(fp, reject_tmp_path, tmp_path, SVN_WC__PROP_REJ_EXT, svn_io_file_del_none, pool)); /* reject_tmp_path is an absolute path at this point, but that's no good for us. We need to convert this path to a *relative* path to use in the logfile. */ tmp_name = svn_path_basename(*reject_tmp_path, pool); if (is_dir) { /* Dealing with directory "path" */ *reject_tmp_path = svn_wc__adm_path("", TRUE, /* use tmp */ pool, tmp_name, NULL); } else { /* Dealing with file "path/name" */ *reject_tmp_path = svn_wc__adm_path("", TRUE, pool, SVN_WC__ADM_PROPS, tmp_name, NULL); } return SVN_NO_ERROR;}/* 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 char *conflict_description_native = svn_utf_cstring_from_utf8_fuzzy(conflict_description->data, pool); SVN_ERR(svn_io_file_write_full(fp, conflict_description_native, strlen(conflict_description_native), &written, pool)); return SVN_NO_ERROR;}/* Look up the entry NAME within ADM_ACCESS and see if it has a `current' reject file describing a state of conflict. Set *REJECT_FILE to the name of that file, or to NULL if no such file exists. */static svn_error_t *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_path_local_style(svn_wc_adm_access_path(adm_access), pool)); *reject_file = the_entry->prejfile ? apr_pstrdup(pool, the_entry->prejfile) : NULL; return SVN_NO_ERROR;}/*---------------------------------------------------------------------*//* Build a space separated list of properties that are contained in the hash PROPS and which we want to cache. The string is allocated in POOL. */static const char *build_present_props(apr_hash_t *props, apr_pool_t *pool){ apr_array_header_t *cachable; svn_stringbuf_t *present_props = svn_stringbuf_create("", pool); int i; if (apr_hash_count(props) == 0) return present_props->data; cachable = svn_cstring_split(SVN_WC__CACHABLE_PROPS, " ", TRUE, pool); for (i = 0; i < cachable->nelts; i++) { const char *proptolookfor = APR_ARRAY_IDX(cachable, i, const char *); if (apr_hash_get(props, proptolookfor, APR_HASH_KEY_STRING) != NULL) { svn_stringbuf_appendcstr(present_props, proptolookfor); svn_stringbuf_appendcstr(present_props, " "); } } /* Avoid returning a string with a trailing space. */ svn_stringbuf_chop(present_props, 1); return present_props->data;}/*** Loading regular properties. ***/svn_error_t *svn_wc__load_props(apr_hash_t **base_props_p, apr_hash_t **props_p, svn_wc_adm_access_t *adm_access, const char *name, apr_pool_t *pool){ const char *full_path; const char *access_path = svn_wc_adm_access_path(adm_access); svn_node_kind_t kind; svn_boolean_t has_propcaching = svn_wc__adm_wc_format(adm_access) > SVN_WC__NO_PROPCACHING_VERSION; const svn_wc_entry_t *entry; apr_hash_t *base_props = NULL; /* Silence uninitialized warning. */ if (strcmp(name, SVN_WC_ENTRY_THIS_DIR) == 0) { full_path = access_path; kind = svn_node_dir; } else { full_path = svn_path_join(access_path, name, pool); kind = svn_node_file; } SVN_ERR(svn_wc_entry(&entry, full_path, adm_access, FALSE, pool)); /* If there is no entry, we just return empty hashes, since the property merging can use this function when there is no entry. */ if (! entry) { if (base_props_p) *base_props_p = apr_hash_make(pool); if (props_p) *props_p = apr_hash_make(pool); return SVN_NO_ERROR; } /* We will need the base props if the user requested them, OR, our WC has prop caching, the user requested working props and there are no prop mods. */ if (base_props_p || (has_propcaching && ! entry->has_prop_mods && entry->has_props)) { const char *prop_base_path; SVN_ERR(svn_wc__prop_base_path(&prop_base_path, full_path, kind, FALSE, pool)); base_props = apr_hash_make(pool); SVN_ERR(svn_wc__load_prop_file(prop_base_path, base_props, pool)); if (base_props_p) *base_props_p = base_props; } if (props_p) { if (has_propcaching && ! entry->has_prop_mods && entry->has_props) *props_p = apr_hash_copy(pool, base_props); else if (! has_propcaching || entry->has_props) { const char *prop_path; SVN_ERR(svn_wc__prop_path(&prop_path, full_path, kind, FALSE, pool)); *props_p = apr_hash_make(pool); SVN_ERR(svn_wc__load_prop_file(prop_path, *props_p, pool)); } else *props_p = apr_hash_make(pool); } return SVN_NO_ERROR;}/*---------------------------------------------------------------------*//*** Installing new properties. ***/svn_error_t *svn_wc__install_props(svn_stringbuf_t **log_accum, svn_wc_adm_access_t *adm_access, const char *name, apr_hash_t *base_props, apr_hash_t *working_props, svn_boolean_t write_base_props, apr_pool_t *pool){ const char *working_propfile_path, *working_prop_tmp_path; const char *tmp_props, *real_props; const char *full_path; const char *access_path = svn_wc_adm_access_path(adm_access); int access_len = strlen(access_path); apr_array_header_t *prop_diffs; svn_wc_entry_t tmp_entry; svn_node_kind_t kind; /* Non-empty path without trailing slash need an extra slash removed */ if (access_len != 0 && access_path[access_len - 1] != '/') access_len++; if (strcmp(name, SVN_WC_ENTRY_THIS_DIR) == 0) { kind = svn_node_dir; full_path = access_path; } else { kind = svn_node_file; full_path = svn_path_join(access_path, name, pool); } /* Check if the props are modified. */ SVN_ERR(svn_prop_diffs(&prop_diffs, working_props, base_props, pool)); tmp_entry.has_prop_mods = (prop_diffs->nelts > 0); tmp_entry.has_props = (apr_hash_count(working_props) > 0); tmp_entry.cachable_props = SVN_WC__CACHABLE_PROPS; tmp_entry.present_props = build_present_props(working_props, pool); SVN_ERR(svn_wc__loggy_entry_modify(log_accum, adm_access, name, &tmp_entry, SVN_WC__ENTRY_MODIFY_HAS_PROPS | SVN_WC__ENTRY_MODIFY_HAS_PROP_MODS | SVN_WC__ENTRY_MODIFY_CACHABLE_PROPS | SVN_WC__ENTRY_MODIFY_PRESENT_PROPS, pool)); /* Write our property hashes into temporary files. Notice that the paths computed are ABSOLUTE pathnames, which is what our disk routines require. */ SVN_ERR(svn_wc__prop_path(&working_propfile_path, full_path, kind, FALSE, pool)); real_props = apr_pstrdup(pool, working_propfile_path + access_len); if (tmp_entry.has_prop_mods) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -