~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_client/add.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
 
48
48
#include "private/svn_client_private.h"
49
49
#include "private/svn_wc_private.h"
 
50
#include "private/svn_ra_private.h"
50
51
#include "private/svn_magic.h"
51
52
 
52
53
#include "svn_private_config.h"
55
56
 
56
57
/*** Code. ***/
57
58
 
58
 
/* This structure is used as baton for enumerating the config entries
59
 
   in the auto-props section.
60
 
*/
61
 
typedef struct auto_props_baton_t
62
 
{
63
 
  /* the file name for which properties are searched */
64
 
  const char *filename;
65
 
 
66
 
  /* when this flag is set the hash contains svn:executable */
67
 
  svn_boolean_t have_executable;
68
 
 
69
 
  /* when mimetype is not NULL is set the hash contains svn:mime-type */
70
 
  const char *mimetype;
71
 
 
72
 
  /* the hash table for storing the property name/value pairs */
73
 
  apr_hash_t *properties;
74
 
 
75
 
  /* a pool used for allocating memory */
76
 
  apr_pool_t *pool;
77
 
} auto_props_baton_t;
78
 
 
79
59
/* Remove leading and trailing white space from a C string, in place. */
80
60
static void
81
61
trim_string(char **pstr)
154
134
  *props = temp_props;
155
135
}
156
136
 
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.
 
139
 
 
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.
 
148
 
 
149
   Use SCRATCH_POOL for temporary allocations.
161
150
*/
162
 
static svn_boolean_t
163
 
auto_props_enumerator(const char *name,
164
 
                      const char *value,
165
 
                      void *baton,
166
 
                      apr_pool_t *pool)
 
151
static void
 
152
get_auto_props_for_pattern(apr_hash_t *properties,
 
153
                           const char **mimetype,
 
154
                           svn_boolean_t *have_executable,
 
155
                           const char *filename,
 
156
                           const char *pattern,
 
157
                           apr_hash_t *propvals,
 
158
                           apr_pool_t *scratch_pool)
167
159
{
168
 
  int i;
169
 
  auto_props_baton_t *autoprops = baton;
170
 
  apr_array_header_t *props;
171
 
 
172
 
  /* nothing to do here without a value */
173
 
  if (*value == 0)
174
 
    return TRUE;
 
160
  apr_hash_index_t *hi;
175
161
 
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)
178
 
    return TRUE;
179
 
 
180
 
  split_props(&props, value, autoprops->pool);
181
 
 
182
 
  for (i = 0; i < props->nelts; i++)
 
163
  if (apr_fnmatch(pattern, filename,
 
164
                  APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
 
165
    return;
 
166
 
 
167
  for (hi = apr_hash_first(scratch_pool, propvals);
 
168
       hi != NULL;
 
169
       hi = apr_hash_next(hi))
183
170
    {
184
 
      size_t len;
185
 
      const char *this_value;
186
 
      char *property = APR_ARRAY_IDX(props, i, char *);
187
 
      char *equal_sign = strchr(property, '=');
188
 
 
189
 
      if (equal_sign)
190
 
        {
191
 
          *equal_sign = '\0';
192
 
          equal_sign++;
193
 
          trim_string(&equal_sign);
194
 
          unquote_string(&equal_sign);
195
 
          this_value = equal_sign;
196
 
        }
197
 
      else
198
 
        {
199
 
          this_value = "";
200
 
        }
201
 
      trim_string(&property);
202
 
      len = strlen(property);
203
 
 
204
 
      if (len > 0)
205
 
        {
206
 
          svn_string_t *propval = apr_palloc(autoprops->pool,
207
 
                                             sizeof(*propval));
208
 
          propval->data = this_value;
209
 
          propval->len = strlen(this_value);
210
 
 
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;
216
 
        }
 
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));
 
175
 
 
176
      propval_str->data = propval;
 
177
      propval_str->len = strlen(propval);
 
178
 
 
179
      svn_hash_sets(properties, propname, propval_str);
 
180
      if (strcmp(propname, SVN_PROP_MIME_TYPE) == 0)
 
181
        *mimetype = propval;
 
182
      else if (strcmp(propname, SVN_PROP_EXECUTABLE) == 0)
 
183
        *have_executable = TRUE;
217
184
    }
218
 
  return TRUE;
219
185
}
220
186
 
221
187
svn_error_t *
222
 
svn_client__get_auto_props(apr_hash_t **properties,
223
 
                           const char **mimetype,
224
 
                           const char *path,
225
 
                           svn_magic__cookie_t *magic_cookie,
226
 
                           svn_client_ctx_t *ctx,
227
 
                           apr_pool_t *pool)
 
