]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_wc/translate.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_wc / translate.c
1 /*
2  * translate.c :  wc-specific eol/keyword substitution
3  *
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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
20  *    under the License.
21  * ====================================================================
22  */
23
24
25 \f
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <apr_pools.h>
30 #include <apr_file_io.h>
31 #include <apr_strings.h>
32
33 #include "svn_types.h"
34 #include "svn_string.h"
35 #include "svn_dirent_uri.h"
36 #include "svn_hash.h"
37 #include "svn_path.h"
38 #include "svn_error.h"
39 #include "svn_subst.h"
40 #include "svn_io.h"
41 #include "svn_props.h"
42
43 #include "wc.h"
44 #include "adm_files.h"
45 #include "translate.h"
46 #include "props.h"
47
48 #include "svn_private_config.h"
49 #include "private/svn_wc_private.h"
50
51
52
53 /* */
54 static svn_error_t *
55 read_handler_unsupported(void *baton, char *buffer, apr_size_t *len)
56 {
57   SVN_ERR_MALFUNCTION();
58 }
59
60 /* */
61 static svn_error_t *
62 write_handler_unsupported(void *baton, const char *buffer, apr_size_t *len)
63 {
64   SVN_ERR_MALFUNCTION();
65 }
66
67 svn_error_t *
68 svn_wc__internal_translated_stream(svn_stream_t **stream,
69                                    svn_wc__db_t *db,
70                                    const char *local_abspath,
71                                    const char *versioned_abspath,
72                                    apr_uint32_t flags,
73                                    apr_pool_t *result_pool,
74                                    apr_pool_t *scratch_pool)
75 {
76   svn_boolean_t special;
77   svn_boolean_t to_nf = flags & SVN_WC_TRANSLATE_TO_NF;
78   svn_subst_eol_style_t style;
79   const char *eol;
80   apr_hash_t *keywords;
81   svn_boolean_t repair_forced = flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR;
82
83   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
84   SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
85
86   SVN_ERR(svn_wc__get_translate_info(&style, &eol,
87                                      &keywords,
88                                      &special,
89                                      db, versioned_abspath, NULL, FALSE,
90                                      scratch_pool, scratch_pool));
91
92   if (special)
93     {
94       if (to_nf)
95         return svn_subst_read_specialfile(stream, local_abspath, result_pool,
96                                           scratch_pool);
97
98       return svn_subst_create_specialfile(stream, local_abspath, result_pool,
99                                           scratch_pool);
100     }
101
102   if (to_nf)
103     SVN_ERR(svn_stream_open_readonly(stream, local_abspath, result_pool,
104                                      scratch_pool));
105   else
106     {
107       apr_file_t *file;
108
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);
115     }
116
117   if (svn_subst_translation_required(style, eol, keywords, special, TRUE))
118     {
119       if (to_nf)
120         {
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);
127
128           /* Wrap the stream to translate to normal form */
129           *stream = svn_subst_stream_translated(*stream,
130                                                 eol,
131                                                 repair_forced,
132                                                 keywords,
133                                                 FALSE /* expand */,
134                                                 result_pool);
135
136           /* Enforce our contract. TO_NF streams are readonly */
137           svn_stream_set_write(*stream, write_handler_unsupported);
138         }
139       else
140         {
141           *stream = svn_subst_stream_translated(*stream, eol, TRUE,
142                                                 keywords, TRUE, result_pool);
143
144           /* Enforce our contract. FROM_NF streams are write-only */
145           svn_stream_set_read(*stream, read_handler_unsupported);
146         }
147     }
148
149   return SVN_NO_ERROR;
150 }
151
152
153 svn_error_t *
154 svn_wc__internal_translated_file(const char **xlated_abspath,
155                                  const char *src_abspath,
156                                  svn_wc__db_t *db,
157                                  const char *versioned_abspath,
158                                  apr_uint32_t flags,
159                                  svn_cancel_func_t cancel_func,
160                                  void *cancel_baton,
161                                  apr_pool_t *result_pool,
162                                  apr_pool_t *scratch_pool)
163 {
164   svn_subst_eol_style_t style;
165   const char *eol;
166   apr_hash_t *keywords;
167   svn_boolean_t special;
168
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,
172                                      &keywords,
173                                      &special,
174                                      db, versioned_abspath, NULL, FALSE,
175                                      scratch_pool, scratch_pool));
176
177   if (! svn_subst_translation_required(style, eol, keywords, special, TRUE)
178       && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY)))
179     {
180       /* Translation would be a no-op, so return the original file. */
181       *xlated_abspath = src_abspath;
182     }
183   else  /* some translation (or copying) is necessary */
184     {
185       const char *tmp_dir;
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;
190
191       if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP)
192         tmp_dir = NULL;
193       else
194         SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath,
195                                                scratch_pool, scratch_pool));
196
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));
202
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 */
207
208       if (expand)
209         {
210           /* from normal form */
211
212           repair_forced = TRUE;
213         }
214       else
215         {
216           /* to normal form */
217
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);
224         }
225
226       SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile,
227                                             eol, repair_forced,
228                                             keywords,
229                                             expand,
230                                             special,
231                                             cancel_func, cancel_baton,
232                                             result_pool));
233
234       *xlated_abspath = tmp_vfile;
235     }
236
237   return SVN_NO_ERROR;
238 }
239
240 void
241 svn_wc__eol_value_from_string(const char **value, const char *eol)
242 {
243   if (eol == NULL)
244     *value = NULL;
245   else if (! strcmp("\n", eol))
246     *value = "LF";
247   else if (! strcmp("\r", eol))
248     *value = "CR";
249   else if (! strcmp("\r\n", eol))
250     *value = "CRLF";
251   else
252     *value = NULL;
253 }
254
255 svn_error_t *
256 svn_wc__get_translate_info(svn_subst_eol_style_t *style,
257                            const char **eol,
258                            apr_hash_t **keywords,
259                            svn_boolean_t *special,
260                            svn_wc__db_t *db,
261                            const char *local_abspath,
262                            apr_hash_t *props,
263                            svn_boolean_t for_normalization,
264                            apr_pool_t *result_pool,
265                            apr_pool_t *scratch_pool)
266 {
267   const char *propval;
268   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
269
270   if (props == NULL)
271     SVN_ERR(svn_wc__get_actual_props(&props, db, local_abspath,
272                                      scratch_pool, scratch_pool));
273
274   if (eol)
275     {
276       propval = svn_prop_get_value(props, SVN_PROP_EOL_STYLE);
277
278       svn_subst_eol_style_from_value(style, eol, propval);
279     }
280
281   if (keywords)
282     {
283       propval = svn_prop_get_value(props, SVN_PROP_KEYWORDS);
284
285       if (!propval || *propval == '\0')
286         *keywords = NULL;
287       else
288         SVN_ERR(svn_wc__expand_keywords(keywords,
289                                         db, local_abspath, NULL,
290                                         propval, for_normalization,
291                                         result_pool, scratch_pool));
292     }
293   if (special)
294     {
295       propval = svn_prop_get_value(props, SVN_PROP_SPECIAL);
296
297       *special = (propval != NULL);
298     }
299
300   return SVN_NO_ERROR;
301 }
302
303 svn_error_t *
304 svn_wc__expand_keywords(apr_hash_t **keywords,
305                         svn_wc__db_t *db,
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)
312 {
313   svn_revnum_t changed_rev;
314   apr_time_t changed_date;
315   const char *changed_author;
316   const char *url;
317   const char *repos_root_url;
318
319   if (! for_normalization)
320     {
321       const char *repos_relpath;
322
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,
329                                    db, local_abspath,
330                                    scratch_pool, scratch_pool));
331
332       if (repos_relpath)
333         url = svn_path_url_add_component2(repos_root_url, repos_relpath,
334                                           scratch_pool);
335       else
336          SVN_ERR(svn_wc__db_read_url(&url, db, local_abspath, scratch_pool,
337                                      scratch_pool));
338     }
339   else
340     {
341       url = "";
342       changed_rev = SVN_INVALID_REVNUM;
343       changed_date = 0;
344       changed_author = "";
345       repos_root_url = "";
346     }
347
348   SVN_ERR(svn_subst_build_keywords3(keywords, keyword_list,
349                                     apr_psprintf(scratch_pool, "%ld",
350                                                  changed_rev),
351                                     url, repos_root_url,
352                                     changed_date, changed_author,
353                                     result_pool));
354
355   if (apr_hash_count(*keywords) == 0)
356     *keywords = NULL;
357
358   return SVN_NO_ERROR;
359 }
360
361 svn_error_t *
362 svn_wc__sync_flags_with_props(svn_boolean_t *did_set,
363                               svn_wc__db_t *db,
364                               const char *local_abspath,
365                               apr_pool_t *scratch_pool)
366 {
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;
373
374   if (did_set)
375     *did_set = FALSE;
376
377   /* ### We'll consolidate these info gathering statements in a future
378          commit. */
379
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,
384                                db, local_abspath,
385                                scratch_pool, scratch_pool));
386
387   /* We actually only care about the following flags on files, so just
388      early-out for all other types.
389
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))
394     return SVN_NO_ERROR;
395
396   if (props_mod || had_props)
397     SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
398                                   scratch_pool));
399   else
400     props = NULL;
401
402   /* If we get this far, we're going to change *something*, so just set
403      the flag appropriately. */
404   if (did_set)
405     *did_set = TRUE;
406
407   /* Handle the read-write bit. */
408   if (status != svn_wc__db_status_normal
409       || props == NULL
410       || ! svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)
411       || lock)
412     {
413       SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
414     }
415   else
416     {
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;
420
421       if (! props_mod)
422         pristine_props = props;
423       else if (had_props)
424         SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
425                                                 scratch_pool, scratch_pool));
426       else
427         pristine_props = NULL;
428
429       if (pristine_props
430             && svn_hash_gets(pristine_props, SVN_PROP_NEEDS_LOCK) )
431             /*&& props
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));
434     }
435
436 /* Windows doesn't care about the execute bit. */
437 #ifndef WIN32
438
439   if (props == NULL
440       || ! svn_hash_gets(props, SVN_PROP_EXECUTABLE))
441     {
442       /* Turn off the execute bit */
443       SVN_ERR(svn_io_set_file_executable(local_abspath, FALSE, FALSE,
444                                          scratch_pool));
445     }
446   else
447     SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE,
448                                        scratch_pool));
449 #endif
450
451   return SVN_NO_ERROR;
452 }