2 * translate.c : wc-specific eol/keyword substitution
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
29 #include <apr_pools.h>
30 #include <apr_file_io.h>
31 #include <apr_strings.h>
33 #include "svn_private_config.h"
34 #include "svn_types.h"
35 #include "svn_string.h"
36 #include "svn_dirent_uri.h"
39 #include "svn_error.h"
40 #include "svn_subst.h"
42 #include "svn_props.h"
45 #include "adm_files.h"
46 #include "translate.h"
49 #include "private/svn_wc_private.h"
53 svn_wc__internal_translated_stream(svn_stream_t **stream,
55 const char *local_abspath,
56 const char *versioned_abspath,
58 apr_pool_t *result_pool,
59 apr_pool_t *scratch_pool)
61 svn_boolean_t special;
62 svn_boolean_t to_nf = flags & SVN_WC_TRANSLATE_TO_NF;
63 svn_subst_eol_style_t style;
66 svn_boolean_t repair_forced = flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR;
68 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
69 SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
71 SVN_ERR(svn_wc__get_translate_info(&style, &eol,
74 db, versioned_abspath, NULL, FALSE,
75 scratch_pool, scratch_pool));
80 return svn_subst_read_specialfile(stream, local_abspath, result_pool,
83 return svn_subst_create_specialfile(stream, local_abspath, result_pool,
88 SVN_ERR(svn_stream_open_readonly(stream, local_abspath, result_pool,
94 /* We don't want the "open-exclusively" feature of the normal
95 svn_stream_open_writable interface. Do this manually. */
96 SVN_ERR(svn_io_file_open(&file, local_abspath,
97 APR_CREATE | APR_WRITE | APR_BUFFERED,
98 APR_OS_DEFAULT, result_pool));
99 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
102 if (svn_subst_translation_required(style, eol, keywords, special, TRUE))
106 if (style == svn_subst_eol_style_native)
107 eol = SVN_SUBST_NATIVE_EOL_STR;
108 else if (style == svn_subst_eol_style_fixed)
109 repair_forced = TRUE;
110 else if (style != svn_subst_eol_style_none)
111 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
113 /* Wrap the stream to translate to normal form */
114 *stream = svn_subst_stream_translated(*stream,
121 /* streams enforce our contract that TO_NF streams are read-only
122 * by returning SVN_ERR_STREAM_NOT_SUPPORTED when trying to
127 *stream = svn_subst_stream_translated(*stream, eol, TRUE,
128 keywords, TRUE, result_pool);
130 /* streams enforce our contract that FROM_NF streams are write-only
131 * by returning SVN_ERR_STREAM_NOT_SUPPORTED when trying to
141 svn_wc__internal_translated_file(const char **xlated_abspath,
142 const char *src_abspath,
144 const char *versioned_abspath,
146 svn_cancel_func_t cancel_func,
148 apr_pool_t *result_pool,
149 apr_pool_t *scratch_pool)
151 svn_subst_eol_style_t style;
153 apr_hash_t *keywords;
154 svn_boolean_t special;
156 SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
157 SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
158 SVN_ERR(svn_wc__get_translate_info(&style, &eol,
161 db, versioned_abspath, NULL, FALSE,
162 scratch_pool, scratch_pool));
164 if (! svn_subst_translation_required(style, eol, keywords, special, TRUE)
165 && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY)))
167 /* Translation would be a no-op, so return the original file. */
168 *xlated_abspath = src_abspath;
170 else /* some translation (or copying) is necessary */
173 const char *tmp_vfile;
174 svn_boolean_t repair_forced
175 = (flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR) != 0;
176 svn_boolean_t expand = (flags & SVN_WC_TRANSLATE_TO_NF) == 0;
178 if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP)
181 SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath,
182 scratch_pool, scratch_pool));
184 SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_vfile, tmp_dir,
185 (flags & SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP)
186 ? svn_io_file_del_none
187 : svn_io_file_del_on_pool_cleanup,
188 result_pool, scratch_pool));
190 /* ### ugh. the repair behavior does NOT match the docstring. bleah.
191 ### all of these translation functions are crap and should go
192 ### away anyways. we'll just deprecate most of the functions and
193 ### properly document the survivors */
197 /* from normal form */
199 repair_forced = TRUE;
205 if (style == svn_subst_eol_style_native)
206 eol = SVN_SUBST_NATIVE_EOL_STR;
207 else if (style == svn_subst_eol_style_fixed)
208 repair_forced = TRUE;
209 else if (style != svn_subst_eol_style_none)
210 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
213 SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile,
218 cancel_func, cancel_baton,
221 *xlated_abspath = tmp_vfile;
228 svn_wc__eol_value_from_string(const char **value, const char *eol)
232 else if (! strcmp("\n", eol))
234 else if (! strcmp("\r", eol))
236 else if (! strcmp("\r\n", eol))
243 svn_wc__get_translate_info(svn_subst_eol_style_t *style,
245 apr_hash_t **keywords,
246 svn_boolean_t *special,
248 const char *local_abspath,
250 svn_boolean_t for_normalization,
251 apr_pool_t *result_pool,
252 apr_pool_t *scratch_pool)
255 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
258 SVN_ERR(svn_wc__get_actual_props(&props, db, local_abspath,
259 scratch_pool, scratch_pool));
263 propval = svn_prop_get_value(props, SVN_PROP_EOL_STYLE);
265 svn_subst_eol_style_from_value(style, eol, propval);
270 propval = svn_prop_get_value(props, SVN_PROP_KEYWORDS);
272 if (!propval || *propval == '\0')
275 SVN_ERR(svn_wc__expand_keywords(keywords,
276 db, local_abspath, NULL,
277 propval, for_normalization,
278 result_pool, scratch_pool));
282 propval = svn_prop_get_value(props, SVN_PROP_SPECIAL);
284 *special = (propval != NULL);
291 svn_wc__expand_keywords(apr_hash_t **keywords,
293 const char *local_abspath,
294 const char *wri_abspath,
295 const char *keyword_list,
296 svn_boolean_t for_normalization,
297 apr_pool_t *result_pool,
298 apr_pool_t *scratch_pool)
300 svn_revnum_t changed_rev;
301 apr_time_t changed_date;
302 const char *changed_author;
304 const char *repos_root_url;
306 if (! for_normalization)
308 const char *repos_relpath;
310 SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, &repos_relpath,
311 &repos_root_url, NULL, &changed_rev,
312 &changed_date, &changed_author, NULL,
313 NULL, NULL, NULL, NULL, NULL, NULL,
314 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
315 NULL, NULL, NULL, NULL,
317 scratch_pool, scratch_pool));
319 /* Handle special statuses (e.g. added) */
321 SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
322 &repos_root_url, NULL,
324 scratch_pool, scratch_pool));
326 url = svn_path_url_add_component2(repos_root_url, repos_relpath,
332 changed_rev = SVN_INVALID_REVNUM;
338 SVN_ERR(svn_subst_build_keywords3(keywords, keyword_list,
339 apr_psprintf(scratch_pool, "%ld",
342 changed_date, changed_author,
345 if (apr_hash_count(*keywords) == 0)
352 svn_wc__sync_flags_with_props(svn_boolean_t *did_set,
354 const char *local_abspath,
355 apr_pool_t *scratch_pool)
357 svn_wc__db_status_t status;
358 svn_node_kind_t kind;
359 svn_wc__db_lock_t *lock;
360 apr_hash_t *props = NULL;
361 svn_boolean_t had_props;
362 svn_boolean_t props_mod;
367 /* ### We'll consolidate these info gathering statements in a future
370 SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
371 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
372 NULL, &lock, NULL, NULL, NULL, NULL, NULL,
373 &had_props, &props_mod, NULL, NULL, NULL,
375 scratch_pool, scratch_pool));
377 /* We actually only care about the following flags on files, so just
378 early-out for all other types.
380 Also bail if there is no in-wc representation of the file. */
381 if (kind != svn_node_file
382 || (status != svn_wc__db_status_normal
383 && status != svn_wc__db_status_added))
386 if (props_mod || had_props)
387 SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
392 /* If we get this far, we're going to change *something*, so just set
393 the flag appropriately. */
397 /* Handle the read-write bit. */
398 if (status != svn_wc__db_status_normal
400 || ! svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)
403 SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
407 /* Special case: If we have an uncommitted svn:needs-lock, we don't
408 set the file read_only just yet. That happens upon commit. */
409 apr_hash_t *pristine_props;
412 pristine_props = props;
414 SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
415 scratch_pool, scratch_pool));
417 pristine_props = NULL;
420 && svn_hash_gets(pristine_props, SVN_PROP_NEEDS_LOCK) )
422 && apr_hash_get(props, SVN_PROP_NEEDS_LOCK, APR_HASH_KEY_STRING) )*/
423 SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool));
426 /* Windows doesn't care about the execute bit. */
430 || ! svn_hash_gets(props, SVN_PROP_EXECUTABLE))
432 /* Turn off the execute bit */
433 SVN_ERR(svn_io_set_file_executable(local_abspath, FALSE, FALSE,
437 SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE,