]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_wc/translate.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.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_private_config.h"
34 #include "svn_types.h"
35 #include "svn_string.h"
36 #include "svn_dirent_uri.h"
37 #include "svn_hash.h"
38 #include "svn_path.h"
39 #include "svn_error.h"
40 #include "svn_subst.h"
41 #include "svn_io.h"
42 #include "svn_props.h"
43
44 #include "wc.h"
45 #include "adm_files.h"
46 #include "translate.h"
47 #include "props.h"
48
49 #include "private/svn_wc_private.h"
50
51
52 svn_error_t *
53 svn_wc__internal_translated_stream(svn_stream_t **stream,
54                                    svn_wc__db_t *db,
55                                    const char *local_abspath,
56                                    const char *versioned_abspath,
57                                    apr_uint32_t flags,
58                                    apr_pool_t *result_pool,
59                                    apr_pool_t *scratch_pool)
60 {
61   svn_boolean_t special;
62   svn_boolean_t to_nf = flags & SVN_WC_TRANSLATE_TO_NF;
63   svn_subst_eol_style_t style;
64   const char *eol;
65   apr_hash_t *keywords;
66   svn_boolean_t repair_forced = flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR;
67
68   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
69   SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
70
71   SVN_ERR(svn_wc__get_translate_info(&style, &eol,
72                                      &keywords,
73                                      &special,
74                                      db, versioned_abspath, NULL, FALSE,
75                                      scratch_pool, scratch_pool));
76
77   if (special)
78     {
79       if (to_nf)
80         return svn_subst_read_specialfile(stream, local_abspath, result_pool,
81                                           scratch_pool);
82
83       return svn_subst_create_specialfile(stream, local_abspath, result_pool,
84                                           scratch_pool);
85     }
86
87   if (to_nf)
88     SVN_ERR(svn_stream_open_readonly(stream, local_abspath, result_pool,
89                                      scratch_pool));
90   else
91     {
92       apr_file_t *file;
93
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);
100     }
101
102   if (svn_subst_translation_required(style, eol, keywords, special, TRUE))
103     {
104       if (to_nf)
105         {
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);
112
113           /* Wrap the stream to translate to normal form */
114           *stream = svn_subst_stream_translated(*stream,
115                                                 eol,
116                                                 repair_forced,
117                                                 keywords,
118                                                 FALSE /* expand */,
119                                                 result_pool);
120
121           /* streams enforce our contract that TO_NF streams are read-only
122            * by returning SVN_ERR_STREAM_NOT_SUPPORTED when trying to
123            * write to them. */
124         }
125       else
126         {
127           *stream = svn_subst_stream_translated(*stream, eol, TRUE,
128                                                 keywords, TRUE, result_pool);
129
130           /* streams enforce our contract that FROM_NF streams are write-only
131            * by returning SVN_ERR_STREAM_NOT_SUPPORTED when trying to
132            * read them. */
133         }
134     }
135
136   return SVN_NO_ERROR;
137 }
138
139
140 svn_error_t *
141 svn_wc__internal_translated_file(const char **xlated_abspath,
142                                  const char *src_abspath,
143                                  svn_wc__db_t *db,
144                                  const char *versioned_abspath,
145                                  apr_uint32_t flags,
146                                  svn_cancel_func_t cancel_func,
147                                  void *cancel_baton,
148                                  apr_pool_t *result_pool,
149                                  apr_pool_t *scratch_pool)
150 {
151   svn_subst_eol_style_t style;
152   const char *eol;
153   apr_hash_t *keywords;
154   svn_boolean_t special;
155
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,
159                                      &keywords,
160                                      &special,
161                                      db, versioned_abspath, NULL, FALSE,
162                                      scratch_pool, scratch_pool));
163
164   if (! svn_subst_translation_required(style, eol, keywords, special, TRUE)
165       && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY)))
166     {
167       /* Translation would be a no-op, so return the original file. */
168       *xlated_abspath = src_abspath;
169     }
170   else  /* some translation (or copying) is necessary */
171     {
172       const char *tmp_dir;
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;
177
178       if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP)
179         tmp_dir = NULL;
180       else
181         SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath,
182                                                scratch_pool, scratch_pool));
183
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));
189
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 */
194
195       if (expand)
196         {
197           /* from normal form */
198
199           repair_forced = TRUE;
200         }
201       else
202         {
203           /* to normal form */
204
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);
211         }
212
213       SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile,
214                                             eol, repair_forced,
215                                             keywords,
216                                             expand,
217                                             special,
218                                             cancel_func, cancel_baton,
219                                             result_pool));
220
221       *xlated_abspath = tmp_vfile;
222     }
223
224   return SVN_NO_ERROR;
225 }
226
227 void
228 svn_wc__eol_value_from_string(const char **value, const char *eol)
229 {
230   if (eol == NULL)
231     *value = NULL;
232   else if (! strcmp("\n", eol))
233     *value = "LF";
234   else if (! strcmp("\r", eol))
235     *value = "CR";
236   else if (! strcmp("\r\n", eol))
237     *value = "CRLF";
238   else
239     *value = NULL;
240 }
241
242 svn_error_t *
243 svn_wc__get_translate_info(svn_subst_eol_style_t *style,
244                            const char **eol,
245                            apr_hash_t **keywords,
246                            svn_boolean_t *special,
247                            svn_wc__db_t *db,
248                            const char *local_abspath,
249                            apr_hash_t *props,
250                            svn_boolean_t for_normalization,
251                            apr_pool_t *result_pool,
252                            apr_pool_t *scratch_pool)
253 {
254   const char *propval;
255   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
256
257   if (props == NULL)
258     SVN_ERR(svn_wc__get_actual_props(&props, db, local_abspath,
259                                      scratch_pool, scratch_pool));
260
261   if (eol)
262     {
263       propval = svn_prop_get_value(props, SVN_PROP_EOL_STYLE);
264
265       svn_subst_eol_style_from_value(style, eol, propval);
266     }
267
268   if (keywords)
269     {
270       propval = svn_prop_get_value(props, SVN_PROP_KEYWORDS);
271
272       if (!propval || *propval == '\0')
273         *keywords = NULL;
274       else
275         SVN_ERR(svn_wc__expand_keywords(keywords,
276                                         db, local_abspath, NULL,
277                                         propval, for_normalization,
278                                         result_pool, scratch_pool));
279     }
280   if (special)
281     {
282       propval = svn_prop_get_value(props, SVN_PROP_SPECIAL);
283
284       *special = (propval != NULL);
285     }
286
287   return SVN_NO_ERROR;
288 }
289
290 svn_error_t *
291 svn_wc__expand_keywords(apr_hash_t **keywords,
292                         svn_wc__db_t *db,
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)
299 {
300   svn_revnum_t changed_rev;
301   apr_time_t changed_date;
302   const char *changed_author;
303   const char *url;
304   const char *repos_root_url;
305
306   if (! for_normalization)
307     {
308       const char *repos_relpath;
309
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,
316                                    db, local_abspath,
317                                    scratch_pool, scratch_pool));
318
319       /* Handle special statuses (e.g. added) */
320       if (!repos_relpath)
321          SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
322                                             &repos_root_url, NULL,
323                                             db, local_abspath,
324                                             scratch_pool, scratch_pool));
325
326       url = svn_path_url_add_component2(repos_root_url, repos_relpath,
327                                         scratch_pool);
328     }
329   else
330     {
331       url = "";
332       changed_rev = SVN_INVALID_REVNUM;
333       changed_date = 0;
334       changed_author = "";
335       repos_root_url = "";
336     }
337
338   SVN_ERR(svn_subst_build_keywords3(keywords, keyword_list,
339                                     apr_psprintf(scratch_pool, "%ld",
340                                                  changed_rev),
341                                     url, repos_root_url,
342                                     changed_date, changed_author,
343                                     result_pool));
344
345   if (apr_hash_count(*keywords) == 0)
346     *keywords = NULL;
347
348   return SVN_NO_ERROR;
349 }
350
351 svn_error_t *
352 svn_wc__sync_flags_with_props(svn_boolean_t *did_set,
353                               svn_wc__db_t *db,
354                               const char *local_abspath,
355                               apr_pool_t *scratch_pool)
356 {
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;
363
364   if (did_set)
365     *did_set = FALSE;
366
367   /* ### We'll consolidate these info gathering statements in a future
368          commit. */
369
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,
374                                db, local_abspath,
375                                scratch_pool, scratch_pool));
376
377   /* We actually only care about the following flags on files, so just
378      early-out for all other types.
379
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))
384     return SVN_NO_ERROR;
385
386   if (props_mod || had_props)
387     SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
388                                   scratch_pool));
389   else
390     props = NULL;
391
392   /* If we get this far, we're going to change *something*, so just set
393      the flag appropriately. */
394   if (did_set)
395     *did_set = TRUE;
396
397   /* Handle the read-write bit. */
398   if (status != svn_wc__db_status_normal
399       || props == NULL
400       || ! svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)
401       || lock)
402     {
403       SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
404     }
405   else
406     {
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;
410
411       if (! props_mod)
412         pristine_props = props;
413       else if (had_props)
414         SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
415                                                 scratch_pool, scratch_pool));
416       else
417         pristine_props = NULL;
418
419       if (pristine_props
420             && svn_hash_gets(pristine_props, SVN_PROP_NEEDS_LOCK) )
421             /*&& props
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));
424     }
425
426 /* Windows doesn't care about the execute bit. */
427 #ifndef WIN32
428
429   if (props == NULL
430       || ! svn_hash_gets(props, SVN_PROP_EXECUTABLE))
431     {
432       /* Turn off the execute bit */
433       SVN_ERR(svn_io_set_file_executable(local_abspath, FALSE, FALSE,
434                                          scratch_pool));
435     }
436   else
437     SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE,
438                                        scratch_pool));
439 #endif
440
441   return SVN_NO_ERROR;
442 }