188
svn_client__get_paths_auto_props(apr_hash_t **properties,
 
189
                                 const char **mimetype,
 
190
                                 const char *path,
 
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)
228
196
{
229
 
  svn_config_t *cfg;
230
 
  svn_boolean_t use_autoprops;
231
 
  auto_props_baton_t autoprops;
232
 
 
233
 
  /* initialisation */
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;
240
 
 
241
 
  cfg = ctx->config ? apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
242
 
                                   APR_HASH_KEY_STRING) : NULL;
243
 
 
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));
248
 
 
249
 
  /* search for auto props */
250
 
  if (use_autoprops)
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;
 
199
 
 
200
  *properties = apr_hash_make(result_pool);
 
201
  *mimetype = NULL;
 
202
 
 
203
  if (autoprops)
 
204
    {
 
205
      for (hi = apr_hash_first(scratch_pool, autoprops);
 
206
           hi != NULL;
 
207
           hi = apr_hash_next(hi))
 
208
        {
 
209
          const char *pattern = svn__apr_hash_index_key(hi);
 
210
          apr_hash_t *propvals = svn__apr_hash_index_val(hi);
 
211
 
 
212
          get_auto_props_for_pattern(*properties, mimetype, &have_executable,
 
213
                                     svn_dirent_basename(path, scratch_pool),
 
214
                                     pattern, propvals, scratch_pool);
 
215
        }
 
216
    }
253
217
 
254
218
  /* if mimetype has not been set check the file */
255
 
  if (! autoprops.mimetype)
 
219
  if (! *mimetype)
256
220
    {
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,
 
222
                                      result_pool));
259
223
 
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))
 
227
          (!*mimetype ||
 
228
           strcmp(*mimetype, "application/octet-stream") == 0))
265
229
        {
266
230
          const char *magic_mimetype;
267
231
 
274
238
          * returns "text/plain" for them. */
275
239
          SVN_ERR(svn_magic__detect_binary_mimetype(&magic_mimetype,
276
240
                                                    path, magic_cookie,
277
 
                                                    pool, pool));
 
241
                                                    result_pool,
 
242
                                                    scratch_pool));
278
243
          if (magic_mimetype)
279
 
            autoprops.mimetype = magic_mimetype;
 
244
            *mimetype = magic_mimetype;
280
245
        }
281
246
 
282
 
      if (autoprops.mimetype)
283
 
        apr_hash_set(autoprops.properties, SVN_PROP_MIME_TYPE,
 
247
      if (*mimetype)
 
248
        apr_hash_set(*properties, SVN_PROP_MIME_TYPE,
284
249
                     strlen(SVN_PROP_MIME_TYPE),
285
 
                     svn_string_create(autoprops.mimetype, pool));
 
250
                     svn_string_create(*mimetype, result_pool));
286
251
    }
287
252
 
288
253
  /* if executable has not been set check the file */
289
 
  if (! autoprops.have_executable)
 
254
  if (! have_executable)
290
255
    {
291
256
      svn_boolean_t executable = FALSE;
292
 
      SVN_ERR(svn_io_is_file_executable(&executable, path, pool));
 
257
      SVN_ERR(svn_io_is_file_executable(&executable, path, scratch_pool));
293
258
      if (executable)
294
 
        apr_hash_set(autoprops.properties, SVN_PROP_EXECUTABLE,
 
259
        apr_hash_set(*properties, SVN_PROP_EXECUTABLE,
295
260
                     strlen(SVN_PROP_EXECUTABLE),
296
 
                     svn_string_create("", pool));
 
261
                     svn_string_create_empty(result_pool));
297
262
    }
298
263
 
299
 
  *mimetype = autoprops.mimetype;
300
264
  return SVN_NO_ERROR;
301
265
}
302
266
 
304
268
static svn_error_t *
305
269
add_file(const char *local_abspath,
306
270
         svn_magic__cookie_t *magic_cookie,
 
271
         apr_hash_t *autoprops,
 
272
         svn_boolean_t no_autoprops,
307
273
         svn_client_ctx_t *ctx,
308
274
         apr_pool_t *pool)
309
275
{
310
 
  apr_hash_t* properties;
311
 
  apr_hash_index_t *hi;
 
276
  apr_hash_t *properties;
312
277
  const char *mimetype;
313
278
  svn_node_kind_t kind;
314
279
  svn_boolean_t is_special;
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));
318
283
 
 
284
  /* Determine the properties that the file should have */
319
285
  if (is_special)
320
 
    mimetype = NULL;
 
286
    {
 
287
      mimetype = NULL;
 
288
      properties = apr_hash_make(pool);
 
289
      svn_hash_sets(properties, SVN_PROP_SPECIAL,
 
290
                    svn_string_create(SVN_PROP_BOOLEAN_TRUE, pool));
 
291
    }
