154
134
*props = temp_props;
157
/* For one auto-props config entry (NAME, VALUE), if the filename pattern
158
NAME matches BATON->filename case insensitively then add the properties
159
listed in VALUE into BATON->properties.
160
BATON must point to an auto_props_baton_t.
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.
163
auto_props_enumerator(const char *name,
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)
169
auto_props_baton_t *autoprops = baton;
170
apr_array_header_t *props;
172
/* nothing to do here without a value */
160
apr_hash_index_t *hi;
176
162
/* check if filename matches and return if it doesn't */
177
if (apr_fnmatch(name, autoprops->filename, APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
180
split_props(&props, value, autoprops->pool);
182
for (i = 0; i < props->nelts; i++)
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))
185
const char *this_value;
186
char *property = APR_ARRAY_IDX(props, i, char *);
187
char *equal_sign = strchr(property, '=');
193
trim_string(&equal_sign);
194
unquote_string(&equal_sign);
195
this_value = equal_sign;
201
trim_string(&property);
202
len = strlen(property);
206
svn_string_t *propval = apr_palloc(autoprops->pool,
208
propval->data = this_value;
209
propval->len = strlen(this_value);
211
apr_hash_set(autoprops->properties, property, len, propval);
212
if (strcmp(property, SVN_PROP_MIME_TYPE) == 0)
213
autoprops->mimetype = this_value;
214
else if (strcmp(property, SVN_PROP_EXECUTABLE) == 0)
215
autoprops->have_executable = TRUE;
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;
222
svn_client__get_auto_props(apr_hash_t **properties,
223
const char **mimetype,
225
svn_magic__cookie_t *magic_cookie,
226
svn_client_ctx_t *ctx,
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)
230
svn_boolean_t use_autoprops;
231
auto_props_baton_t autoprops;
234
autoprops.properties = apr_hash_make(pool);
235
autoprops.filename = svn_dirent_basename(path, pool);
236
autoprops.pool = pool;
237
autoprops.mimetype = NULL;
238
autoprops.have_executable = FALSE;
239
*properties = autoprops.properties;
241
cfg = ctx->config ? apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
242
APR_HASH_KEY_STRING) : NULL;
244
/* check that auto props is enabled */
245
SVN_ERR(svn_config_get_bool(cfg, &use_autoprops,
246
SVN_CONFIG_SECTION_MISCELLANY,
247
SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS, FALSE));
249
/* search for auto props */
251
svn_config_enumerate2(cfg, SVN_CONFIG_SECTION_AUTO_PROPS,
252
auto_props_enumerator, &autoprops, 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);
254
218
/* if mimetype has not been set check the file */
255
if (! autoprops.mimetype)
257
SVN_ERR(svn_io_detect_mimetype2(&autoprops.mimetype, path,
258
ctx->mimetypes_map, pool));
221
SVN_ERR(svn_io_detect_mimetype2(mimetype, path, ctx->mimetypes_map,
260
224
/* If we got no mime-type, or if it is "application/octet-stream",
261
225
* try to get the mime-type from libmagic. */
262
226
if (magic_cookie &&
263
(!autoprops.mimetype ||
264
strcmp(autoprops.mimetype, "application/octet-stream") == 0))
228
strcmp(*mimetype, "application/octet-stream") == 0))
266
230
const char *magic_mimetype;
316
281
/* Check to see if this is a special file. */
317
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));
322
/* Get automatic properties */
323
/* This may fail on write-only files:
324
we open them to estimate file type.
325
That's why we postpone the add until after this step. */
326
SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, local_abspath,
327
magic_cookie, ctx, 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,
329
318
/* Add the file */
330
SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
334
/* This must be a special file. */
335
SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath, SVN_PROP_SPECIAL,
336
svn_string_create(SVN_PROP_BOOLEAN_TRUE, pool),
337
svn_depth_empty, FALSE, NULL,
338
NULL, NULL /* cancellation */,
339
NULL, NULL /* notification */,
343
/* loop through the hashtable and add the properties */
344
for (hi = apr_hash_first(pool, properties);
345
hi != NULL; hi = apr_hash_next(hi))
347
const char *pname = svn__apr_hash_index_key(hi);
348
const svn_string_t *pval = svn__apr_hash_index_val(hi);
351
/* It's probably best to pass 0 for force, so that if
352
the autoprops say to set some weird combination,
353
we just error and let the user sort it out. */
354
err = svn_wc_prop_set4(ctx->wc_ctx, local_abspath, pname, pval,
355
svn_depth_empty, FALSE, NULL,
356
NULL, NULL /* cancellation */,
357
NULL, NULL /* notification */,
361
/* Don't leave the job half-done. If we fail to set a property,
362
* (try to) un-add the file. */
363
svn_error_clear(svn_wc_revert4(ctx->wc_ctx,
366
FALSE /* use_commit_times */,
367
NULL /* changelists */,
368
NULL, NULL, NULL, NULL,
370
return svn_error_trace(err);
375
/* Report the addition to the caller. */
376
if (ctx->notify_func2 != NULL)
378
svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath,
379
svn_wc_notify_add, pool);
380
notify->kind = svn_node_file;
381
notify->mime_type = mimetype;
382
(*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
319
SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, local_abspath, properties,
320
ctx->notify_func2, ctx->notify_baton2, pool));
385
322
return SVN_NO_ERROR;
388
325
/* Schedule directory DIR_ABSPATH, and some of the tree under it, for
389
* addition. DEPTH is the depth at this
390
* point in the descent (it may be changed for recursive calls).
326
* addition. DEPTH is the depth at this point in the descent (it may
327
* be changed for recursive calls).
392
329
* If DIR_ABSPATH (or any item below DIR_ABSPATH) is already scheduled for
393
330
* addition, add will fail and return an error unless FORCE is TRUE.
395
* Files and directories that match ignore patterns will not be added unless
398
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.
401
350
* If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to allow
402
* the user to cancel the operation
351
* the user to cancel the operation.
353
* Use SCRATCH_POOL for temporary allocations.
404
355
static svn_error_t *
405
356
add_dir_recursive(const char *dir_abspath,
406
357
svn_depth_t depth,
407
358
svn_boolean_t force,
408
svn_boolean_t no_ignore,
359
svn_boolean_t no_autoprops,
409
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,
410
364
svn_client_ctx_t *ctx,
365
apr_pool_t *result_pool,
411
366
apr_pool_t *scratch_pool)
413
368
svn_error_t *err;
414
369
apr_pool_t *iterpool;
415
apr_array_header_t *ignores;
416
370
apr_hash_t *dirents;
417
371
apr_hash_index_t *hi;
372
svn_boolean_t entry_exists = FALSE;
419
374
/* Check cancellation; note that this catches recursive calls too. */
420
375
if (ctx->cancel_func)
493
484
return SVN_NO_ERROR;
497
struct add_with_write_lock_baton {
498
const char *local_abspath;
501
svn_boolean_t no_ignore;
502
svn_client_ctx_t *ctx;
504
/* Absolute path to the first existing parent directory of local_abspath.
505
* If not NULL, all missing parents of local_abspath must be created
506
* before local_abspath can be added. */
507
const char *existing_parent_abspath;
510
/* The main logic of the public svn_client_add4. */
512
add(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
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)
514
839
svn_node_kind_t kind;
515
840
svn_error_t *err;
516
struct add_with_write_lock_baton *b = baton;
517
841
svn_magic__cookie_t *magic_cookie;
842
apr_array_header_t *ignores = NULL;
519
844
svn_magic__init(&magic_cookie, scratch_pool);
521
if (b->existing_parent_abspath)
846
if (existing_parent_abspath)
523
848
const char *parent_abspath;
524
849
const char *child_relpath;
548
873
if (disk_kind != svn_node_none && disk_kind != svn_node_dir)
549
874
return svn_error_createf(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL,
550
875
_("'%s' prevents creating parent of '%s'"),
551
parent_abspath, b->local_abspath);
876
parent_abspath, local_abspath);
553
878
SVN_ERR(svn_io_make_dir_recursively(parent_abspath, scratch_pool));
554
SVN_ERR(svn_wc_add_from_disk(b->ctx->wc_ctx, parent_abspath,
555
b->ctx->notify_func2,
556
b->ctx->notify_baton2,
879
SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, parent_abspath,
881
ctx->notify_func2, ctx->notify_baton2,
559
884
svn_pool_destroy(iterpool);
562
SVN_ERR(svn_io_check_path(b->local_abspath, &kind, scratch_pool));
887
SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
563
888
if (kind == svn_node_dir)
565
890
/* We use add_dir_recursive for all directory targets
566
891
and pass depth along no matter what it is, so that the
567
892
target's depth will be set correctly. */
568
err = add_dir_recursive(b->local_abspath, b->depth,
569
b->force, b->no_ignore, magic_cookie, b->ctx,
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);
572
898
else if (kind == svn_node_file)
573
err = add_file(b->local_abspath, magic_cookie, b->ctx, scratch_pool);
899
err = add_file(local_abspath, magic_cookie, NULL,
900
no_autoprops, ctx, scratch_pool);
574
901
else if (kind == svn_node_none)
576
903
svn_boolean_t tree_conflicted;
614
/* Go up the directory tree from LOCAL_ABSPATH, looking for a versioned
615
* directory. If found, return its path in *EXISTING_PARENT_ABSPATH.
616
* Otherwise, return SVN_ERR_CLIENT_NO_VERSIONED_PARENT. */
618
find_existing_parent(const char **existing_parent_abspath,
619
svn_client_ctx_t *ctx,
620
const char *local_abspath,
621
apr_pool_t *result_pool,
622
apr_pool_t *scratch_pool)
624
svn_node_kind_t kind;
625
const char *parent_abspath;
626
svn_wc_context_t *wc_ctx = ctx->wc_ctx;
628
SVN_ERR(svn_wc_read_kind(&kind, wc_ctx, local_abspath, FALSE, scratch_pool));
630
if (kind == svn_node_dir)
632
svn_boolean_t is_deleted;
634
SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted,
635
wc_ctx, local_abspath,
639
*existing_parent_abspath = apr_pstrdup(result_pool, local_abspath);
644
if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
645
return svn_error_create(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL, NULL);
647
if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
649
return svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED, NULL,
650
_("'%s' ends in a reserved name"),
651
svn_dirent_local_style(local_abspath,
654
parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
656
if (ctx->cancel_func)
657
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
659
SVN_ERR(find_existing_parent(existing_parent_abspath, ctx, parent_abspath,
660
result_pool, scratch_pool));
668
svn_client_add4(const char *path,
943
svn_client_add5(const char *path,
669
944
svn_depth_t depth,
670
945
svn_boolean_t force,
671
946
svn_boolean_t no_ignore,
947
svn_boolean_t no_autoprops,
672
948
svn_boolean_t add_parents,
673
949
svn_client_ctx_t *ctx,
950
apr_pool_t *scratch_pool)
676
952
const char *parent_abspath;
677
953
const char *local_abspath;
678
struct add_with_write_lock_baton baton;
954
const char *existing_parent_abspath;
955
svn_boolean_t is_wc_root;
680
958
if (svn_path_is_url(path))
681
959
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
682
960
_("'%s' is not a local path"), path);
684
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
686
/* ### this is a hack.
687
### before we switched to absolute paths, if a user tried to do
688
### 'svn add .', PATH would be "" and PARENT_PATH would also be "",
689
### thus emulating the behavior below. Now that we are using
690
### absolute paths, svn_dirent_dirname() doesn't behave the same way
691
### w.r.t. '.', so we need to include the following hack. This
692
### behavior is tested in schedule_tests-11. */
694
parent_abspath = local_abspath;
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 */
696
parent_abspath = svn_dirent_dirname(local_abspath, pool);
1010
parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
698
baton.existing_parent_abspath = NULL;
1012
existing_parent_abspath = NULL;
1013
if (add_parents && !is_wc_root)
701
1015
apr_pool_t *subpool;
702
const char *existing_parent_abspath;
1016
const char *existing_parent_abspath2;
704
subpool = svn_pool_create(pool);
705
SVN_ERR(find_existing_parent(&existing_parent_abspath, ctx,
706
parent_abspath, pool, subpool));
707
if (strcmp(existing_parent_abspath, parent_abspath) != 0)
708
baton.existing_parent_abspath = existing_parent_abspath;
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;
709
1023
svn_pool_destroy(subpool);
712
baton.local_abspath = local_abspath;
715
baton.no_ignore = no_ignore;
717
SVN_ERR(svn_wc__call_with_write_lock(add, &baton, ctx->wc_ctx,
718
baton.existing_parent_abspath
719
? baton.existing_parent_abspath
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);
722
1032
return SVN_NO_ERROR;