aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/translate.c')
-rw-r--r--subversion/libsvn_wc/translate.c452
1 files changed, 452 insertions, 0 deletions
diff --git a/subversion/libsvn_wc/translate.c b/subversion/libsvn_wc/translate.c
new file mode 100644
index 000000000000..9e0b2656853a
--- /dev/null
+++ b/subversion/libsvn_wc/translate.c
@@ -0,0 +1,452 @@
+/*
+ * translate.c : wc-specific eol/keyword substitution
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <apr_pools.h>
+#include <apr_file_io.h>
+#include <apr_strings.h>
+
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_path.h"
+#include "svn_error.h"
+#include "svn_subst.h"
+#include "svn_io.h"
+#include "svn_props.h"
+
+#include "wc.h"
+#include "adm_files.h"
+#include "translate.h"
+#include "props.h"
+
+#include "svn_private_config.h"
+#include "private/svn_wc_private.h"
+
+
+
+/* */
+static svn_error_t *
+read_handler_unsupported(void *baton, char *buffer, apr_size_t *len)
+{
+ SVN_ERR_MALFUNCTION();
+}
+
+/* */
+static svn_error_t *
+write_handler_unsupported(void *baton, const char *buffer, apr_size_t *len)
+{
+ SVN_ERR_MALFUNCTION();
+}
+
+svn_error_t *
+svn_wc__internal_translated_stream(svn_stream_t **stream,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *versioned_abspath,
+ apr_uint32_t flags,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t special;
+ svn_boolean_t to_nf = flags & SVN_WC_TRANSLATE_TO_NF;
+ svn_subst_eol_style_t style;
+ const char *eol;
+ apr_hash_t *keywords;
+ svn_boolean_t repair_forced = flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
+
+ SVN_ERR(svn_wc__get_translate_info(&style, &eol,
+ &keywords,
+ &special,
+ db, versioned_abspath, NULL, FALSE,
+ scratch_pool, scratch_pool));
+
+ if (special)
+ {
+ if (to_nf)
+ return svn_subst_read_specialfile(stream, local_abspath, result_pool,
+ scratch_pool);
+
+ return svn_subst_create_specialfile(stream, local_abspath, result_pool,
+ scratch_pool);
+ }
+
+ if (to_nf)
+ SVN_ERR(svn_stream_open_readonly(stream, local_abspath, result_pool,
+ scratch_pool));
+ else
+ {
+ apr_file_t *file;
+
+ /* We don't want the "open-exclusively" feature of the normal
+ svn_stream_open_writable interface. Do this manually. */
+ SVN_ERR(svn_io_file_open(&file, local_abspath,
+ APR_CREATE | APR_WRITE | APR_BUFFERED,
+ APR_OS_DEFAULT, result_pool));
+ *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
+ }
+
+ if (svn_subst_translation_required(style, eol, keywords, special, TRUE))
+ {
+ if (to_nf)
+ {
+ if (style == svn_subst_eol_style_native)
+ eol = SVN_SUBST_NATIVE_EOL_STR;
+ else if (style == svn_subst_eol_style_fixed)
+ repair_forced = TRUE;
+ else if (style != svn_subst_eol_style_none)
+ return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
+
+ /* Wrap the stream to translate to normal form */
+ *stream = svn_subst_stream_translated(*stream,
+ eol,
+ repair_forced,
+ keywords,
+ FALSE /* expand */,
+ result_pool);
+
+ /* Enforce our contract. TO_NF streams are readonly */
+ svn_stream_set_write(*stream, write_handler_unsupported);
+ }
+ else
+ {
+ *stream = svn_subst_stream_translated(*stream, eol, TRUE,
+ keywords, TRUE, result_pool);
+
+ /* Enforce our contract. FROM_NF streams are write-only */
+ svn_stream_set_read(*stream, read_handler_unsupported);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__internal_translated_file(const char **xlated_abspath,
+ const char *src_abspath,
+ svn_wc__db_t *db,
+ const char *versioned_abspath,
+ apr_uint32_t flags,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_subst_eol_style_t style;
+ const char *eol;
+ apr_hash_t *keywords;
+ svn_boolean_t special;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
+ SVN_ERR(svn_wc__get_translate_info(&style, &eol,
+ &keywords,
+ &special,
+ db, versioned_abspath, NULL, FALSE,
+ scratch_pool, scratch_pool));
+
+ if (! svn_subst_translation_required(style, eol, keywords, special, TRUE)
+ && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY)))
+ {
+ /* Translation would be a no-op, so return the original file. */
+ *xlated_abspath = src_abspath;
+ }
+ else /* some translation (or copying) is necessary */
+ {
+ const char *tmp_dir;
+ const char *tmp_vfile;
+ svn_boolean_t repair_forced
+ = (flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR) != 0;
+ svn_boolean_t expand = (flags & SVN_WC_TRANSLATE_TO_NF) == 0;
+
+ if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP)
+ tmp_dir = NULL;
+ else
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_vfile, tmp_dir,
+ (flags & SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP)
+ ? svn_io_file_del_none
+ : svn_io_file_del_on_pool_cleanup,
+ result_pool, scratch_pool));
+
+ /* ### ugh. the repair behavior does NOT match the docstring. bleah.
+ ### all of these translation functions are crap and should go
+ ### away anyways. we'll just deprecate most of the functions and
+ ### properly document the survivors */
+
+ if (expand)
+ {
+ /* from normal form */
+
+ repair_forced = TRUE;
+ }
+ else
+ {
+ /* to normal form */
+
+ if (style == svn_subst_eol_style_native)
+ eol = SVN_SUBST_NATIVE_EOL_STR;
+ else if (style == svn_subst_eol_style_fixed)
+ repair_forced = TRUE;
+ else if (style != svn_subst_eol_style_none)
+ return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
+ }
+
+ SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile,
+ eol, repair_forced,
+ keywords,
+ expand,
+ special,
+ cancel_func, cancel_baton,
+ result_pool));
+
+ *xlated_abspath = tmp_vfile;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+void
+svn_wc__eol_value_from_string(const char **value, const char *eol)
+{
+ if (eol == NULL)
+ *value = NULL;
+ else if (! strcmp("\n", eol))
+ *value = "LF";
+ else if (! strcmp("\r", eol))
+ *value = "CR";
+ else if (! strcmp("\r\n", eol))
+ *value = "CRLF";
+ else
+ *value = NULL;
+}
+
+svn_error_t *
+svn_wc__get_translate_info(svn_subst_eol_style_t *style,
+ const char **eol,
+ apr_hash_t **keywords,
+ svn_boolean_t *special,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_hash_t *props,
+ svn_boolean_t for_normalization,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *propval;
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ if (props == NULL)
+ SVN_ERR(svn_wc__get_actual_props(&props, db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (eol)
+ {
+ propval = svn_prop_get_value(props, SVN_PROP_EOL_STYLE);
+
+ svn_subst_eol_style_from_value(style, eol, propval);
+ }
+
+ if (keywords)
+ {
+ propval = svn_prop_get_value(props, SVN_PROP_KEYWORDS);
+
+ if (!propval || *propval == '\0')
+ *keywords = NULL;
+ else
+ SVN_ERR(svn_wc__expand_keywords(keywords,
+ db, local_abspath, NULL,
+ propval, for_normalization,
+ result_pool, scratch_pool));
+ }
+ if (special)
+ {
+ propval = svn_prop_get_value(props, SVN_PROP_SPECIAL);
+
+ *special = (propval != NULL);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__expand_keywords(apr_hash_t **keywords,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *wri_abspath,
+ const char *keyword_list,
+ svn_boolean_t for_normalization,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_revnum_t changed_rev;
+ apr_time_t changed_date;
+ const char *changed_author;
+ const char *url;
+ const char *repos_root_url;
+
+ if (! for_normalization)
+ {
+ const char *repos_relpath;
+
+ SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, &repos_relpath,
+ &repos_root_url, NULL, &changed_rev,
+ &changed_date, &changed_author, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (repos_relpath)
+ url = svn_path_url_add_component2(repos_root_url, repos_relpath,
+ scratch_pool);
+ else
+ SVN_ERR(svn_wc__db_read_url(&url, db, local_abspath, scratch_pool,
+ scratch_pool));
+ }
+ else
+ {
+ url = "";
+ changed_rev = SVN_INVALID_REVNUM;
+ changed_date = 0;
+ changed_author = "";
+ repos_root_url = "";
+ }
+
+ SVN_ERR(svn_subst_build_keywords3(keywords, keyword_list,
+ apr_psprintf(scratch_pool, "%ld",
+ changed_rev),
+ url, repos_root_url,
+ changed_date, changed_author,
+ result_pool));
+
+ if (apr_hash_count(*keywords) == 0)
+ *keywords = NULL;
+
+ return SVN_NO_ERROR;
+}
+
+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;
+}