321
292
  else
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));
 
293
    {
 
294
      apr_hash_t *file_autoprops = NULL;
 
295
 
 
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. */
 
300
      if (!no_autoprops)
 
301
        {
 
302
          if (autoprops == NULL)
 
303
            SVN_ERR(svn_client__get_all_auto_props(
 
304
              &file_autoprops, svn_dirent_dirname(local_abspath,pool),
 
305
              ctx, pool, pool));
 
306
          else
 
307
            file_autoprops = autoprops;
 
308
        }
 
309
 
 
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,
 
315
                                               pool));
 
316
    }
328
317
 
329
318
  /* Add the file */
330
 
  SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
331
 
                               NULL, NULL, pool));
332
 
 
333
 
  if (is_special)
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 */,
340
 
                             pool));
341
 
  else if (properties)
342
 
    {
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))
346
 
        {
347
 
          const char *pname = svn__apr_hash_index_key(hi);
348
 
          const svn_string_t *pval = svn__apr_hash_index_val(hi);
349
 
          svn_error_t *err;
350
 
 
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 */,
358
 
                                 pool);
359
 
          if (err)
360
 
            {
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,
364
 
                                             local_abspath,
365
 
                                             svn_depth_empty,
366
 
                                             FALSE /* use_commit_times */,
367
 
                                             NULL /* changelists */,
368
 
                                             NULL, NULL, NULL, NULL,
369
 
                                             pool));
370
 
              return svn_error_trace(err);
371
 
            }
372
 
        }
373
 
    }
374
 
 
375
 
  /* Report the addition to the caller. */
376
 
  if (ctx->notify_func2 != NULL)
377
 
    {
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);
383
 
    }
 
319
  SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, local_abspath, properties,
 
320
                                ctx->notify_func2, ctx->notify_baton2, pool));
384
321
 
385
322
  return SVN_NO_ERROR;
386
323
}
387
324
 
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).
391
328
 *
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.
394
331
 *
395
 
 * Files and directories that match ignore patterns will not be added unless
396
 
 * NO_IGNORE is TRUE.
397
 
 *
398
332
 * Use MAGIC_COOKIE (which may be NULL) to detect the mime-type of files
399
333
 * if necessary.
400
334
 *
 
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.
 
341
 *
 
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.
 
349
 *
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.
 
352
 *
 
353
 * Use SCRATCH_POOL for temporary allocations.
403
354
 */
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)
412
367
{
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;
418
373
 
419
374
  /* Check cancellation; note that this catches recursive calls too. */
420
375
  if (ctx->cancel_func)
423
378
  iterpool = svn_pool_create(scratch_pool);
424
379
 
425
380
  /* Add this directory to revision control. */
426
 
  err = svn_wc_add_from_disk(ctx->wc_ctx, dir_abspath,
427
 
                             ctx->notify_func2, ctx->notify_baton2,
428
 
                             iterpool);
429
 
  if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
430
 
    svn_error_clear(err);
431
 
  else if (err)
432
 
    return svn_error_trace(err);
433
 
 
434
 
  if (!no_ignore)
435
 
    {
436
 
      SVN_ERR(svn_wc_get_ignores2(&ignores, ctx->wc_ctx, dir_abspath,
437
 
                                  ctx->config, scratch_pool, iterpool));
 
381
  err = svn_wc_add_from_disk2(ctx->wc_ctx, dir_abspath, NULL /*props*/,
 
382
                              ctx->notify_func2, ctx->notify_baton2,
 
383
                              iterpool);
 
384
  if (err)
 
385
    {
 
386
      if (err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
 
387
        {
 
388
          svn_error_clear(err);
 
389
          entry_exists = TRUE;
 
390
        }
 
391
      else if (err)
 
392
        {
 
393
          return svn_error_trace(err);
 
394
        }
 
395
    }
 
396
 
 
397
  /* Fetch ignores after adding to handle ignores on the directory itself
 
398
     and ancestors via the single db optimization in libsvn_wc */
 
399
  if (refresh_ignores)
 
400
    SVN_ERR(svn_wc_get_ignores2(&ignores, ctx->wc_ctx, dir_abspath,
 
401
                                ctx->config, result_pool, iterpool));
 
402
 
 
403
  /* If DIR_ABSPATH is the root of an unversioned subtree then get the
 
404
     following "autoprops":
 
405
 
 
406
       1) Explicit and inherited svn:auto-props properties on
 
407
          DIR_ABSPATH
 
408
       2) auto-props from the CTX->CONFIG hash
 
409
 
 
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)
 
415
    {
 
416
      SVN_ERR(svn_client__get_all_auto_props(&config_autoprops, dir_abspath,
 
417
                                             ctx, scratch_pool, iterpool));
438
418
    }
439
419
 
440
420
  SVN_ERR(svn_io_get_dirents3(&dirents, dir_abspath, TRUE, scratch_pool,
459
439
      if (svn_wc_is_adm_dir(name, iterpool))
460
440
        continue;
461
441
 
462
 
      if ((!no_ignore) && svn_wc_match_ignore_list(name, ignores, iterpool))
 
442
      if (ignores
 
443
          && svn_wc_match_ignore_list(name, ignores, iterpool))
463
444
        continue;
464
445
 
465
446
      /* Construct the full path of the entry. */
472
453
          if (depth == svn_depth_immediates)
473
454
            depth_below_here = svn_depth_empty;
474
455
 
 
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
 
459
             set of ignores. */
 
460
          if (refresh_ignores && !entry_exists)
 
461
            refresh_ignores = FALSE;
 
462
 
475
463
          SVN_ERR(add_dir_recursive(abspath, depth_below_here,
476
 
                                    force, no_ignore, magic_cookie,
477
 
                                    ctx, iterpool));
 
464
                                    force, no_autoprops,
 
465
                                    magic_cookie, config_autoprops,
 
466
                                    refresh_ignores, ignores, ctx,
 
467
                                    result_pool, iterpool));
478
468
        }
