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_types.h"
34 #include "svn_string.h"
35 #include "svn_dirent_uri.h"
38 #include "svn_error.h"
39 #include "svn_subst.h"
41 #include "svn_props.h"
44 #include "adm_files.h"
45 #include "translate.h"
48 #include "svn_private_config.h"
49 #include "private/svn_wc_private.h"
55 read_handler_unsupported(void *baton, char *buffer, apr_size_t *len)
57 SVN_ERR_MALFUNCTION();
62 write_handler_unsupported(void *baton, const char *buffer, apr_size_t *len)
64 SVN_ERR_MALFUNCTION();
68 svn_wc__internal_translated_stream(svn_stream_t **stream,
70 const char *local_abspath,
71 const char *versioned_abspath,
73 apr_pool_t *result_pool,
74 apr_pool_t *scratch_pool)
76 svn_boolean_t special;
77 svn_boolean_t to_nf = flags & SVN_WC_TRANSLATE_TO_NF;
78 svn_subst_eol_style_t style;
81 svn_boolean_t repair_forced = flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR;
83 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
84 SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
86 SVN_ERR(svn_wc__get_translate_info(&style, &eol,
89 db, versioned_abspath, NULL, FALSE,
90 scratch_pool, scratch_pool));
95 return svn_subst_read_specialfile(stream, local_abspath, result_pool,
98 return svn_subst_create_specialfile(stream, local_abspath, result_pool,
103 SVN_ERR(svn_stream_open_readonly(stream, local_abspath, result_pool,
109 /* We don't want the "open-exclusively" feature of the normal
110 svn_stream_open_writable interface. Do this manually. */
111 SVN_ERR(svn_io_file_open(&file, local_abspath,
112 APR_CREATE | APR_WRITE | APR_BUFFERED,
113 APR_OS_DEFAULT, result_pool));
114 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
117 if (svn_subst_translation_required(style, eol, keywords, special, TRUE))
121 if (style == svn_subst_eol_style_native)
122 eol = SVN_SUBST_NATIVE_EOL_STR;
123 else if (style == svn_subst_eol_style_fixed)
124 repair_forced = TRUE;
125 else if (style != svn_subst_eol_style_none)
126 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
128 /* Wrap the stream to translate to normal form */
129 *stream = svn_subst_stream_translated(*stream,
136 /* Enforce our contract. TO_NF streams are readonly */
137 svn_stream_set_write(*stream, write_handler_unsupported);
141 *stream = svn_subst_stream_translated(*stream, eol, TRUE,
142 keywords, TRUE, result_pool);
144 /* Enforce our contract. FROM_NF streams are write-only */
145 svn_stream_set_read(*stream, read_handler_unsupported);
154 svn_wc__internal_translated_file(const char **xlated_abspath,
155 const char *src_abspath,
157 const char *versioned_abspath,
159 svn_cancel_func_t cancel_func,
161 apr_pool_t *result_pool,
162 apr_pool_t *scratch_pool)
164 svn_subst_eol_style_t style;
166 apr_hash_t *keywords;
167 svn_boolean_t special;
169 SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
170 SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
171 SVN_ERR(svn_wc__get_translate_info(&style, &eol,
174 db, versioned_abspath, NULL, FALSE,
175 scratch_pool, scratch_pool));
177 if (! svn_subst_translation_required(style, eol, keywords, special, TRUE)
178 && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY)))
180 /* Translation would be a no-op, so return the original file. */
181 *xlated_abspath = src_abspath;
183 else /* some translation (or copying) is necessary */
186 const char *tmp_vfile;
187 svn_boolean_t repair_forced
188 = (flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR) != 0;
189 svn_boolean_t expand = (flags & SVN_WC_TRANSLATE_TO_NF) == 0;
191 if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP)
194 SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath,
195 scratch_pool, scratch_pool));
197 SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_vfile, tmp_dir,
198 (flags & SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP)
199 ? svn_io_file_del_none
200 : svn_io_file_del_on_pool_cleanup,
201 result_pool, scratch_pool));
203 /* ### ugh. the repair behavior does NOT match the docstring. bleah.
204 ### all of these translation functions are crap and should go
205 ### away anyways. we'll just deprecate most of the functions and
206 ### properly document the survivors */
210 /* from normal form */
212 repair_forced = TRUE;
218 if (style == svn_subst_eol_style_native)
219 eol = SVN_SUBST_NATIVE_EOL_STR;
220 else if (style == svn_subst_eol_style_fixed)
221 repair_forced = TRUE;
222 else if (style != svn_subst_eol_style_none)
223 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
226 SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile,
231 cancel_func, cancel_baton,
234 *xlated_abspath = tmp_vfile;
241 svn_wc__eol_value_from_string(const char **value, const char *eol)
245 else if (! strcmp("\n", eol))
247 else if (! strcmp("\r", eol))
249 else if (! strcmp("\r\n", eol))
256 svn_wc__get_translate_info(svn_subst_eol_style_t *style,
258 apr_hash_t **keywords,
259 svn_boolean_t *special,
261 const char *local_abspath,
263 svn_boolean_t for_normalization,
264 apr_pool_t *result_pool,
265 apr_pool_t *scratch_pool)
268 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
271 SVN_ERR(svn_wc__get_actual_props(&props, db, local_abspath,
272 scratch_pool, scratch_pool));
276 propval = svn_prop_get_value(props, SVN_PROP_EOL_STYLE);
278 svn_subst_eol_style_from_value(style, eol, propval);
283 propval = svn_prop_get_value(props, SVN_PROP_KEYWORDS);
285 if (!propval || *propval == '\0')
288 SVN_ERR(svn_wc__expand_keywords(keywords,
289 db, local_abspath, NULL,
290 propval, for_normalization,
291 result_pool, scratch_pool));
295 propval = svn_prop_get_value(props, SVN_PROP_SPECIAL);
297 *special = (propval != NULL);
304 svn_wc__expand_keywords(apr_hash_t **keywords,
306 const char *local_abspath,
307 const char *wri_abspath,
308 const char *keyword_list,
309 svn_boolean_t for_normalization,
310 apr_pool_t *result_pool,
311 apr_pool_t *scratch_pool)
313 svn_revnum_t changed_rev;
314 apr_time_t changed_date;
315 const char *changed_author;
317 const char *repos_root_url;
319 if (! for_normalization)
321 const char *repos_relpath;
323 SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, &repos_relpath,
324 &repos_root_url, NULL, &changed_rev,
325 &changed_date, &changed_author, NULL,
326 NULL, NULL, NULL, NULL, NULL, NULL,
327 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
328 NULL, NULL, NULL, NULL,
330 scratch_pool, scratch_pool));
333 url = svn_path_url_add_component2(repos_root_url, repos_relpath,
336 SVN_ERR(svn_wc__db_read_url(&url, db, local_abspath, scratch_pool,
342 changed_rev = SVN_INVALID_REVNUM;
348 SVN_ERR(svn_subst_build_keywords3(keywords, keyword_list,
349 apr_psprintf(scratch_pool, "%ld",
352 changed_date, changed_author,
355 if (apr_hash_count(*keywords) == 0)
362 svn_wc__sync_flags_with_props(svn_boolean_t *did_set,
364 const char *local_abspath,
365 apr_pool_t *scratch_pool)
367 svn_wc__db_status_t status;
368 svn_node_kind_t kind;
369 svn_wc__db_lock_t *lock;
370 apr_hash_t *props = NULL;
371 svn_boolean_t had_props;
372 svn_boolean_t props_mod;
377 /* ### We'll consolidate these info gathering statements in a future
380 SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
381 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
382 NULL, &lock, NULL, NULL, NULL, NULL, NULL,
383 &had_props, &props_mod, NULL, NULL, NULL,
385 scratch_pool, scratch_pool));
387 /* We actually only care about the following flags on files, so just
388 early-out for all other types.
390 Also bail if there is no in-wc representation of the file. */
391 if (kind != svn_node_file
392 || (status != svn_wc__db_status_normal
393 && status != svn_wc__db_status_added))
396 if (props_mod || had_props)
397 SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
402 /* If we get this far, we're going to change *something*, so just set
403 the flag appropriately. */
407 /* Handle the read-write bit. */
408 if (status != svn_wc__db_status_normal
410 || ! svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)
413 SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
417 /* Special case: If we have an uncommitted svn:needs-lock, we don't
418 set the file read_only just yet. That happens upon commit. */
419 apr_hash_t *pristine_props;
422 pristine_props = props;
424 SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
425 scratch_pool, scratch_pool));
427 pristine_props = NULL;
430 && svn_hash_gets(pristine_props, SVN_PROP_NEEDS_LOCK) )
432 && apr_hash_get(props, SVN_PROP_NEEDS_LOCK, APR_HASH_KEY_STRING) )*/
433 SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool));
436 /* Windows doesn't care about the execute bit. */
440 || ! svn_hash_gets(props, SVN_PROP_EXECUTABLE))
442 /* Turn off the execute bit */
443 SVN_ERR(svn_io_set_file_executable(local_abspath, FALSE, FALSE,
447 SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE,