2 * add.c: wrappers around wc add/mkdir functionality.
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 * ====================================================================
24 /* ==================================================================== */
32 #include <apr_fnmatch.h>
34 #include "svn_client.h"
35 #include "svn_string.h"
36 #include "svn_pools.h"
37 #include "svn_error.h"
38 #include "svn_dirent_uri.h"
41 #include "svn_config.h"
42 #include "svn_props.h"
44 #include "svn_sorts.h"
46 #include "svn_ctype.h"
48 #include "private/svn_client_private.h"
49 #include "private/svn_wc_private.h"
50 #include "private/svn_ra_private.h"
51 #include "private/svn_magic.h"
53 #include "svn_private_config.h"
59 /* Remove leading and trailing white space from a C string, in place. */
61 trim_string(char **pstr)
66 while (svn_ctype_isspace(*str))
70 while ((i > 0) && svn_ctype_isspace(str[i-1]))
75 /* Remove leading and trailing single- or double quotes from a C string,
78 unquote_string(char **pstr)
81 size_t i = strlen(str);
83 if (i > 0 && ((*str == '"' && str[i - 1] == '"') ||
84 (*str == '\'' && str[i - 1] == '\'')))
92 /* Split PROPERTY and store each individual value in PROPS.
93 Allocates from POOL. */
95 split_props(apr_array_header_t **props,
99 apr_array_header_t *temp_props;
104 temp_props = apr_array_make(pool, 4, sizeof(char *));
105 new_prop = apr_palloc(pool, strlen(property)+1);
107 for (i = 0; property[i] != '\0'; i++)
109 if (property[i] != ';')
111 new_prop[j] = property[i];
114 else if (property[i] == ';')
116 /* ";;" becomes ";" */
117 if (property[i+1] == ';')
126 APR_ARRAY_PUSH(temp_props, char *) = new_prop;
133 APR_ARRAY_PUSH(temp_props, char *) = new_prop;
137 /* PROPVALS is a hash mapping char * property names to const char * property
138 values. PROPERTIES can be empty but not NULL.
140 If FILENAME doesn't match the filename pattern PATTERN case insensitively,
141 the do nothing. Otherwise for each 'name':'value' pair in PROPVALS, add
142 a new entry mappying 'name' to a svn_string_t * wrapping the 'value' in
143 PROPERTIES. The svn_string_t is allocated in the pool used to allocate
144 PROPERTIES, but the char *'s from PROPVALS are re-used in PROPERTIES.
145 If PROPVALS contains a 'svn:mime-type' mapping, then set *MIMETYPE to
146 the mapped value. Likewise if PROPVALS contains a mapping for
147 svn:executable, then set *HAVE_EXECUTABLE to TRUE.
149 Use SCRATCH_POOL for temporary allocations.
152 get_auto_props_for_pattern(apr_hash_t *properties,
153 const char **mimetype,
154 svn_boolean_t *have_executable,
155 const char *filename,
157 apr_hash_t *propvals,
158 apr_pool_t *scratch_pool)
160 apr_hash_index_t *hi;
162 /* check if filename matches and return if it doesn't */
163 if (apr_fnmatch(pattern, filename,
164 APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
167 for (hi = apr_hash_first(scratch_pool, propvals);
169 hi = apr_hash_next(hi))
171 const char *propname = svn__apr_hash_index_key(hi);
172 const char *propval = svn__apr_hash_index_val(hi);
173 svn_string_t *propval_str =
174 svn_string_create_empty(apr_hash_pool_get(properties));
176 propval_str->data = propval;
177 propval_str->len = strlen(propval);
179 svn_hash_sets(properties, propname, propval_str);
180 if (strcmp(propname, SVN_PROP_MIME_TYPE) == 0)
182 else if (strcmp(propname, SVN_PROP_EXECUTABLE) == 0)
183 *have_executable = TRUE;
188 svn_client__get_paths_auto_props(apr_hash_t **properties,
189 const char **mimetype,
191 svn_magic__cookie_t *magic_cookie,
192 apr_hash_t *autoprops,
193 svn_client_ctx_t *ctx,
194 apr_pool_t *result_pool,
195 apr_pool_t *scratch_pool)
197 apr_hash_index_t *hi;
198 svn_boolean_t have_executable = FALSE;
200 *properties = apr_hash_make(result_pool);
205 for (hi = apr_hash_first(scratch_pool, autoprops);
207 hi = apr_hash_next(hi))
209 const char *pattern = svn__apr_hash_index_key(hi);
210 apr_hash_t *propvals = svn__apr_hash_index_val(hi);
212 get_auto_props_for_pattern(*properties, mimetype, &have_executable,
213 svn_dirent_basename(path, scratch_pool),
214 pattern, propvals, scratch_pool);
218 /* if mimetype has not been set check the file */
221 SVN_ERR(svn_io_detect_mimetype2(mimetype, path, ctx->mimetypes_map,
224 /* If we got no mime-type, or if it is "application/octet-stream",
225 * try to get the mime-type from libmagic. */
228 strcmp(*mimetype, "application/octet-stream") == 0))
230 const char *magic_mimetype;
232 /* Since libmagic usually treats UTF-16 files as "text/plain",
233 * svn_magic__detect_binary_mimetype() will return NULL for such
234 * files. This is fine for now since we currently don't support
235 * UTF-16-encoded text files (issue #2194).
236 * Once we do support UTF-16 this code path will fail to detect
237 * them as text unless the svn_io_detect_mimetype2() call above
238 * returns "text/plain" for them. */
239 SVN_ERR(svn_magic__detect_binary_mimetype(&magic_mimetype,
244 *mimetype = magic_mimetype;
248 apr_hash_set(*properties, SVN_PROP_MIME_TYPE,
249 strlen(SVN_PROP_MIME_TYPE),
250 svn_string_create(*mimetype, result_pool));
253 /* if executable has not been set check the file */
254 if (! have_executable)
256 svn_boolean_t executable = FALSE;
257 SVN_ERR(svn_io_is_file_executable(&executable, path, scratch_pool));
259 apr_hash_set(*properties, SVN_PROP_EXECUTABLE,
260 strlen(SVN_PROP_EXECUTABLE),
261 svn_string_create_empty(result_pool));
267 /* Only call this if the on-disk node kind is a file. */
269 add_file(const char *local_abspath,
270 svn_magic__cookie_t *magic_cookie,
271 apr_hash_t *autoprops,
272 svn_boolean_t no_autoprops,
273 svn_client_ctx_t *ctx,
276 apr_hash_t *properties;
277 const char *mimetype;
278 svn_node_kind_t kind;
279 svn_boolean_t is_special;
281 /* Check to see if this is a special file. */
282 SVN_ERR(svn_io_check_special_path(local_abspath, &kind, &is_special, pool));
284 /* Determine the properties that the file should have */
288 properties = apr_hash_make(pool);
289 svn_hash_sets(properties, SVN_PROP_SPECIAL,
290 svn_string_create(SVN_PROP_BOOLEAN_TRUE, pool));
294 apr_hash_t *file_autoprops = NULL;
296 /* Get automatic properties */
297 /* If we are setting autoprops grab the inherited svn:auto-props and
298 config file auto-props for this file if we haven't already got them
299 when iterating over the file's unversioned parents. */
302 if (autoprops == NULL)
303 SVN_ERR(svn_client__get_all_auto_props(
304 &file_autoprops, svn_dirent_dirname(local_abspath,pool),
307 file_autoprops = autoprops;
310 /* This may fail on write-only files:
311 we open them to estimate file type. */
312 SVN_ERR(svn_client__get_paths_auto_props(&properties, &mimetype,
313 local_abspath, magic_cookie,
314 file_autoprops, ctx, pool,
319 SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, local_abspath, properties,
320 ctx->notify_func2, ctx->notify_baton2, pool));
325 /* Schedule directory DIR_ABSPATH, and some of the tree under it, for
326 * addition. DEPTH is the depth at this point in the descent (it may
327 * be changed for recursive calls).
329 * If DIR_ABSPATH (or any item below DIR_ABSPATH) is already scheduled for
330 * addition, add will fail and return an error unless FORCE is TRUE.
332 * Use MAGIC_COOKIE (which may be NULL) to detect the mime-type of files
335 * If not NULL, CONFIG_AUTOPROPS is a hash representing the config file and
336 * svn:auto-props autoprops which apply to DIR_ABSPATH. It maps
337 * const char * file patterns to another hash which maps const char *
338 * property names to const char *property values. If CONFIG_AUTOPROPS is
339 * NULL and the config file and svn:auto-props autoprops are required by this
340 * function, then such will be obtained.
342 * If IGNORES is not NULL, then it is an array of const char * ignore patterns
343 * that apply to any children of DIR_ABSPATH. If REFRESH_IGNORES is TRUE, then
344 * the passed in value of IGNORES (if any) is itself ignored and this function
345 * will gather all ignore patterns applicable to DIR_ABSPATH itself (allocated in
346 * RESULT_POOL). Any recursive calls to this function get the refreshed ignore
347 * patterns. If IGNORES is NULL and REFRESH_IGNORES is FALSE, then all children of DIR_ABSPATH
348 * are unconditionally added.
350 * If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to allow
351 * the user to cancel the operation.
353 * Use SCRATCH_POOL for temporary allocations.
356 add_dir_recursive(const char *dir_abspath,
359 svn_boolean_t no_autoprops,
360 svn_magic__cookie_t *magic_cookie,
361 apr_hash_t *config_autoprops,
362 svn_boolean_t refresh_ignores,
363 apr_array_header_t *ignores,
364 svn_client_ctx_t *ctx,
365 apr_pool_t *result_pool,
366 apr_pool_t *scratch_pool)
369 apr_pool_t *iterpool;
371 apr_hash_index_t *hi;
372 svn_boolean_t entry_exists = FALSE;
374 /* Check cancellation; note that this catches recursive calls too. */
375 if (ctx->cancel_func)
376 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
378 iterpool = svn_pool_create(scratch_pool);
380 /* Add this directory to revision control. */
381 err = svn_wc_add_from_disk2(ctx->wc_ctx, dir_abspath, NULL /*props*/,
382 ctx->notify_func2, ctx->notify_baton2,
386 if (err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
388 svn_error_clear(err);
393 return svn_error_trace(err);
397 /* Fetch ignores after adding to handle ignores on the directory itself
398 and ancestors via the single db optimization in libsvn_wc */
400 SVN_ERR(svn_wc_get_ignores2(&ignores, ctx->wc_ctx, dir_abspath,
401 ctx->config, result_pool, iterpool));
403 /* If DIR_ABSPATH is the root of an unversioned subtree then get the
404 following "autoprops":
406 1) Explicit and inherited svn:auto-props properties on
408 2) auto-props from the CTX->CONFIG hash
410 Since this set of autoprops applies to all unversioned children of
411 DIR_ABSPATH, we will pass these along to any recursive calls to
412 add_dir_recursive() and calls to add_file() below. Thus sparing
413 these callees from looking up the same information. */
414 if (!entry_exists && config_autoprops == NULL)
416 SVN_ERR(svn_client__get_all_auto_props(&config_autoprops, dir_abspath,
417 ctx, scratch_pool, iterpool));
420 SVN_ERR(svn_io_get_dirents3(&dirents, dir_abspath, TRUE, scratch_pool,
423 /* Read the directory entries one by one and add those things to
425 for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
427 const char *name = svn__apr_hash_index_key(hi);
428 svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
431 svn_pool_clear(iterpool);
433 /* Check cancellation so you can cancel during an
434 * add of a directory with lots of files. */
435 if (ctx->cancel_func)
436 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
438 /* Skip over SVN admin directories. */
439 if (svn_wc_is_adm_dir(name, iterpool))
443 && svn_wc_match_ignore_list(name, ignores, iterpool))
446 /* Construct the full path of the entry. */
447 abspath = svn_dirent_join(dir_abspath, name, iterpool);
449 /* Recurse on directories; add files; ignore the rest. */
450 if (dirent->kind == svn_node_dir && depth >= svn_depth_immediates)
452 svn_depth_t depth_below_here = depth;
453 if (depth == svn_depth_immediates)
454 depth_below_here = svn_depth_empty;
456 /* When DIR_ABSPATH is the root of an unversioned subtree then
457 it and all of its children have the same set of ignores. So
458 save any recursive calls the extra work of finding the same
460 if (refresh_ignores && !entry_exists)
461 refresh_ignores = FALSE;
463 SVN_ERR(add_dir_recursive(abspath, depth_below_here,
465 magic_cookie, config_autoprops,
466 refresh_ignores, ignores, ctx,
467 result_pool, iterpool));
469 else if ((dirent->kind == svn_node_file || dirent->special)
470 && depth >= svn_depth_files)
472 err = add_file(abspath, magic_cookie, config_autoprops,
473 no_autoprops, ctx, iterpool);
474 if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
475 svn_error_clear(err);
481 /* Destroy the per-iteration pool. */
482 svn_pool_destroy(iterpool);
487 /* This structure is used as baton for collecting the config entries
488 in the auto-props section and any inherited svn:auto-props
491 typedef struct collect_auto_props_baton_t
493 /* the hash table for storing the property name/value pairs */
494 apr_hash_t *autoprops;
496 /* a pool used for allocating memory */
497 apr_pool_t *result_pool;
498 } collect_auto_props_baton_t;
500 /* Implements svn_config_enumerator2_t callback.
502 For one auto-props config entry (NAME, VALUE), stash a copy of
503 NAME and VALUE, allocated in BATON->POOL, in BATON->AUTOPROP.
504 BATON must point to an collect_auto_props_baton_t.
507 all_auto_props_collector(const char *name,
512 collect_auto_props_baton_t *autoprops_baton = baton;
513 apr_array_header_t *autoprops;
516 /* nothing to do here without a value */
520 split_props(&autoprops, value, pool);
522 for (i = 0; i < autoprops->nelts; i ++)
525 const char *this_value;
526 char *property = APR_ARRAY_IDX(autoprops, i, char *);
527 char *equal_sign = strchr(property, '=');
533 trim_string(&equal_sign);
534 unquote_string(&equal_sign);
535 this_value = equal_sign;
541 trim_string(&property);
542 len = strlen(property);
546 apr_hash_t *pattern_hash = svn_hash_gets(autoprops_baton->autoprops,
548 svn_string_t *propval;
550 /* Force reserved boolean property values to '*'. */
551 if (svn_prop_is_boolean(property))
553 /* SVN_PROP_EXECUTABLE, SVN_PROP_NEEDS_LOCK, SVN_PROP_SPECIAL */
554 propval = svn_string_create("*", autoprops_baton->result_pool);
558 propval = svn_string_create(this_value,
559 autoprops_baton->result_pool);
564 pattern_hash = apr_hash_make(autoprops_baton->result_pool);
565 svn_hash_sets(autoprops_baton->autoprops,
566 apr_pstrdup(autoprops_baton->result_pool, name),
569 svn_hash_sets(pattern_hash,
570 apr_pstrdup(autoprops_baton->result_pool, property),
577 /* Go up the directory tree from LOCAL_ABSPATH, looking for a versioned
578 * directory. If found, return its path in *EXISTING_PARENT_ABSPATH.
579 * Otherwise, return SVN_ERR_CLIENT_NO_VERSIONED_PARENT. */
581 find_existing_parent(const char **existing_parent_abspath,
582 svn_client_ctx_t *ctx,
583 const char *local_abspath,
584 apr_pool_t *result_pool,
585 apr_pool_t *scratch_pool)
587 svn_node_kind_t kind;
588 const char *parent_abspath;
589 svn_wc_context_t *wc_ctx = ctx->wc_ctx;
591 SVN_ERR(svn_wc_read_kind2(&kind, wc_ctx, local_abspath,
592 FALSE, FALSE, scratch_pool));
594 if (kind == svn_node_dir)
596 *existing_parent_abspath = apr_pstrdup(result_pool, local_abspath);
600 if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
601 return svn_error_create(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL, NULL);
603 if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
605 return svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED, NULL,
606 _("'%s' ends in a reserved name"),
607 svn_dirent_local_style(local_abspath,
610 parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
612 if (ctx->cancel_func)
613 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
615 SVN_ERR(find_existing_parent(existing_parent_abspath, ctx, parent_abspath,
616 result_pool, scratch_pool));
622 svn_client__get_all_auto_props(apr_hash_t **autoprops,
623 const char *path_or_url,
624 svn_client_ctx_t *ctx,
625 apr_pool_t *result_pool,
626 apr_pool_t *scratch_pool)
629 apr_array_header_t *inherited_config_auto_props;
631 svn_opt_revision_t rev;
632 svn_string_t *config_auto_prop;
633 svn_boolean_t use_autoprops;
634 collect_auto_props_baton_t autoprops_baton;
635 svn_error_t *err = NULL;
636 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
637 svn_boolean_t target_is_url = svn_path_is_url(path_or_url);
638 svn_config_t *cfg = ctx->config ? svn_hash_gets(ctx->config,
639 SVN_CONFIG_CATEGORY_CONFIG)
641 *autoprops = apr_hash_make(result_pool);
642 autoprops_baton.result_pool = result_pool;
643 autoprops_baton.autoprops = *autoprops;
646 /* Are "traditional" auto-props enabled? If so grab them from the
647 config. This is our starting set auto-props, which may be overriden
648 by svn:auto-props. */
649 SVN_ERR(svn_config_get_bool(cfg, &use_autoprops,
650 SVN_CONFIG_SECTION_MISCELLANY,
651 SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, FALSE));
653 svn_config_enumerate2(cfg, SVN_CONFIG_SECTION_AUTO_PROPS,
654 all_auto_props_collector, &autoprops_baton,
657 /* Convert the config file setting (if any) into a hash mapping file
658 patterns to as hash of prop-->val mappings. */
659 if (svn_path_is_url(path_or_url))
660 rev.kind = svn_opt_revision_head;
662 rev.kind = svn_opt_revision_working;
664 /* If PATH_OR_URL is a WC path, then it might be unversioned, in which case
665 we find it's nearest versioned parent. */
668 err = svn_client_propget5(&props, &inherited_config_auto_props,
669 SVN_PROP_INHERITABLE_AUTO_PROPS, path_or_url,
670 &rev, &rev, NULL, svn_depth_empty, NULL, ctx,
671 scratch_pool, iterpool);
674 if (target_is_url || err->apr_err != SVN_ERR_UNVERSIONED_RESOURCE)
675 return svn_error_trace(err);
677 svn_error_clear(err);
679 SVN_ERR(find_existing_parent(&path_or_url, ctx, path_or_url,
680 scratch_pool, iterpool));
689 /* Stash any explicit PROPS for PARENT_PATH into the inherited props array,
690 since these are actually inherited props for LOCAL_ABSPATH. */
691 config_auto_prop = svn_hash_gets(props, path_or_url);
693 if (config_auto_prop)
695 svn_prop_inherited_item_t *new_iprop =
696 apr_palloc(scratch_pool, sizeof(*new_iprop));
697 new_iprop->path_or_url = path_or_url;
698 new_iprop->prop_hash = apr_hash_make(scratch_pool);
699 svn_hash_sets(new_iprop->prop_hash, SVN_PROP_INHERITABLE_AUTO_PROPS,
701 APR_ARRAY_PUSH(inherited_config_auto_props,
702 svn_prop_inherited_item_t *) = new_iprop;
705 for (i = 0; i < inherited_config_auto_props->nelts; i++)
707 apr_hash_index_t *hi;
708 svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
709 inherited_config_auto_props, i, svn_prop_inherited_item_t *);
711 for (hi = apr_hash_first(scratch_pool, elt->prop_hash);
713 hi = apr_hash_next(hi))
715 const svn_string_t *propval = svn__apr_hash_index_val(hi);
716 const char *ch = propval->data;
717 svn_stringbuf_t *config_auto_prop_pattern;
718 svn_stringbuf_t *config_auto_prop_val;
720 svn_pool_clear(iterpool);
722 config_auto_prop_pattern = svn_stringbuf_create_empty(iterpool);
723 config_auto_prop_val = svn_stringbuf_create_empty(iterpool);
725 /* Parse svn:auto-props value. */
728 svn_stringbuf_setempty(config_auto_prop_pattern);
729 svn_stringbuf_setempty(config_auto_prop_val);
731 /* Parse the file pattern. */
732 while (*ch != '\0' && *ch != '=' && *ch != '\n')
734 svn_stringbuf_appendbyte(config_auto_prop_pattern, *ch);
738 svn_stringbuf_strip_whitespace(config_auto_prop_pattern);
740 /* Parse the auto-prop group. */
741 while (*ch != '\0' && *ch != '\n')
743 svn_stringbuf_appendbyte(config_auto_prop_val, *ch);
747 /* Strip leading '=' and whitespace from auto-prop group. */
748 if (config_auto_prop_val->data[0] == '=')
749 svn_stringbuf_remove(config_auto_prop_val, 0, 1);
750 svn_stringbuf_strip_whitespace(config_auto_prop_val);
752 all_auto_props_collector(config_auto_prop_pattern->data,
753 config_auto_prop_val->data,
757 /* Skip to next line if any. */
758 while (*ch != '\0' && *ch != '\n')
766 svn_pool_destroy(iterpool);
771 svn_error_t *svn_client__get_inherited_ignores(apr_array_header_t **ignores,
772 const char *path_or_url,
773 svn_client_ctx_t *ctx,
774 apr_pool_t *result_pool,
775 apr_pool_t *scratch_pool)
777 svn_opt_revision_t rev;
778 apr_hash_t *explicit_ignores;
779 apr_array_header_t *inherited_ignores;
780 svn_boolean_t target_is_url = svn_path_is_url(path_or_url);
781 svn_string_t *explicit_prop;
785 rev.kind = svn_opt_revision_head;
787 rev.kind = svn_opt_revision_working;
789 SVN_ERR(svn_client_propget5(&explicit_ignores, &inherited_ignores,
790 SVN_PROP_INHERITABLE_IGNORES, path_or_url,
791 &rev, &rev, NULL, svn_depth_empty, NULL, ctx,
792 scratch_pool, scratch_pool));
794 explicit_prop = svn_hash_gets(explicit_ignores, path_or_url);
798 svn_prop_inherited_item_t *new_iprop =
799 apr_palloc(scratch_pool, sizeof(*new_iprop));
800 new_iprop->path_or_url = path_or_url;
801 new_iprop->prop_hash = apr_hash_make(scratch_pool);
802 svn_hash_sets(new_iprop->prop_hash, SVN_PROP_INHERITABLE_IGNORES,
804 APR_ARRAY_PUSH(inherited_ignores,
805 svn_prop_inherited_item_t *) = new_iprop;
808 *ignores = apr_array_make(result_pool, 16, sizeof(const char *));
810 for (i = 0; i < inherited_ignores->nelts; i++)
812 svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
813 inherited_ignores, i, svn_prop_inherited_item_t *);
814 svn_string_t *ignore_val = svn_hash_gets(elt->prop_hash,
815 SVN_PROP_INHERITABLE_IGNORES);
817 svn_cstring_split_append(*ignores, ignore_val->data, "\n\r\t\v ",
824 /* The main logic of the public svn_client_add5.
826 * EXISTING_PARENT_ABSPATH is the absolute path to the first existing
827 * parent directory of local_abspath. If not NULL, all missing parents
828 * of LOCAL_ABSPATH must be created before LOCAL_ABSPATH can be added. */
830 add(const char *local_abspath,
833 svn_boolean_t no_ignore,
834 svn_boolean_t no_autoprops,
835 const char *existing_parent_abspath,
836 svn_client_ctx_t *ctx,
837 apr_pool_t *scratch_pool)
839 svn_node_kind_t kind;
841 svn_magic__cookie_t *magic_cookie;
842 apr_array_header_t *ignores = NULL;
844 svn_magic__init(&magic_cookie, scratch_pool);
846 if (existing_parent_abspath)
848 const char *parent_abspath;
849 const char *child_relpath;
850 apr_array_header_t *components;
852 apr_pool_t *iterpool;
854 parent_abspath = existing_parent_abspath;
855 child_relpath = svn_dirent_is_child(existing_parent_abspath,
856 local_abspath, NULL);
857 components = svn_path_decompose(child_relpath, scratch_pool);
858 iterpool = svn_pool_create(scratch_pool);
859 for (i = 0; i < components->nelts - 1; i++)
861 const char *component;
862 svn_node_kind_t disk_kind;
864 svn_pool_clear(iterpool);
866 if (ctx->cancel_func)
867 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
869 component = APR_ARRAY_IDX(components, i, const char *);
870 parent_abspath = svn_dirent_join(parent_abspath, component,
872 SVN_ERR(svn_io_check_path(parent_abspath, &disk_kind, iterpool));
873 if (disk_kind != svn_node_none && disk_kind != svn_node_dir)
874 return svn_error_createf(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL,
875 _("'%s' prevents creating parent of '%s'"),
876 parent_abspath, local_abspath);
878 SVN_ERR(svn_io_make_dir_recursively(parent_abspath, scratch_pool));
879 SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, parent_abspath,
881 ctx->notify_func2, ctx->notify_baton2,
884 svn_pool_destroy(iterpool);
887 SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
888 if (kind == svn_node_dir)
890 /* We use add_dir_recursive for all directory targets
891 and pass depth along no matter what it is, so that the
892 target's depth will be set correctly. */
893 err = add_dir_recursive(local_abspath, depth, force,
894 no_autoprops, magic_cookie, NULL,
895 !no_ignore, ignores, ctx,
896 scratch_pool, scratch_pool);
898 else if (kind == svn_node_file)
899 err = add_file(local_abspath, magic_cookie, NULL,
900 no_autoprops, ctx, scratch_pool);
901 else if (kind == svn_node_none)
903 svn_boolean_t tree_conflicted;
905 /* Provide a meaningful error message if the node does not exist
906 * on disk but is a tree conflict victim. */
907 err = svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted,
908 ctx->wc_ctx, local_abspath,
911 svn_error_clear(err);
912 else if (tree_conflicted)
913 return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL,
914 _("'%s' is an existing item in conflict; "
915 "please mark the conflict as resolved "
916 "before adding a new item here"),
917 svn_dirent_local_style(local_abspath,
920 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
922 svn_dirent_local_style(local_abspath,
926 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
927 _("Unsupported node kind for path '%s'"),
928 svn_dirent_local_style(local_abspath,
931 /* Ignore SVN_ERR_ENTRY_EXISTS when FORCE is set. */
932 if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
934 svn_error_clear(err);
937 return svn_error_trace(err);
943 svn_client_add5(const char *path,
946 svn_boolean_t no_ignore,
947 svn_boolean_t no_autoprops,
948 svn_boolean_t add_parents,
949 svn_client_ctx_t *ctx,
950 apr_pool_t *scratch_pool)
952 const char *parent_abspath;
953 const char *local_abspath;
954 const char *existing_parent_abspath;
955 svn_boolean_t is_wc_root;
958 if (svn_path_is_url(path))
959 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
960 _("'%s' is not a local path"), path);
962 SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
964 /* See if we're being asked to add a wc-root. That's typically not
965 okay, unless we're in "force" mode. svn_wc__is_wcroot()
966 will return TRUE even if LOCAL_ABSPATH is a *symlink* to a working
967 copy root, which is a scenario we want to treat differently. */
968 err = svn_wc__is_wcroot(&is_wc_root, ctx->wc_ctx, local_abspath,
972 if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
973 && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
975 return svn_error_trace(err);
978 svn_error_clear(err);
979 err = NULL; /* SVN_NO_ERROR */
985 svn_node_kind_t disk_kind;
986 svn_boolean_t is_special;
988 SVN_ERR(svn_io_check_special_path(local_abspath, &disk_kind, &is_special,
991 /* A symlink can be an unversioned target and a wcroot. Lets try to add
992 the symlink, which can't be a wcroot. */
999 return svn_error_createf(
1000 SVN_ERR_ENTRY_EXISTS, NULL,
1001 _("'%s' is already under version control"),
1002 svn_dirent_local_style(local_abspath,
1008 parent_abspath = local_abspath; /* We will only add children */
1010 parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
1012 existing_parent_abspath = NULL;
1013 if (add_parents && !is_wc_root)
1015 apr_pool_t *subpool;
1016 const char *existing_parent_abspath2;
1018 subpool = svn_pool_create(scratch_pool);
1019 SVN_ERR(find_existing_parent(&existing_parent_abspath2, ctx,
1020 parent_abspath, scratch_pool, subpool));
1021 if (strcmp(existing_parent_abspath2, parent_abspath) != 0)
1022 existing_parent_abspath = existing_parent_abspath2;
1023 svn_pool_destroy(subpool);
1026 SVN_WC__CALL_WITH_WRITE_LOCK(
1027 add(local_abspath, depth, force, no_ignore, no_autoprops,
1028 existing_parent_abspath, ctx, scratch_pool),
1029 ctx->wc_ctx, (existing_parent_abspath ? existing_parent_abspath
1031 FALSE /* lock_anchor */, scratch_pool);
1032 return SVN_NO_ERROR;
1036 static svn_error_t *
1037 path_driver_cb_func(void **dir_baton,
1039 void *callback_baton,
1043 const svn_delta_editor_t *editor = callback_baton;
1044 SVN_ERR(svn_path_check_valid(path, pool));
1045 return editor->add_directory(path, parent_baton, NULL,
1046 SVN_INVALID_REVNUM, pool, dir_baton);
1049 /* Append URL, and all it's non-existent parent directories, to TARGETS.
1050 Use TEMPPOOL for temporary allocations and POOL for any additions to
1052 static svn_error_t *
1053 add_url_parents(svn_ra_session_t *ra_session,
1055 apr_array_header_t *targets,
1056 apr_pool_t *temppool,
1059 svn_node_kind_t kind;
1060 const char *parent_url = svn_uri_dirname(url, pool);
1062 SVN_ERR(svn_ra_reparent(ra_session, parent_url, temppool));
1063 SVN_ERR(svn_ra_check_path(ra_session, "", SVN_INVALID_REVNUM, &kind,
1066 if (kind == svn_node_none)
1067 SVN_ERR(add_url_parents(ra_session, parent_url, targets, temppool, pool));
1069 APR_ARRAY_PUSH(targets, const char *) = url;
1071 return SVN_NO_ERROR;
1074 static svn_error_t *
1075 mkdir_urls(const apr_array_header_t *urls,
1076 svn_boolean_t make_parents,
1077 const apr_hash_t *revprop_table,
1078 svn_commit_callback2_t commit_callback,
1080 svn_client_ctx_t *ctx,
1083 svn_ra_session_t *ra_session = NULL;
1084 const svn_delta_editor_t *editor;
1086 const char *log_msg;
1087 apr_array_header_t *targets;
1088 apr_hash_t *targets_hash;
1089 apr_hash_t *commit_revprops;
1094 /* Find any non-existent parent directories */
1097 apr_array_header_t *all_urls = apr_array_make(pool, urls->nelts,
1098 sizeof(const char *));
1099 const char *first_url = APR_ARRAY_IDX(urls, 0, const char *);
1100 apr_pool_t *iterpool = svn_pool_create(pool);
1102 SVN_ERR(svn_client_open_ra_session2(&ra_session, first_url, NULL,
1103 ctx, pool, iterpool));
1105 for (i = 0; i < urls->nelts; i++)
1107 const char *url = APR_ARRAY_IDX(urls, i, const char *);
1109 svn_pool_clear(iterpool);
1110 SVN_ERR(add_url_parents(ra_session, url, all_urls, iterpool, pool));
1113 svn_pool_destroy(iterpool);
1118 /* Condense our list of mkdir targets. */
1119 SVN_ERR(svn_uri_condense_targets(&common, &targets, urls, FALSE,
1122 /*Remove duplicate targets introduced by make_parents with more targets. */
1123 SVN_ERR(svn_hash_from_cstring_keys(&targets_hash, targets, pool));
1124 SVN_ERR(svn_hash_keys(&targets, targets_hash, pool));
1126 if (! targets->nelts)
1129 svn_uri_split(&common, &bname, common, pool);
1130 APR_ARRAY_PUSH(targets, const char *) = bname;
1133 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1134 _("There is no valid URI above '%s'"),
1139 svn_boolean_t resplit = FALSE;
1141 /* We can't "mkdir" the root of an editor drive, so if one of
1142 our targets is the empty string, we need to back everything
1143 up by a path component. */
1144 for (i = 0; i < targets->nelts; i++)
1146 const char *path = APR_ARRAY_IDX(targets, i, const char *);
1157 svn_uri_split(&common, &bname, common, pool);
1160 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
1161 _("There is no valid URI above '%s'"),
1164 for (i = 0; i < targets->nelts; i++)
1166 const char *path = APR_ARRAY_IDX(targets, i, const char *);
1167 path = svn_relpath_join(bname, path, pool);
1168 APR_ARRAY_IDX(targets, i, const char *) = path;
1172 qsort(targets->elts, targets->nelts, targets->elt_size,
1173 svn_sort_compare_paths);
1175 /* ### This reparent may be problematic in limited-authz-to-common-parent
1176 ### scenarios (compare issue #3242). See also issue #3649. */
1178 SVN_ERR(svn_ra_reparent(ra_session, common, pool));
1180 /* Create new commit items and add them to the array. */
1181 if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
1183 svn_client_commit_item3_t *item;
1184 const char *tmp_file;
1185 apr_array_header_t *commit_items
1186 = apr_array_make(pool, targets->nelts, sizeof(item));
1188 for (i = 0; i < targets->nelts; i++)
1190 const char *path = APR_ARRAY_IDX(targets, i, const char *);
1192 item = svn_client_commit_item3_create(pool);
1193 item->url = svn_path_url_add_component2(common, path, pool);
1194 item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
1195 APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
1198 SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items,
1202 return SVN_NO_ERROR;
1207 SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
1208 log_msg, ctx, pool));
1210 /* Open an RA session for the URL. Note that we don't have a local
1211 directory, nor a place to put temp files. */
1213 SVN_ERR(svn_client_open_ra_session2(&ra_session, common, NULL, ctx,
1216 SVN_ERR(svn_ra_reparent(ra_session, common, pool));
1219 /* Fetch RA commit editor */
1220 SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
1221 svn_client__get_shim_callbacks(ctx->wc_ctx, NULL,
1223 SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
1227 NULL, TRUE, /* No lock tokens */
1230 /* Call the path-based editor driver. */
1231 err = svn_delta_path_driver2(editor, edit_baton, targets, TRUE,
1232 path_driver_cb_func, (void *)editor, pool);
1236 /* At least try to abort the edit (and fs txn) before throwing err. */
1237 return svn_error_compose_create(
1239 editor->abort_edit(edit_baton, pool));
1242 /* Close the edit. */
1243 return editor->close_edit(edit_baton, pool);
1249 svn_client__make_local_parents(const char *path,
1250 svn_boolean_t make_parents,
1251 svn_client_ctx_t *ctx,
1255 svn_node_kind_t orig_kind;
1256 SVN_ERR(svn_io_check_path(path, &orig_kind, pool));
1258 SVN_ERR(svn_io_make_dir_recursively(path, pool));
1260 SVN_ERR(svn_io_dir_make(path, APR_OS_DEFAULT, pool));
1262 /* Should no longer use svn_depth_empty to indicate that only the directory
1263 itself is added, since it not only constraints the operation depth, but
1264 also defines the depth of the target directory now. Moreover, the new
1265 directory will have no children at all.*/
1266 err = svn_client_add5(path, svn_depth_infinity, FALSE, FALSE, FALSE,
1267 make_parents, ctx, pool);
1269 /* If we created a new directory, but couldn't add it to version
1270 control, then delete it. */
1271 if (err && (orig_kind == svn_node_none))
1273 /* ### If this returns an error, should we link it onto
1274 err instead, so that the user is warned that we just
1275 created an unversioned directory? */
1277 svn_error_clear(svn_io_remove_dir2(path, FALSE, NULL, NULL, pool));
1280 return svn_error_trace(err);
1285 svn_client_mkdir4(const apr_array_header_t *paths,
1286 svn_boolean_t make_parents,
1287 const apr_hash_t *revprop_table,
1288 svn_commit_callback2_t commit_callback,
1290 svn_client_ctx_t *ctx,
1294 return SVN_NO_ERROR;
1296 SVN_ERR(svn_client__assert_homogeneous_target_type(paths));
1298 if (svn_path_is_url(APR_ARRAY_IDX(paths, 0, const char *)))
1300 SVN_ERR(mkdir_urls(paths, make_parents, revprop_table, commit_callback,
1301 commit_baton, ctx, pool));
1305 /* This is a regular "mkdir" + "svn add" */
1306 apr_pool_t *subpool = svn_pool_create(pool);
1309 for (i = 0; i < paths->nelts; i++)
1311 const char *path = APR_ARRAY_IDX(paths, i, const char *);
1313 svn_pool_clear(subpool);
1315 /* See if the user wants us to stop. */
1316 if (ctx->cancel_func)
1317 SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
1319 SVN_ERR(svn_client__make_local_parents(path, make_parents, ctx,
1322 svn_pool_destroy(subpool);
1325 return SVN_NO_ERROR;