479
469
      else if ((dirent->kind == svn_node_file || dirent->special)
480
470
               && depth >= svn_depth_files)
481
471
        {
482
 
          err = add_file(abspath, magic_cookie, ctx, iterpool);
 
472
          err = add_file(abspath, magic_cookie, config_autoprops,
 
473
                         no_autoprops, ctx, iterpool);
483
474
          if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
484
475
            svn_error_clear(err);
485
476
          else
493
484
  return SVN_NO_ERROR;
494
485
}
495
486
 
496
 
 
497
 
struct add_with_write_lock_baton {
498
 
  const char *local_abspath;
499
 
  svn_depth_t depth;
500
 
  svn_boolean_t force;
501
 
  svn_boolean_t no_ignore;
502
 
  svn_client_ctx_t *ctx;
503
 
 
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;
508
 
};
509
 
 
510
 
/* The main logic of the public svn_client_add4. */
511
 
static svn_error_t *
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
 
489
   properties.
 
490
*/
 
491
typedef struct collect_auto_props_baton_t
 
492
{
 
493
  /* the hash table for storing the property name/value pairs */
 
494
  apr_hash_t *autoprops;
 
495
 
 
496
  /* a pool used for allocating memory */
 
497
  apr_pool_t *result_pool;
 
498
} collect_auto_props_baton_t;
 
499
 
 
500
/* Implements svn_config_enumerator2_t callback.
 
501
 
 
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.
 
505
*/
 
506
static svn_boolean_t
 
507
all_auto_props_collector(const char *name,
 
508
                         const char *value,
 
509
                         void *baton,
 
510
                         apr_pool_t *pool)
 
511
{
 
512
  collect_auto_props_baton_t *autoprops_baton = baton;
 
513
  apr_array_header_t *autoprops;
 
514
  int i;
 
515
 
 
516
  /* nothing to do here without a value */
 
517
  if (*value == 0)
 
518
    return TRUE;
 
519
 
 
520
  split_props(&autoprops, value, pool);
 
521
 
 
522
  for (i = 0; i < autoprops->nelts; i ++)
 
523
    {
 
524
      size_t len;
 
525
      const char *this_value;
 
526
      char *property = APR_ARRAY_IDX(autoprops, i, char *);
 
527
      char *equal_sign = strchr(property, '=');
 
528
 
 
529
      if (equal_sign)
 
530
        {
 
531
          *equal_sign = '\0';
 
532
          equal_sign++;
 
533
          trim_string(&equal_sign);
 
534
          unquote_string(&equal_sign);
 
535
          this_value = equal_sign;
 
536
        }
 
537
      else
 
538
        {
 
539
          this_value = "";
 
540
        }
 
541
      trim_string(&property);
 
542
      len = strlen(property);
 
543
 
 
544
      if (len > 0)
 
545
        {
 
546
          apr_hash_t *pattern_hash = svn_hash_gets(autoprops_baton->autoprops,
 
547
                                                   name);
 
548
          svn_string_t *propval;
 
549
 
 
550
          /* Force reserved boolean property values to '*'. */
 
551
          if (svn_prop_is_boolean(property))
 
552
            {
 
553
              /* SVN_PROP_EXECUTABLE, SVN_PROP_NEEDS_LOCK, SVN_PROP_SPECIAL */
 
554
              propval = svn_string_create("*", autoprops_baton->result_pool);
 
555
            }
 
556
          else
 
557
            {
 
558
              propval = svn_string_create(this_value,
 
559
                                          autoprops_baton->result_pool);
 
560
            }
 
561
 
 
562
          if (!pattern_hash)
 
563
            {
 
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),
 
567
                            pattern_hash);
 
568
            }
 
569
          svn_hash_sets(pattern_hash,
 
570
                        apr_pstrdup(autoprops_baton->result_pool, property),
 
571
                        propval->data);
 
572
        }
 
