2 * add.c: wrappers around wc add/mkdir functionality.
4 * ====================================================================
5 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ==================================================================== */
27 #include <apr_fnmatch.h>
29 #include "svn_client.h"
30 #include "svn_string.h"
31 #include "svn_pools.h"
32 #include "svn_error.h"
35 #include "svn_config.h"
36 #include "svn_props.h"
38 #include "svn_sorts.h"
41 #include "svn_private_config.h"
47 /* This structure is used as baton for enumerating the config entries
48 in the auto-props section.
52 /* the file name for which properties are searched */
55 /* when this flag is set the hash contains svn:executable */
56 svn_boolean_t have_executable
;
58 /* when mimetype is not NULL is set the hash contains svn:mime-type */
61 /* the hash table for storing the property name/value pairs */
62 apr_hash_t
*properties
;
64 /* a pool used for allocating memory */
68 /* Remove leading and trailing white space from a C string, in place. */
70 trim_string(char **pstr
)
75 while (apr_isspace(*str
))
79 while ((i
> 0) && apr_isspace(str
[i
-1]))
84 /* For one auto-props config entry (NAME, VALUE), if the filename pattern
85 NAME matches BATON->filename case insensitively then add the properties
86 listed in VALUE into BATON->properties.
87 BATON must point to an auto_props_baton_t.
90 auto_props_enumerator(const char *name
,
95 auto_props_baton_t
*autoprops
= baton
;
99 /* nothing to do here without a value */
100 if (strlen(value
) == 0)
103 /* check if filename matches and return if it doesn't */
104 if (apr_fnmatch(name
, autoprops
->filename
, APR_FNM_CASE_BLIND
) == APR_FNM_NOMATCH
)
107 /* parse the value (we dup it first to effectively lose the
108 'const', and to avoid messing up the original value) */
109 property
= apr_pstrdup(autoprops
->pool
, value
);
110 property
= apr_strtok(property
, ";", &last_token
);
114 const char *this_value
;
115 char *equal_sign
= strchr(property
, '=');
121 trim_string(&equal_sign
);
122 this_value
= equal_sign
;
128 trim_string(&property
);
129 len
= strlen(property
);
132 svn_string_t
*propval
= svn_string_create(this_value
,
135 apr_hash_set(autoprops
->properties
, property
, len
, propval
);
136 if (strcmp(property
, SVN_PROP_MIME_TYPE
) == 0)
137 autoprops
->mimetype
= this_value
;
138 else if (strcmp(property
, SVN_PROP_EXECUTABLE
) == 0)
139 autoprops
->have_executable
= TRUE
;
141 property
= apr_strtok(NULL
, ";", &last_token
);
147 svn_client__get_auto_props(apr_hash_t
**properties
,
148 const char **mimetype
,
150 svn_client_ctx_t
*ctx
,
154 svn_boolean_t use_autoprops
;
155 auto_props_baton_t autoprops
;
158 autoprops
.properties
= apr_hash_make(pool
);
159 autoprops
.filename
= svn_path_basename(path
, pool
);
160 autoprops
.pool
= pool
;
161 autoprops
.mimetype
= NULL
;
162 autoprops
.have_executable
= FALSE
;
163 *properties
= autoprops
.properties
;
165 cfg
= ctx
->config
? apr_hash_get(ctx
->config
, SVN_CONFIG_CATEGORY_CONFIG
,
166 APR_HASH_KEY_STRING
) : NULL
;
168 /* check that auto props is enabled */
169 SVN_ERR(svn_config_get_bool(cfg
, &use_autoprops
,
170 SVN_CONFIG_SECTION_MISCELLANY
,
171 SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS
, FALSE
));
173 /* search for auto props */
175 svn_config_enumerate2(cfg
, SVN_CONFIG_SECTION_AUTO_PROPS
,
176 auto_props_enumerator
, &autoprops
, pool
);
178 /* if mimetype has not been set check the file */
179 if (! autoprops
.mimetype
)
181 SVN_ERR(svn_io_detect_mimetype2(&autoprops
.mimetype
, path
,
182 ctx
->mimetypes_map
, pool
));
183 if (autoprops
.mimetype
)
184 apr_hash_set(autoprops
.properties
, SVN_PROP_MIME_TYPE
,
185 strlen(SVN_PROP_MIME_TYPE
),
186 svn_string_create(autoprops
.mimetype
, pool
));
189 /* Don't automatically set the svn:executable property on added items
190 * on OS400. While OS400 supports the executable permission its use is
191 * inconsistent at best. */
193 /* if executable has not been set check the file */
194 if (! autoprops
.have_executable
)
196 svn_boolean_t executable
= FALSE
;
197 SVN_ERR(svn_io_is_file_executable(&executable
, path
, pool
));
199 apr_hash_set(autoprops
.properties
, SVN_PROP_EXECUTABLE
,
200 strlen(SVN_PROP_EXECUTABLE
),
201 svn_string_create("", pool
));
205 *mimetype
= autoprops
.mimetype
;
210 add_file(const char *path
,
211 svn_client_ctx_t
*ctx
,
212 svn_wc_adm_access_t
*adm_access
,
215 apr_hash_t
* properties
;
216 apr_hash_index_t
*hi
;
217 const char *mimetype
;
218 svn_node_kind_t kind
;
219 svn_boolean_t is_special
;
221 /* Check to see if this is a special file. */
222 SVN_ERR(svn_io_check_special_path(path
, &kind
, &is_special
, pool
));
227 /* Get automatic properties */
228 /* This may fail on write-only files:
229 we open them to estimate file type.
230 That's why we postpone the add until after this step. */
231 SVN_ERR(svn_client__get_auto_props(&properties
, &mimetype
, path
, ctx
,
235 SVN_ERR(svn_wc_add2(path
, adm_access
, NULL
, SVN_INVALID_REVNUM
,
236 ctx
->cancel_func
, ctx
->cancel_baton
,
240 /* This must be a special file. */
241 SVN_ERR(svn_wc_prop_set2
243 svn_string_create(SVN_PROP_BOOLEAN_TRUE
, pool
),
244 path
, adm_access
, FALSE
, pool
));
247 /* loop through the hashtable and add the properties */
248 for (hi
= apr_hash_first(pool
, properties
);
249 hi
!= NULL
; hi
= apr_hash_next(hi
))
254 apr_hash_this(hi
, &pname
, NULL
, &pval
);
255 /* It's probably best to pass 0 for force, so that if
256 the autoprops say to set some weird combination,
257 we just error and let the user sort it out. */
258 SVN_ERR(svn_wc_prop_set2(pname
, pval
, path
,
259 adm_access
, FALSE
, pool
));
263 /* Report the addition to the caller. */
264 if (ctx
->notify_func2
!= NULL
)
266 svn_wc_notify_t
*notify
= svn_wc_create_notify(path
, svn_wc_notify_add
,
268 notify
->kind
= svn_node_file
;
269 notify
->mime_type
= mimetype
;
270 (*ctx
->notify_func2
)(ctx
->notify_baton2
, notify
, pool
);
276 /* Schedule directory DIRNAME, and some of the tree under it, for
277 * addition with access baton ADM_ACCESS. DEPTH is the depth at this
278 * point in the descent (it may be changed for recursive calls).
280 * If DIRNAME (or any item below directory DIRNAME) is already scheduled for
281 * addition, add will fail and return an error unless FORCE is TRUE.
283 * Files and directories that match ignore patterns will not be added unless
286 * If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to allow
287 * the user to cancel the operation
290 add_dir_recursive(const char *dirname
,
291 svn_wc_adm_access_t
*adm_access
,
294 svn_boolean_t no_ignore
,
295 svn_client_ctx_t
*ctx
,
299 apr_finfo_t this_entry
;
302 apr_int32_t flags
= APR_FINFO_TYPE
| APR_FINFO_NAME
;
303 svn_wc_adm_access_t
*dir_access
;
304 apr_array_header_t
*ignores
;
306 /* Check cancellation; note that this catches recursive calls too. */
307 if (ctx
->cancel_func
)
308 SVN_ERR(ctx
->cancel_func(ctx
->cancel_baton
));
310 /* Add this directory to revision control. */
311 err
= svn_wc_add2(dirname
, adm_access
,
312 NULL
, SVN_INVALID_REVNUM
,
313 ctx
->cancel_func
, ctx
->cancel_baton
,
314 ctx
->notify_func2
, ctx
->notify_baton2
, pool
);
315 if (err
&& err
->apr_err
== SVN_ERR_ENTRY_EXISTS
&& force
)
316 svn_error_clear(err
);
320 SVN_ERR(svn_wc_adm_retrieve(&dir_access
, adm_access
, dirname
, pool
));
323 SVN_ERR(svn_wc_get_ignores(&ignores
, ctx
->config
, dir_access
, pool
));
325 subpool
= svn_pool_create(pool
);
327 SVN_ERR(svn_io_dir_open(&dir
, dirname
, pool
));
329 /* Read the directory entries one by one and add those things to
333 const char *fullpath
;
335 svn_pool_clear(subpool
);
337 err
= svn_io_dir_read(&this_entry
, flags
, dir
, subpool
);
341 /* Check if we're done reading the dir's entries. */
342 if (APR_STATUS_IS_ENOENT(err
->apr_err
))
344 apr_status_t apr_err
;
346 svn_error_clear(err
);
347 apr_err
= apr_dir_close(dir
);
349 return svn_error_wrap_apr
350 (apr_err
, _("Can't close directory '%s'"),
351 svn_path_local_style(dirname
, subpool
));
356 return svn_error_createf
358 _("Error during add of '%s'"),
359 svn_path_local_style(dirname
, subpool
));
363 /* Skip entries for this dir and its parent. */
364 if (this_entry
.name
[0] == '.'
365 && (this_entry
.name
[1] == '\0'
366 || (this_entry
.name
[1] == '.' && this_entry
.name
[2] == '\0')))
369 /* Check cancellation so you can cancel during an
370 * add of a directory with lots of files. */
371 if (ctx
->cancel_func
)
372 SVN_ERR(ctx
->cancel_func(ctx
->cancel_baton
));
374 /* Skip over SVN admin directories. */
375 if (svn_wc_is_adm_dir(this_entry
.name
, subpool
))
378 if ((!no_ignore
) && svn_wc_match_ignore_list(this_entry
.name
,
382 /* Construct the full path of the entry. */
383 fullpath
= svn_path_join(dirname
, this_entry
.name
, subpool
);
385 /* Recurse on directories; add files; ignore the rest. */
386 if (this_entry
.filetype
== APR_DIR
&& depth
>= svn_depth_immediates
)
388 svn_depth_t depth_below_here
= depth
;
389 if (depth
== svn_depth_immediates
)
390 depth_below_here
= svn_depth_empty
;
392 SVN_ERR(add_dir_recursive(fullpath
, dir_access
, depth_below_here
,
393 force
, no_ignore
, ctx
, subpool
));
395 else if (this_entry
.filetype
!= APR_UNKFILE
396 && this_entry
.filetype
!= APR_DIR
397 && depth
>= svn_depth_files
)
399 err
= add_file(fullpath
, ctx
, dir_access
, subpool
);
400 if (err
&& err
->apr_err
== SVN_ERR_ENTRY_EXISTS
&& force
)
401 svn_error_clear(err
);
407 /* Opened by svn_wc_add */
408 SVN_ERR(svn_wc_adm_close(dir_access
));
410 /* Destroy the per-iteration pool. */
411 svn_pool_destroy(subpool
);
417 /* The main logic of the public svn_client_add4; the only difference
418 is that this function uses an existing access baton.
419 (svn_client_add4 just generates an access baton and calls this func.) */
421 add(const char *path
,
424 svn_boolean_t no_ignore
,
425 svn_wc_adm_access_t
*adm_access
,
426 svn_client_ctx_t
*ctx
,
429 svn_node_kind_t kind
;
432 SVN_ERR(svn_io_check_path(path
, &kind
, pool
));
433 if (kind
== svn_node_dir
&& depth
>= svn_depth_files
)
434 err
= add_dir_recursive(path
, adm_access
, depth
,
435 force
, no_ignore
, ctx
, pool
);
436 else if (kind
== svn_node_file
)
437 err
= add_file(path
, ctx
, adm_access
, pool
);
439 err
= svn_wc_add2(path
, adm_access
, NULL
, SVN_INVALID_REVNUM
,
440 ctx
->cancel_func
, ctx
->cancel_baton
,
441 ctx
->notify_func2
, ctx
->notify_baton2
, pool
);
443 /* Ignore SVN_ERR_ENTRY_EXISTS when FORCE is set. */
444 if (err
&& err
->apr_err
== SVN_ERR_ENTRY_EXISTS
&& force
)
446 svn_error_clear(err
);
453 /* Go up the directory tree, looking for a versioned directory. If found,
454 add all the intermediate directories. Otherwise, return
455 SVN_ERR_CLIENT_NO_VERSIONED_PARENT. */
457 add_parent_dirs(const char *path
,
458 svn_wc_adm_access_t
**parent_access
,
459 svn_client_ctx_t
*ctx
,
462 svn_wc_adm_access_t
*adm_access
;
465 err
= svn_wc_adm_open3(&adm_access
, NULL
, path
, TRUE
, 0,
466 ctx
->cancel_func
, ctx
->cancel_baton
, pool
);
468 if (err
&& err
->apr_err
== SVN_ERR_WC_NOT_DIRECTORY
)
470 if (svn_dirent_is_root(path
, strlen(path
)))
472 svn_error_clear(err
);
474 return svn_error_create
475 (SVN_ERR_CLIENT_NO_VERSIONED_PARENT
, NULL
, NULL
);
479 const char *parent_path
= svn_path_dirname(path
, pool
);
481 svn_error_clear(err
);
482 SVN_ERR(add_parent_dirs(parent_path
, &adm_access
, ctx
, pool
));
483 SVN_ERR(svn_wc_adm_retrieve(&adm_access
, adm_access
, parent_path
,
485 SVN_ERR(svn_wc_add2(path
, adm_access
, NULL
, SVN_INVALID_REVNUM
,
486 ctx
->cancel_func
, ctx
->cancel_baton
,
487 ctx
->notify_func2
, ctx
->notify_baton2
, pool
));
496 *parent_access
= adm_access
;
504 svn_client_add4(const char *path
,
507 svn_boolean_t no_ignore
,
508 svn_boolean_t add_parents
,
509 svn_client_ctx_t
*ctx
,
512 svn_error_t
*err
, *err2
;
513 svn_wc_adm_access_t
*adm_access
;
514 const char *parent_dir
;
520 SVN_ERR(svn_path_get_absolute(&path
, path
, pool
));
521 parent_dir
= svn_path_dirname(path
, pool
);
523 subpool
= svn_pool_create(pool
);
524 SVN_ERR(add_parent_dirs(parent_dir
, &adm_access
, ctx
, subpool
));
525 SVN_ERR(svn_wc_adm_close(adm_access
));
526 svn_pool_destroy(subpool
);
528 SVN_ERR(svn_wc_adm_open3(&adm_access
, NULL
, parent_dir
,
529 TRUE
, 0, ctx
->cancel_func
, ctx
->cancel_baton
,
534 parent_dir
= svn_path_dirname(path
, pool
);
535 SVN_ERR(svn_wc_adm_open3(&adm_access
, NULL
, parent_dir
,
536 TRUE
, 0, ctx
->cancel_func
, ctx
->cancel_baton
,
540 err
= add(path
, depth
, force
, no_ignore
, adm_access
, ctx
, pool
);
542 err2
= svn_wc_adm_close(adm_access
);
546 svn_error_clear(err2
);
555 svn_client_add3(const char *path
,
556 svn_boolean_t recursive
,
558 svn_boolean_t no_ignore
,
559 svn_client_ctx_t
*ctx
,
562 return svn_client_add4(path
, SVN_DEPTH_INFINITY_OR_FILES(recursive
),
563 force
, no_ignore
, FALSE
, ctx
,
568 svn_client_add2(const char *path
,
569 svn_boolean_t recursive
,
571 svn_client_ctx_t
*ctx
,
574 return svn_client_add3(path
, recursive
, force
, FALSE
, ctx
, pool
);
578 svn_client_add(const char *path
,
579 svn_boolean_t recursive
,
580 svn_client_ctx_t
*ctx
,
583 return svn_client_add3(path
, recursive
, FALSE
, FALSE
, ctx
, pool
);
588 path_driver_cb_func(void **dir_baton
,
590 void *callback_baton
,
594 const svn_delta_editor_t
*editor
= callback_baton
;
595 SVN_ERR(svn_path_check_valid(path
, pool
));
596 return editor
->add_directory(path
, parent_baton
, NULL
,
597 SVN_INVALID_REVNUM
, pool
, dir_baton
);
600 /* Append URL, and all it's non-existent parent directories, to TARGETS.
601 Use TEMPPOOL for temporary allocations and POOL for any additions to
604 add_url_parents(svn_ra_session_t
*ra_session
,
606 apr_array_header_t
*targets
,
607 apr_pool_t
*temppool
,
610 svn_node_kind_t kind
;
611 const char *parent_url
;
613 svn_path_split(url
, &parent_url
, NULL
, pool
);
615 SVN_ERR(svn_ra_reparent(ra_session
, parent_url
, temppool
));
616 SVN_ERR(svn_ra_check_path(ra_session
, "", SVN_INVALID_REVNUM
, &kind
,
619 if (kind
== svn_node_none
)
620 SVN_ERR(add_url_parents(ra_session
, parent_url
, targets
, temppool
, pool
));
622 APR_ARRAY_PUSH(targets
, const char *) = url
;
628 mkdir_urls(svn_commit_info_t
**commit_info_p
,
629 const apr_array_header_t
*urls
,
630 svn_boolean_t make_parents
,
631 svn_client_ctx_t
*ctx
,
634 svn_ra_session_t
*ra_session
= NULL
;
635 const svn_delta_editor_t
*editor
;
639 apr_hash_t
*revprop_table
;
640 apr_array_header_t
*targets
;
641 apr_hash_t
*targets_hash
;
646 /* Find any non-existent parent directories */
649 apr_array_header_t
*all_urls
= apr_array_make(pool
, urls
->nelts
,
650 sizeof(const char *));
651 const char *first_url
= APR_ARRAY_IDX(urls
, 0, const char *);
652 apr_pool_t
*iterpool
= svn_pool_create(pool
);
654 SVN_ERR(svn_client__open_ra_session_internal(&ra_session
, first_url
,
655 NULL
, NULL
, NULL
, FALSE
,
658 for (i
= 0; i
< urls
->nelts
; i
++)
660 const char *url
= APR_ARRAY_IDX(urls
, i
, const char *);
662 svn_pool_clear(iterpool
);
663 SVN_ERR(add_url_parents(ra_session
, url
, all_urls
, iterpool
, pool
));
666 svn_pool_destroy(iterpool
);
671 /* Condense our list of mkdir targets. */
672 SVN_ERR(svn_path_condense_targets(&common
, &targets
, urls
, FALSE
, pool
));
673 SVN_ERR(svn_hash_from_cstring_keys(&targets_hash
, targets
, pool
));
674 SVN_ERR(svn_hash_keys(&targets
, targets_hash
, pool
));
676 if (! targets
->nelts
)
679 svn_path_split(common
, &common
, &bname
, pool
);
680 APR_ARRAY_PUSH(targets
, const char *) = bname
;
684 svn_boolean_t resplit
= FALSE
;
686 /* We can't "mkdir" the root of an editor drive, so if one of
687 our targets is the empty string, we need to back everything
688 up by a path component. */
689 for (i
= 0; i
< targets
->nelts
; i
++)
691 const char *path
= APR_ARRAY_IDX(targets
, i
, const char *);
701 svn_path_split(common
, &common
, &bname
, pool
);
702 for (i
= 0; i
< targets
->nelts
; i
++)
704 const char *path
= APR_ARRAY_IDX(targets
, i
, const char *);
705 path
= svn_path_join(bname
, path
, pool
);
706 APR_ARRAY_IDX(targets
, i
, const char *) = path
;
710 qsort(targets
->elts
, targets
->nelts
, targets
->elt_size
,
711 svn_sort_compare_paths
);
713 /* Create new commit items and add them to the array. */
714 if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx
))
716 svn_client_commit_item3_t
*item
;
717 const char *tmp_file
;
718 apr_array_header_t
*commit_items
719 = apr_array_make(pool
, targets
->nelts
, sizeof(item
));
721 for (i
= 0; i
< targets
->nelts
; i
++)
723 const char *path
= APR_ARRAY_IDX(targets
, i
, const char *);
724 SVN_ERR(svn_client_commit_item_create
725 ((const svn_client_commit_item3_t
**) &item
, pool
));
726 item
->url
= svn_path_join(common
, path
, pool
);
727 item
->state_flags
= SVN_CLIENT_COMMIT_ITEM_ADD
;
728 APR_ARRAY_PUSH(commit_items
, svn_client_commit_item3_t
*) = item
;
731 SVN_ERR(svn_client__get_log_msg(&log_msg
, &tmp_file
, commit_items
,
740 SVN_ERR(svn_client__get_revprop_table(&revprop_table
, log_msg
, ctx
, pool
));
742 /* Open an RA session for the URL. Note that we don't have a local
743 directory, nor a place to put temp files. */
745 SVN_ERR(svn_client__open_ra_session_internal(&ra_session
, common
, NULL
,
746 NULL
, NULL
, FALSE
, TRUE
,
749 /* URI-decode each target. */
750 for (i
= 0; i
< targets
->nelts
; i
++)
752 const char *path
= APR_ARRAY_IDX(targets
, i
, const char *);
753 path
= svn_path_uri_decode(path
, pool
);
754 APR_ARRAY_IDX(targets
, i
, const char *) = path
;
757 /* Fetch RA commit editor */
758 SVN_ERR(svn_client__commit_get_baton(&commit_baton
, commit_info_p
, pool
));
759 SVN_ERR(svn_ra_get_commit_editor3(ra_session
, &editor
, &edit_baton
,
761 svn_client__commit_callback
,
763 NULL
, TRUE
, /* No lock tokens */
766 /* Call the path-based editor driver. */
767 err
= svn_delta_path_driver(editor
, edit_baton
, SVN_INVALID_REVNUM
,
768 targets
, path_driver_cb_func
,
769 (void *)editor
, pool
);
772 /* At least try to abort the edit (and fs txn) before throwing err. */
773 svn_error_clear(editor
->abort_edit(edit_baton
, pool
));
777 /* Close the edit. */
778 SVN_ERR(editor
->close_edit(edit_baton
, pool
));
786 svn_client__make_local_parents(const char *path
,
787 svn_boolean_t make_parents
,
788 svn_client_ctx_t
*ctx
,
794 SVN_ERR(svn_io_make_dir_recursively(path
, pool
));
796 SVN_ERR(svn_io_dir_make(path
, APR_OS_DEFAULT
, pool
));
798 err
= svn_client_add4(path
, svn_depth_empty
, FALSE
, FALSE
,
799 make_parents
, ctx
, pool
);
801 /* We just created a new directory, but couldn't add it to
802 version control. Don't leave unversioned directories behind. */
805 /* ### If this returns an error, should we link it onto
806 err instead, so that the user is warned that we just
807 created an unversioned directory? */
809 svn_error_clear(svn_io_remove_dir(path
, pool
));
817 svn_client_mkdir3(svn_commit_info_t
**commit_info_p
,
818 const apr_array_header_t
*paths
,
819 svn_boolean_t make_parents
,
820 svn_client_ctx_t
*ctx
,
826 if (svn_path_is_url(APR_ARRAY_IDX(paths
, 0, const char *)))
828 SVN_ERR(mkdir_urls(commit_info_p
, paths
, make_parents
, ctx
, pool
));
832 /* This is a regular "mkdir" + "svn add" */
833 apr_pool_t
*subpool
= svn_pool_create(pool
);
836 for (i
= 0; i
< paths
->nelts
; i
++)
838 const char *path
= APR_ARRAY_IDX(paths
, i
, const char *);
840 svn_pool_clear(subpool
);
842 /* See if the user wants us to stop. */
843 if (ctx
->cancel_func
)
844 SVN_ERR(ctx
->cancel_func(ctx
->cancel_baton
));
846 SVN_ERR(svn_client__make_local_parents(path
, make_parents
, ctx
,
849 svn_pool_destroy(subpool
);
857 svn_client_mkdir2(svn_commit_info_t
**commit_info_p
,
858 const apr_array_header_t
*paths
,
859 svn_client_ctx_t
*ctx
,
862 return svn_client_mkdir3(commit_info_p
, paths
, FALSE
, ctx
, pool
);
867 svn_client_mkdir(svn_client_commit_info_t
**commit_info_p
,
868 const apr_array_header_t
*paths
,
869 svn_client_ctx_t
*ctx
,
872 svn_commit_info_t
*commit_info
= NULL
;
875 err
= svn_client_mkdir2(&commit_info
, paths
, ctx
, pool
);
876 /* These structs have the same layout for the common fields. */
877 *commit_info_p
= (svn_client_commit_info_t
*) commit_info
;