573
    }
 
574
  return TRUE;
 
575
}
 
576
 
 
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. */
 
580
static svn_error_t *
 
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)
 
586
{
 
587
  svn_node_kind_t kind;
 
588
  const char *parent_abspath;
 
589
  svn_wc_context_t *wc_ctx = ctx->wc_ctx;
 
590
 
 
591
  SVN_ERR(svn_wc_read_kind2(&kind, wc_ctx, local_abspath,
 
592
                            FALSE, FALSE, scratch_pool));
 
593
 
 
594
  if (kind == svn_node_dir)
 
595
    {
 
596
      *existing_parent_abspath = apr_pstrdup(result_pool, local_abspath);
 
597
      return SVN_NO_ERROR;
 
598
    }
 
599
 
 
600
  if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
 
601
    return svn_error_create(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL, NULL);
 
602
 
 
603
  if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
 
604
                        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,
 
608
                                                    scratch_pool));
 
609
 
 
610
  parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
 
611
 
 
612
  if (ctx->cancel_func)
 
613
    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
614
 
 
615
  SVN_ERR(find_existing_parent(existing_parent_abspath, ctx, parent_abspath,
 
616
                               result_pool, scratch_pool));
 
617
 
 
618
  return SVN_NO_ERROR;
 
619
}
 
620
 
 
621
svn_error_t *
 
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)
 
627
{
 
628
  int i;
 
629
  apr_array_header_t *inherited_config_auto_props;
 
630
  apr_hash_t *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)
 
640
                                  : NULL;
 
641
  *autoprops = apr_hash_make(result_pool);
 
642
  autoprops_baton.result_pool = result_pool;
 
643
  autoprops_baton.autoprops = *autoprops;
 
644
 
 
645
 
 
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));
 
652
  if (use_autoprops)
 
653
    svn_config_enumerate2(cfg, SVN_CONFIG_SECTION_AUTO_PROPS,
 
654
                          all_auto_props_collector, &autoprops_baton,
 
655
                          scratch_pool);
 
656
 
 
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;
 
661
  else
 
662
    rev.kind = svn_opt_revision_working;
 
663
 
 
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. */
 
666
  do
 
667
    {
 
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);
 
672
      if (err)
 
673
        {
 
674
          if (target_is_url || err->apr_err != SVN_ERR_UNVERSIONED_RESOURCE)
 
675
            return svn_error_trace(err);
 
676
 
 
677
          svn_error_clear(err);
 
678
          err = NULL;
 
679
          SVN_ERR(find_existing_parent(&path_or_url, ctx, path_or_url,
 
680
                                       scratch_pool, iterpool));
 
681
        }
 
682
      else
 
683
        {
 
684
          break;
 
685
        }
 
686
    }
 
687
  while (err == NULL);
 
688
 
 
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);
 
692
 
 
693
  if (config_auto_prop)
 
694
    {
 
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,
 
700
                    config_auto_prop);
 
701
      APR_ARRAY_PUSH(inherited_config_auto_props,
 
702
                     svn_prop_inherited_item_t *) = new_iprop;
 
703
    }
 
704
 
 
705
  for (i = 0; i < inherited_config_auto_props->nelts; i++)
 
706
    {
 
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 *);
 
710
 
 
711
      for (hi = apr_hash_first(scratch_pool, elt->prop_hash);
 
712
           hi;
 
713
           hi = apr_hash_next(hi))
 
714
        {
 
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;
 
719
 
 
720
          svn_pool_clear(iterpool);
 
721
 
 
722
          config_auto_prop_pattern = svn_stringbuf_create_empty(iterpool);
 
723
          config_auto_prop_val = svn_stringbuf_create_empty(iterpool);
 
724
 
 
725
          /* Parse svn:auto-props value. */
 
726
          while (*ch != '\0')
 
727
            {
 
728
              svn_stringbuf_setempty(config_auto_prop_pattern);
 
729
              svn_stringbuf_setempty(config_auto_prop_val);
 
730
 
 
731
              /* Parse the file pattern. */
 
732
              while (*ch != '\0' && *ch != '=' && *ch != '\n')
 
733
                {
 
734
                  svn_stringbuf_appendbyte(config_auto_prop_pattern, *ch);
 
735
                  ch++;
 
736
                }
 
737
 
 
738
              svn_stringbuf_strip_whitespace(config_auto_prop_pattern);
 
739
 
 
740
              /* Parse the auto-prop group. */
 
741
              while (*ch != '\0' && *ch != '\n')
 
742
                {
 
743
                  svn_stringbuf_appendbyte(config_auto_prop_val, *ch);
 
744
                  ch++;
 
745
                }
 
746
 
 
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);
 
751
 
 
752
              all_auto_props_collector(config_auto_prop_pattern->data,
 
753
                                       config_auto_prop_val->data,
 
754
                                       &autoprops_baton,
 
755
                                       scratch_pool);
 
756
 
 
757
              /* Skip to next line if any. */
 
758
              while (*ch != '\0' && *ch != '\n')
 
759
                ch++;
 
760
              if (*ch == '\n')
 
761
                ch++;
 
762
            }
 
763
        }
 
764
    }
 
765
 
 
766
  svn_pool_destroy(iterpool);
 
767
 
 
768
  return SVN_NO_ERROR;
 
769
}
 
770
 
 
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)
 
776
{
 
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;
 
782
  int i;
 
783
 
 
784
  if (target_is_url)
 
785
    rev.kind = svn_opt_revision_head;
 
786
  else
 
787
    rev.kind = svn_opt_revision_working;
 
788
 
 
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));
 
793
 
 
794
  explicit_prop = svn_hash_gets(explicit_ignores, path_or_url);
 
795
 
 
796
  if (explicit_prop)
 
797
    {
 
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,
 
803
                    explicit_prop);
 
804
      APR_ARRAY_PUSH(inherited_ignores,
 
805
                     svn_prop_inherited_item_t *) = new_iprop;
 
806
    }
 
807
 
 
808
  *ignores = apr_array_make(result_pool, 16, sizeof(const char *));
 
809
 
 
810
  for (i = 0; i < inherited_ignores->nelts; i++)
 
811
    {
 
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);
 
816
      if (ignore_val)
 
817
        svn_cstring_split_append(*ignores, ignore_val->data, "\n\r\t\v ",
 
818
                                 FALSE, result_pool);
 
819
    }
 
820
 
 
821
  return SVN_NO_ERROR;
 
822
}
 
823
 
 
824
/* The main logic of the public svn_client_add5.
 
825
 *
 
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. */
 
829
static svn_error_t *
 
830
add(const char *local_abspath,
 
831
    svn_depth_t depth,
 
832
    svn_boolean_t force,
 
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)
513
838
{
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;
518
843
 
519
844
  svn_magic__init(&magic_cookie, scratch_pool);
520
845
 
521
 
  if (b->existing_parent_abspath)
 
846
  if (existing_parent_abspath)
522
847
    {
523
848
      const char *parent_abspath;
524
849
      const char *child_relpath;
526
851
      int i;
527
852
      apr_pool_t *iterpool;
528
853
 
529
 
      parent_abspath = b->existing_parent_abspath;
530
 
      child_relpath = svn_dirent_is_child(b->existing_parent_abspath,
531
 
                                          b->local_abspath, NULL);
 
854
      parent_abspath = existing_parent_abspath;
 
855
      child_relpath = svn_dirent_is_child(existing_parent_abspath,
 
856
                                          local_abspath, NULL);
532
857
      components = svn_path_decompose(child_relpath, scratch_pool);
533
858
      iterpool = svn_pool_create(scratch_pool);
534
859
      for (i = 0; i < components->nelts - 1; i++)
538
863
 
539
864
          svn_pool_clear(iterpool);
540
865
 
541
 
          if (b->ctx->cancel_func)
542
 
            SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
 
866
          if (ctx->cancel_func)
 
867
            SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
543
868
 
544
869
          component = APR_ARRAY_IDX(components, i, const char *);
545
870
          parent_abspath = svn_dirent_join(parent_abspath, component,
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);
552
877
 
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,
557
 
                                       scratch_pool));
 
879
          SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, parent_abspath,
 
880
                                        NULL /*props*/,
 
881
                                        ctx->notify_func2, ctx->notify_baton2,
 
882
                                        scratch_pool));
558
883
        }
559
884
      svn_pool_destroy(iterpool);
560
885
    }
561
886
 
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)
564
889
    {
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,
570
 
                              scratch_pool);
 
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);
571
897
    }
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)
575
902
    {
576
903
      svn_boolean_t tree_conflicted;
578
905
      /* Provide a meaningful error message if the node does not exist
579
906
       * on disk but is a tree conflict victim. */
580
907
      err = svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted,
581
 
                                 b->ctx->wc_ctx, b->local_abspath,
 
908
                                 ctx->wc_ctx, local_abspath,
582
909
                                 scratch_pool);
583
910
      if (err)
584
911
        svn_error_clear(err);
587
914
                                 _("'%s' is an existing item in conflict; "
588
915
                                   "please mark the conflict as resolved "
589
916
                                   "before adding a new item here"),
590
 
                                 svn_dirent_local_style(b->local_abspath,
 
917
                                 svn_dirent_local_style(local_abspath,
591
918
                                                        scratch_pool));
592
919
 
593
920
      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
594
921
                               _("'%s' not found"),
595
 
                               svn_dirent_local_style(b->local_abspath,
 
922
                               svn_dirent_local_style(local_abspath,
596
923
                                                      scratch_pool));
597
924
    }
598
925
  else
599
926
    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
600
927
                             _("Unsupported node kind for path '%s'"),
601
 
                             svn_dirent_local_style(b->local_abspath,
 
928
                             svn_dirent_local_style(local_abspath,
602
929
                                                    scratch_pool));
603
930
 
604
931
  /* Ignore SVN_ERR_ENTRY_EXISTS when FORCE is set.  */
605
 
  if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && b->force)
 
932
  if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
606
933
    {
607
934
      svn_error_clear(err);
608
935
      err = SVN_NO_ERROR;
611
938
}
612
939
 
613
940
 
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. */
617
 
static svn_error_t *
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)
623
 
{
624
 
  svn_node_kind_t kind;
625
 
  const char *parent_abspath;
626
 
  svn_wc_context_t *wc_ctx = ctx->wc_ctx;
627
 
 
628
 
  SVN_ERR(svn_wc_read_kind(&kind, wc_ctx, local_abspath, FALSE, scratch_pool));
629
 
 
630
 
  if (kind == svn_node_dir)
631
 
    {
632
 
      svn_boolean_t is_deleted;
633
 
 
634
 
      SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted,
635
 
                                             wc_ctx, local_abspath,
636
 
                                             scratch_pool));
637
 
      if (!is_deleted)
638
 
        {
639
 
          *existing_parent_abspath = apr_pstrdup(result_pool, local_abspath);
640
 
          return SVN_NO_ERROR;
641
 
        }
642
 
    }
643
 
 
644
 
  if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
645
 
    return svn_error_create(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL, NULL);
646
 
 
647
 
  if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
648
 
                        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,
652
 
                                                    scratch_pool));
653
 
 
654
 
  parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
655
 
 
656
 
  if (ctx->cancel_func)
657
 
    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
658
 
 
659
 
  SVN_ERR(find_existing_parent(existing_parent_abspath, ctx, parent_abspath,
660
 
                               result_pool, scratch_pool));
661
 
 
662
 
  return SVN_NO_ERROR;
663
 
}
664
 
 
665
 
 
666
941
 
667
942
svn_error_t *
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,
674
 
                apr_pool_t *pool)
 
950
                apr_pool_t *scratch_pool)
675
951
{
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;
 
956
  svn_error_t *err;
679
957
 
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);
683
961
 
684
 
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
685
 
 
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. */
693
 
  if (path[0] == 0)
694
 
    parent_abspath = local_abspath;
 
962
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
 
963
 
 
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,
 
969
                          scratch_pool);
 
970
  if (err)
 
971
    {
 
972
      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
 
973
          && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
 
974
        {
 
975
          return svn_error_trace(err);
 
976
        }
 
977
 
 
978
      svn_error_clear(err);
 
979
      err = NULL; /* SVN_NO_ERROR */
 
980
      is_wc_root = FALSE;
 
981
    }
 
982
  if (is_wc_root)
 
983
    {
 
984
#ifdef HAVE_SYMLINK
 
985
      svn_node_kind_t disk_kind;
 
986
      svn_boolean_t is_special;
 
987
 
 
988
      SVN_ERR(svn_io_check_special_path(local_abspath, &disk_kind, &is_special,
 
989
                                        scratch_pool));
 
990
 
 
991
      /* A symlink can be an unversioned target and a wcroot. Lets try to add
 
992
         the symlink, which can't be a wcroot. */
 
993
      if (is_special)
 
994
        is_wc_root = FALSE;
 
995
      else
 
996
#endif
 
997
        {
 
998
          if (! force)
 
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,
 
1003
                                                        scratch_pool));
 
1004
        }
 
1005
    }
 
1006
 
 
1007
  if (is_wc_root)
 
1008
    parent_abspath = local_abspath; /* We will only add children */
695
1009
  else
696
 
    parent_abspath = svn_dirent_dirname(local_abspath, pool);
 
1010
    parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
697
1011
 
698
 
  baton.existing_parent_abspath = NULL;
699
 
  if (add_parents)
 
1012
  existing_parent_abspath = NULL;
 
1013
  if (add_parents && !is_wc_root)
700
1014
    {
701
1015
      apr_pool_t *subpool;
702
 
      const char *existing_parent_abspath;
 
1016
      const char *existing_parent_abspath2;
703
1017
 
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);
710
1024
    }
711
1025
 
712
 
  baton.local_abspath = local_abspath;
713
 
  baton.depth = depth;
714
 
  baton.force = force;
715
 
  baton.no_ignore = no_ignore;
716
 
  baton.ctx = ctx;
717
 
  SVN_ERR(svn_wc__call_with_write_lock(add, &baton, ctx->wc_ctx,
718
 
                                       baton.existing_parent_abspath
719
 
                                         ? baton.existing_parent_abspath
720
 
                                         : parent_abspath,
721
 
                                       FALSE, pool, pool));
 
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
 
1030
                                          : parent_abspath),
 
1031
    FALSE /* lock_anchor */, scratch_pool);
722
1032
  return SVN_NO_ERROR;
723
1033
}
724
1034
 
789
1099
      const char *first_url = APR_ARRAY_IDX(urls, 0, const char *);
790
1100
      apr_pool_t *iterpool = svn_pool_create(pool);
791
1101
 
792
 
      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL,
793
 
                                                   first_url, NULL, NULL,
794
 
                                                   FALSE, TRUE, ctx, pool));
 
1102
      SVN_ERR(svn_client_open_ra_session2(&ra_session, first_url, NULL,
 
1103
                                          ctx, pool, iterpool));
795
1104
 
796
1105
      for (i = 0; i < urls->nelts; i++)
797
1106
        {
822
1131
 
823
1132
      if (*bname == '\0')
824
1133
        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
825
 
                                 _("There is no valid uri above '%s'"),
 
1134
                                 _("There is no valid URI above '%s'"),
826
1135
                                 common);
827
1136
    }
828
1137
  else
849
1158
 
850
1159
          if (*bname == '\0')
851
1160
             return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
852
 
                                      _("There is no valid uri above '%s'"),
 
1161
                                      _("There is no valid URI above '%s'"),
853
1162
                                      common);
854
1163
 
855
1164
          for (i = 0; i < targets->nelts; i++)
901
1210
  /* Open an RA session for the URL. Note that we don't have a local
902
1211
     directory, nor a place to put temp files. */
903
1212
  if (!ra_session)
904
 
    SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, common,
905
 
                                                 NULL, NULL, FALSE, TRUE,
906
 
                                                 ctx, pool));
 
1213
    SVN_ERR(svn_client_open_ra_session2(&ra_session, common, NULL, ctx,
 
1214
                                        pool, pool));
 
1215
  else
 
1216
    SVN_ERR(svn_ra_reparent(ra_session, common, pool));
 
1217
 
907
1218
 
908
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,
 
1222
                                                       pool)));
909
1223
  SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
910
1224
                                    commit_revprops,
911
1225
                                    commit_callback,
914
1228
                                    pool));
915
1229
 
916
1230
  /* Call the path-based editor driver. */
917
 
  err = svn_delta_path_driver(editor, edit_baton, SVN_INVALID_REVNUM,
918
 
                              targets, path_driver_cb_func,
919
 
                              (void *)editor, pool);
 
1231
  err = svn_delta_path_driver2(editor, edit_baton, targets, TRUE,
 
1232
                               path_driver_cb_func, (void *)editor, pool);
 
1233
 
920
1234
  if (err)
921
1235
    {
922
1236
      /* At least try to abort the edit (and fs txn) before throwing err. */
923
 
      svn_error_clear(editor->abort_edit(edit_baton, pool));
924
 
      return svn_error_trace(err);
 
1237
      return svn_error_compose_create(
 
1238
                err,
 
1239
                editor->abort_edit(edit_baton, pool));
925
1240
    }
926
1241
 
927
1242
  /* Close the edit. */
948
1263
     itself is added, since it not only constraints the operation depth, but
949
1264
     also defines the depth of the target directory now. Moreover, the new
950
1265
     directory will have no children at all.*/
951
 
  err = svn_client_add4(path, svn_depth_infinity, FALSE, FALSE,
 
1266
  err = svn_client_add5(path, svn_depth_infinity, FALSE, FALSE, FALSE,
952
1267
                        make_parents, ctx, pool);
953
1268
 
954
1269
  /* If we created a new directory, but couldn't add it to version